Node.js+MySQL后端应用Docker容器化后无法建立数据库连接
Node.js+MySQL容器化后连接失败问题解决
问题
本地运行正常的Node.js+MySQL后端应用,容器化部署后Node应用容器无法与MySQL容器建立连接。
相关配置文件
文件夹结构
项目根目录包含dbinit、src文件夹,以及database.js、Dockerfile、docker-compose.yml、.env、app.js等核心文件
database.js
const mysql = require('mysql2'); const dotenv = require('dotenv'); dotenv.config(); // Create a MySQL connection const connection = mysql.createConnection({ host: process.env.MYSQLDB_HOST, user: process.env.MYSQLDB_USER, password: process.env.MYSQLDB_ROOT_PASSWORD, port: process.env.NODE_LOCAL_PORT, database: process.env.MYSQLDB_DATABASE }); connection.connect((err) => { if (err) { console.error('Error connecting to MySQL: ' + err.stack); return; } console.log('Connected to MySQL as id ' + connection.threadId); }); module.exports = connection;
docker-compose.yml
version: '3.8' services: mysqldb: image: mysql container_name: mysql_container command: --default-authentication-plugin=mysql_native_password restart: unless-stopped volumes: - ./dbinit/init.sql:/docker-entrypoint-initdb.d/0_init.sql - $HOME/database:/var/lib/mysql ports: - $MYSQLDB_LOCAL_PORT:$MYSQLDB_DOCKER_PORT environment: MYSQL_ROOT_PASSWORD: $MYSQLDB_ROOT_PASSWORD MYSQL_DATABASE: $MYSQLDB_DATABASE networks: - internalnet nodeapp: depends_on: - mysqldb build: context: . dockerfile: Dockerfile container_name: nodeapp_container restart: unless-stopped env_file: .env image: nodeapp_backend ports: - $NODE_LOCAL_PORT:$NODE_DOCKER_PORT volumes: - .:/usr/src/app - /usr/src/app/node_modules environment: - DB_HOST=mysqldb - DB_USER=$MYSQLDB_USER - DB_PASSWORD=$MYSQLDB_ROOT_PASSWORD - DB_NAME=$MYSQLDB_DATABASE - DB_PORT=$MYSQLDB_DOCKER_PORT networks: - internalnet networks: internalnet: driver: bridge
Dockerfile
FROM node:alpine3.11 WORKDIR /usr/src/app COPY package*.json ./ RUN npm install COPY . . CMD [ "node", "app.js" ]
.env文件
MYSQLDB_USER=root MYSQLDB_ROOT_PASSWORD=hiru MYSQLDB_DATABASE=assignments_db MYSQLDB_LOCAL_PORT=3306 MYSQLDB_DOCKER_PORT=3306 NODE_LOCAL_PORT=3000 NODE_DOCKER_PORT=3000 MYSQLDB_HOST=mysqldb
app.js文件
const express = require('express'); const app = express(); const bodyParser = require('body-parser'); const authenticationRoutes = require('./src/routes/authentication'); const assignmentsRoutes = require('./src/routes/assignments'); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.use('/auth', authenticationRoutes); app.use('/assignments', assignmentsRoutes); app.get("/", (req, res) => { res.send("Welcome to the Assignments API"); }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`); });
运行日志问题
执行docker-compose up后,Node容器日志显示无法连接MySQL,报错连接超时或连接被拒绝。
问题分析
- 端口配置错误:
database.js中MySQL连接端口使用了NODE_LOCAL_PORT(3000),但MySQL容器内部服务端口为3306,应使用MYSQLDB_DOCKER_PORT。 - 环境变量冗余混淆:
docker-compose.yml中node服务重复定义了DB_*前缀的环境变量,但database.js实际读取的是MYSQLDB_*前缀的变量,配置冗余易引发错误。 - 服务就绪不同步:
depends_on仅保证MySQL容器启动,不代表MySQL服务已完成初始化并可接受连接,Node应用启动时可能MySQL尚未就绪。
解决方案
1. 修正database.js端口配置并添加重试逻辑
const mysql = require('mysql2'); const dotenv = require('dotenv'); dotenv.config(); // Create a MySQL connection const connection = mysql.createConnection({ host: process.env.MYSQLDB_HOST, user: process.env.MYSQLDB_USER, password: process.env.MYSQLDB_ROOT_PASSWORD, port: process.env.MYSQLDB_DOCKER_PORT, // 修正为MySQL容器端口 database: process.env.MYSQLDB_DATABASE }); // 添加重试逻辑,解决MySQL未就绪问题 function connectWithRetry() { connection.connect((err) => { if (err) { console.error('Error connecting to MySQL: ' + err.stack); console.log('Retrying connection in 3 seconds...'); setTimeout(connectWithRetry, 3000); return; } console.log('Connected to MySQL as id ' + connection.threadId); }); } connectWithRetry(); module.exports = connection;
2. 清理docker-compose冗余环境变量
node服务已通过env_file: .env加载所有环境变量,删除重复定义的DB_*变量,修改后的node服务配置:
nodeapp: depends_on: - mysqldb build: context: . dockerfile: Dockerfile container_name: nodeapp_container restart: unless-stopped env_file: .env image: nodeapp_backend ports: - $NODE_LOCAL_PORT:$NODE_DOCKER_PORT volumes: - .:/usr/src/app - /usr/src/app/node_modules networks: - internalnet
3. (可选)使用工具检测MySQL就绪状态
若需要更可靠的启动顺序,可在Dockerfile中安装wait-for-it脚本,等待MySQL服务就绪后再启动Node应用:
- 在Dockerfile中添加安装命令:
RUN wget -O /usr/src/app/wait-for-it.sh https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh && chmod +x /usr/src/app/wait-for-it.sh
- 修改启动命令:
CMD [ "./wait-for-it.sh", "mysqldb:3306", "--", "node", "app.js" ]
验证步骤
- 停止当前容器:
docker-compose down - 重新构建镜像:
docker-compose build - 启动容器:
docker-compose up - 查看日志,确认Node应用成功连接MySQL。
内容的提问来源于stack exchange,提问作者Hiren Timbadiya
相关产品推荐
相关产品推荐

