Docker环境下Ecto连接MySQL失败问题求助
Phoenix应用Docker化后无法连接MySQL的问题排查与解决
问题描述
Phoenix应用Docker化后,执行docker compose up时无法连接MySQL数据库,尝试将DB_HOST设为0.0.0.0或localhost均无效,报错连接拒绝。
错误信息
server-1 | 11:23:07.417 [error] GenServer #PID<0.272.0> terminating server-1 | ** (DBConnection.ConnectionError) (0.0.0.0:3306) connection refused - :econnrefused server-1 | (db_connection 2.4.3) lib/db_connection/connection.ex:100: DBConnection.Connection.connect/2 server-1 | (connection 1.1.0) lib/connection.ex:622: Connection.enter_connect/5 server-1 | (stdlib 4.2) proc_lib.erl:240: :proc_lib.init_p_do_apply/3 server-1 | Last message: nil server-1 | State: MyXQL.Connection server-1 | server-1 | 11:23:07.430 [error] GenServer #PID<0.278.0> terminating server-1 | ** (DBConnection.ConnectionError) (0.0.0.0:3306) connection refused - :econnrefused server-1 | (db_connection 2.4.3) lib/db_connection/connection.ex:100: DBConnection.Connection.connect/2 server-1 | (connection 1.1.0) lib/connection.ex:622: Connection.enter_connect/5 server-1 | (stdlib 4.2) proc_lib.erl:240: :proc_lib.init_p_do_apply/3 server-1 | Last message: nil server-1 | State: MyXQL.Connection server-1 | ** (Mix) The database for App.Repo couldn't be created: %RuntimeError{message: "killed"} server-1 exited with code 1
核心问题分析
- 数据库连接地址错误:Docker Compose默认网络中,容器间通过服务名互相访问。
0.0.0.0是服务监听地址而非连接地址,localhost在容器内指向自身,无法访问MySQL容器。 - 数据库就绪判断不足:
depends_on: condition: service_started仅确保MySQL容器启动,但MySQL服务需要时间完成初始化,此时应用尝试连接会失败。
解决方案
1. 修正DB_HOST配置与健康检查
修改docker-compose.yml,将DB_HOST改为MySQL服务名database,并为数据库添加健康检查,确保服务就绪后再启动应用:
version: '3.8' services: server: image: server environment: DB_HOST: database DB_DATABASE: dev DB_PORT: 3306 DB_USER: dev DB_PASSWORD: dev ports: - "4000:4000" restart: on-failure depends_on: database: condition: service_healthy database: image: mysql:latest command: --default-authentication-plugin=mysql_native_password ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: root MYSQL_USER: dev MYSQL_PASSWORD: dev MYSQL_DATABASE: dev volumes: - mysql_data:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "dev", "-pdev"] interval: 5s timeout: 5s retries: 5 volumes: mysql_data:
2. 增强应用启动前的数据库等待逻辑
修改entry.sh,添加循环检测确保MySQL服务就绪后再执行数据库初始化:
# Exit on failure set -e # 等待MySQL服务就绪 until mysql -h"$DB_HOST" -u"$DB_USER" -p"$DB_PASSWORD" -e "SELECT 1"; do echo "等待MySQL数据库启动..." sleep 2 done mix ecto.create mix ecto.migrate mix run priv/repo/seeds.exs exec mix phx.server
同时更新Dockerfile,安装mysql-client以支持mysql命令:
FROM elixir:latest EXPOSE 4000 # 安装mysql-client RUN apt-get update && apt-get install -y mysql-client && rm -rf /var/lib/apt/lists/* RUN mkdir /server COPY . /server WORKDIR /server RUN mix local.rebar --force RUN mix local.hex --force RUN mix deps.get RUN mix do compile CMD [ "sh", "/server/entry.sh" ]
3. 确认数据库用户权限(可选)
若仍有连接问题,可确认dev用户允许从Docker网络连接。默认通过MYSQL_USER创建的用户权限为%(允许所有主机),若需手动授权,可进入MySQL容器执行:
GRANT ALL PRIVILEGES ON dev.* TO 'dev'@'%'; FLUSH PRIVILEGES;
验证步骤
- 清理旧容器与数据卷:
docker compose down -v - 重新构建server镜像:
docker compose build server - 启动服务:
docker compose up
此时应用应能正常连接MySQL并完成数据库初始化。
内容的提问来源于stack exchange,提问作者Basil
相关产品推荐
相关产品推荐

