Docker容器无法连接MySQL容器报ECONNREFUSED错误求助
问题概述
Node.js应用容器连接同Docker网络下的MySQL容器时触发ECONNREFUSED错误,但通过docker exec -it operatorMysql bash进入MySQL容器、VS Code的MySQL扩展均能正常连接MySQL,说明MySQL服务已启动且凭据正确。
环境配置
容器服务信息
- MySQL容器
- 端口映射:
3306:3002 - 镜像:
mysql:latest - 容器名称:
operatorMysql - 已配置root密码等环境变量
- 端口映射:
- Node.js应用容器
- 自定义Node.js镜像
- 端口映射:
3001:3001、9229:9229 - 包含MySQL相关环境变量
- 两个容器均接入
switchboardDocker网络
核心代码文件
db.js(MySQL连接文件)
// MySQL Connection using mysql2 package const mysql = require('mysql2'); require('dotenv').config(); const connection = mysql.createConnection({ host: 'operatorMysql', port: 3306, user: process.env.MYSQL_USER, password: process.env.MYSQL_PASSWORD, database: process.env.MYSQL_DATABASE }); console.log('MySQL Connection: ' + Object.prototype.toString.call(connection)); module.exports = connection;
Dockerfile.debug
# Dockerfile for the Node.js application FROM node:lts-alpine # Environment setup and dependencies installation ENV NODE_ENV=development WORKDIR /usr/src/app COPY ["package.json", "package-lock.json*", "npm-shrinkwrap.json*", "./"] RUN npm install --production --silent && mv node_modules ../ COPY . . EXPOSE 3001 EXPOSE 3002 EXPOSE 3306 RUN chown -R node /usr/src/app USER node CMD ["npm", "start"]
docker-compose.debug.yaml
version: '3.4' services: operatorMysql: image: mysql:latest container_name: operatorMysql environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} ports: - "3002:3306" expose: - "3002" - "3306" volumes: - operatorMysql_data:/var/lib/mysql networks: - switchboard operatorMain: image: operatormain-debug build: context: . dockerfile: ./Dockerfile.debug environment: NODE_ENV: development MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: ${MYSQL_DATABASE} MYSQL_USER: ${MYSQL_USER} MYSQL_PASSWORD: ${MYSQL_PASSWORD} ports: - "3001:3001" - "9229:9229" command: ["node", "--inspect=0.0.0.0:9229", "./bin/www"] networks: - switchboard depends_on: - operatorMysql volumes: - ./views:/usr/src/app/views networks: switchboard: driver: bridge volumes: operatorMysql_data:
已尝试方案
- 查阅Docker MySQL镜像官方文档及相关问题解答
- 确认两个容器均在
switchboard网络中 - 验证MySQL容器正常运行,可进入并获取MySQL提示符
- 将npm包从
mysql替换为mysql2 - 尝试修改MySQL配置文件允许外部连接,但容器重建后更改丢失
- 端口转发3306
- 尝试使用容器名称、
127.0.0.1、localhost作为MySQL连接主机
排查与解决步骤
1. 修正MySQL容器的绑定地址
MySQL默认监听127.0.0.1,仅允许容器内部本地连接。需修改为监听所有地址,让同网络下的Node.js容器能访问:
在docker-compose.debug.yaml的operatorMysql服务中添加command配置:
operatorMysql: # 其他配置不变 command: --bind-address=0.0.0.0
2. 授权MySQL用户允许跨容器访问
若使用的MySQL用户仅授权localhost访问,容器间连接会被拒绝。进入MySQL容器执行以下命令:
docker exec -it operatorMysql bash mysql -u root -p${MYSQL_ROOT_PASSWORD} # 替换为你的用户、密码、数据库名 GRANT ALL PRIVILEGES ON ${MYSQL_DATABASE}.* TO '${MYSQL_USER}'@'%' IDENTIFIED BY '${MYSQL_PASSWORD}'; FLUSH PRIVILEGES; exit
该操作允许指定用户从任意地址访问目标数据库,适配容器间的网络连接。
3. 修正MySQL容器的expose配置
expose用于声明容器内部暴露的端口,MySQL容器内实际运行端口是3306,宿主机映射的3002无需暴露。修改operatorMysql的expose:
expose: - "3306"
4. 确保Node.js容器加载正确的环境变量
当前Dockerfile未复制.env文件到容器,导致dotenv无法读取变量。在Dockerfile.debug中添加复制.env的指令:
# 在COPY . .之前添加 COPY .env ./
同时可在Node.js代码中添加日志验证变量是否正确加载:
console.log('MySQL User:', process.env.MYSQL_USER); console.log('MySQL Database:', process.env.MYSQL_DATABASE);
5. 解决容器启动顺序问题
depends_on仅保证MySQL容器先启动,但不保证MySQL服务就绪。添加健康检查确保Node.js容器在MySQL服务可用后启动:
在docker-compose.debug.yaml的operatorMysql服务中添加健康检查:
operatorMysql: # 其他配置不变 healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"] interval: 5s timeout: 5s retries: 5
修改operatorMain的depends_on配置:
operatorMain: # 其他配置不变 depends_on: operatorMysql: condition: service_healthy
6. 验证容器间网络连通性
进入Node.js容器,尝试ping MySQL容器名称确认网络连通:
docker exec -it operatorMain ping operatorMysql
若ping不通,需检查switchboard网络是否正常,可重新创建网络:
docker network rm switchboard docker-compose up -d
内容的提问来源于stack exchange,提问作者user22689071

