You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker Compose部署Node服务连接MySQL失败求助

Docker构建Node服务时TypeORM迁移无法连接MySQL的问题解决

问题背景

使用docker-compose部署Node服务与MySQL时,构建阶段执行RUN yarn typeorm:migrate命令失败,报错无法连接MySQL(ECONNREFUSED 127.0.0.1:3306)。

当前配置

1. docker-compose.yml

version: "3"

services:
  db:
    image: mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_ROOT_USER: root
      MYSQL_DATABASE: bl
    ports:
      - "3306:3306"
    volumes:
      - ./data:/var/lib/mysql

  server:
    env_file: "./server/.env"
    build:
      context: ./server
      dockerfile: ./Dockerfile
    image: "server"
    ports:
      - "5000:5000"
    depends_on:
      - db

2. Node服务Dockerfile

FROM node:lts-alpine

WORKDIR /server

COPY . .
COPY package*.json ./
COPY .env ./ 

RUN yarn install

EXPOSE 5000
EXPOSE 3306

ENV NODE_ENV=docker

RUN yarn typeorm:migrate
RUN yarn typeorm:run-migrations

CMD ["yarn", "start"]

3. TypeORM DataSource配置

export const appDataSource = new DataSource({
  type: "mysql",
  host,
  port,
  username: rootUser,
  password,
  database,
  entities: [Company, Order],
  migrationsTableName: "migrations",
  migrations: [`${__dirname}/../migrations/*.ts`],
});

报错信息

> [7/8] RUN yarn typeorm:migrate:
#10 0.857 yarn run v1.22.19
#10 0.943 $ yarn create:migrate-repo && yarn run typeorm -- -d ./src/systems/typeOrm.config.ts migration:generate ./src/migrations/migration
#10 1.344 $ mkdir -p ./src/migrations
#10 1.757 warning From Yarn 1.0 onwards, scripts don't require "--" for options to be forwarded. In a future version, any explicit "--" will be forwarded as-is to the scripts.
#10 1.769 $ ts-node ./node_modules/typeorm/cli -d ./src/systems/typeOrm.config.ts migration:generate ./src/migrations/migration
#10 7.524 Error during migration generation:
#10 7.527 Error: connect ECONNREFUSED 127.0.0.1:3306
#10 7.527     at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1494:16) {
#10 7.527   errno: -111,
#10 7.527   code: 'ECONNREFUSED',
#10 7.527   syscall: 'connect',
#10 7.527   address: '127.0.0.1',
#10 7.527   port: 3306,
#10 7.527   fatal: true
#10 7.527 }
#10 7.565 error Command failed with exit code 1.
#10 7.565 info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
#10 7.594 error Command failed with exit code 1.
#10 7.594 info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
------

已尝试的方法

  • 创建网桥网络连接两个服务
  • 将DataSource的host修改为MySQL服务名db
  • 直接使用MySQL容器的IP地址(172.23.0.2)

核心原因

Dockerfile中的RUN命令是在镜像构建阶段执行的,此时docker-compose定义的db服务还未启动,构建环境与运行环境属于完全隔离的网络空间,因此无论怎么配置host都无法连接到未运行的MySQL服务。


解决方案

1. 移除构建阶段的迁移命令,将迁移移至服务启动阶段

修改Dockerfile,删除构建时的迁移命令,仅保留依赖安装和启动命令:

FROM node:lts-alpine

WORKDIR /server

COPY package*.json ./
RUN yarn install

COPY . .
COPY .env ./ 

EXPOSE 5000

ENV NODE_ENV=docker

CMD ["yarn", "start"]

2. 配置服务启动时等待MySQL可用并执行迁移

方法1:使用等待脚本

在Node服务项目中添加一个等待MySQL连接的脚本wait-for-db.js:

const { appDataSource } = require('./src/systems/typeOrm.config');

const waitForDB = async () => {
  let retries = 10;
  while (retries > 0) {
    try {
      await appDataSource.initialize();
      console.log('MySQL连接成功');
      await appDataSource.destroy();
      break;
    } catch (err) {
      console.log(`MySQL连接失败,${retries}次重试剩余...`);
      retries--;
      await new Promise(resolve => setTimeout(resolve, 3000));
    }
  }
  if (retries === 0) {
    console.error('多次重试后仍无法连接MySQL,退出服务');
    process.exit(1);
  }
};

waitForDB().then(() => {
  // 执行迁移并启动服务
  require('child_process').execSync('yarn typeorm:run-migrations', { stdio: 'inherit' });
  require('./dist/index.js'); // 替换为你的服务入口文件路径
});

修改package.json的启动脚本:

{
  "scripts": {
    "start": "node wait-for-db.js",
    "typeorm:run-migrations": "ts-node ./node_modules/typeorm/cli -d ./src/systems/typeOrm.config.ts migration:run"
  }
}

方法2:使用docker-compose的健康检查

修改docker-compose.yml,为MySQL添加健康检查,确保Node服务在MySQL完全就绪后再启动:

version: "3"

services:
  db:
    image: mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_ROOT_USER: root
      MYSQL_DATABASE: bl
    ports:
      - "3306:3306"
    volumes:
      - ./data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot"]
      interval: 5s
      timeout: 5s
      retries: 5

  server:
    env_file: "./server/.env"
    build:
      context: ./server
      dockerfile: ./Dockerfile
    image: "server"
    ports:
      - "5000:5000"
    depends_on:
      db:
        condition: service_healthy

然后在Node服务的启动脚本中直接执行迁移(因为docker-compose已经确保MySQL可用):

{
  "scripts": {
    "start": "yarn typeorm:run-migrations && node dist/index.js"
  }
}

3. 修正DataSource的环境变量配置

确保server/.env中的数据库连接配置指向docker-compose的db服务:

DB_HOST=db
DB_PORT=3306
DB_USER=root
DB_PASSWORD=root
DB_NAME=bl

在DataSource配置中读取这些环境变量:

import 'dotenv/config';

export const appDataSource = new DataSource({
  type: "mysql",
  host: process.env.DB_HOST || 'localhost',
  port: parseInt(process.env.DB_PORT || '3306'),
  username: process.env.DB_USER || 'root',
  password: process.env.DB_PASSWORD || 'root',
  database: process.env.DB_NAME || 'bl',
  entities: [Company, Order],
  migrationsTableName: "migrations",
  migrations: [`${__dirname}/../migrations/*.ts`],
});

4. 迁移生成的正确方式

迁移文件的生成(typeorm:migrate)应该在本地开发环境执行,而不是构建阶段。本地连接到开发数据库(或临时启动的MySQL容器)生成迁移文件后,将文件提交到代码仓库,构建镜像时只需要运行已生成的迁移文件即可。


内容的提问来源于stack exchange,提问作者Inon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 17:13:07