Docker Compose下Node.js与MySQL服务连接失败问题求助
我通过Docker Compose部署了2个Node.js服务和2个MySQL服务,能使用对应凭证登录两个MySQL容器,但两个Node.js服务均无法连接MySQL服务,报错信息为:
original: Error: connect ECONNREFUSED 172.22.0.2:3308
此外,我已成功通过PHP脚本连接两个MySQL服务。以下是我的docker-compose.yml文件:
version: '3.8' services: genreapp: depends_on: - genresqldb build: ./genre #command: sh -c './wait-for-it.sh -t 0 genresqldb:$DB_PORT_GENRE' restart: unless-stopped env_file: ./.env links: - genresqldb volumes: - ./:/app ports: - $NODE_PORT_GENRE:$NODE_PORT_GENRE environment: - DB_USERNAME=$DB_USERNAME - DB_PASSWORD=$DB_PASSWORD_GENRE - DB_NAME=$DB_NAME_GENRE - DB_PORT=$DB_PORT_GENRE - DIALTEC=$DIALTEC - APP_PORT=$NODE_PORT_GENRE - HOST=$HOST - DB_HOST_GENRE=genresqldb stdin_open: true tty: true movieapp: depends_on: - moviesqldb build: ./movie restart: unless-stopped env_file: ./.env links: - moviesqldb volumes: - ./:/app #command: sh -c './wait-for-it.sh -t 0 moviesqldb:$DB_PORT_MOVIE' ports: - $NODE_PORT_MOVIE:$NODE_PORT_MOVIE environment: - DB_USERNAME=$DB_USERNAME - DB_PASSWORD=$DB_PASSWORD_MOVIE - DB_NAME=$DB_NAME_MOVIE - DB_PORT=$DB_PORT_MOVIE - DIALTEC=$DIALTEC - APP_PORT=$NODE_PORT_MOVIE - HOST=$HOST - DB_HOST_GENRE=moviesqldb stdin_open: true tty: true genresqldb: image: mysql:5 # restart: unless-stopped env_file: ./.env environment: - MYSQL_ROOT_PASSWORD=$DB_PASSWORD_GENRE - MYSQL_DATABASE=$DB_NAME_GENRE expose: - $DB_PORT_GENRE ports: - $DB_PORT_GENRE:$DB_PORT volumes: - db:/var/lib/mysqli moviesqldb: image: mysql:5 # restart: unless-stopped env_file: ./.env environment: - MYSQL_ROOT_PASSWORD=$DB_PASSWORD_MOVIE - MYSQL_DATABASE=$DB_NAME_MOVIE expose: - $DB_PORT_MOVIE ports: - $DB_PORT_MOVIE:$DB_PORT volumes: - db:/var/lib/mysqli volumes: db:
问题排查与解决方案
1. 端口配置错误
MySQL容器内部默认监听端口是3306,你的配置中ports字段写的是$DB_PORT_GENRE:$DB_PORT,如果.env里的DB_PORT不是3306,会导致容器内部端口映射错误。Node.js服务连接MySQL时,应该用容器内部的3306端口,而非宿主机的映射端口(比如报错里的3308)。
2. 环境变量命名错误
movieapp服务的环境变量里错写了DB_HOST_GENRE=moviesqldb,应该改成对应服务的主机变量(比如DB_HOST_MOVIE=moviesqldb),否则Node.js代码会读取错误的主机地址。
3. 数据库未就绪就启动Node.js服务
depends_on仅保证容器启动顺序,不确保MySQL服务已经完全就绪可以接收连接。你注释掉了wait-for-it.sh脚本,导致Node.js可能在MySQL初始化完成前就尝试连接,引发连接拒绝错误。
4. 数据卷冲突
两个MySQL服务共用同一个db数据卷,会导致数据库文件互相覆盖,损坏数据结构,进而无法正常连接。需要给每个MySQL服务分配独立的数据卷。
5. 冗余配置干扰
links和expose在Docker Compose默认网络下是冗余配置,而且expose里写的是宿主机端口(比如$DB_PORT_GENRE),不是容器内部的3306,反而可能造成混淆。
修正后的docker-compose.yml示例
version: '3.8' services: genreapp: depends_on: - genresqldb build: ./genre # 等待MySQL服务就绪后启动 command: sh -c './wait-for-it.sh -t 0 genresqldb:3306' restart: unless-stopped env_file: ./.env volumes: - ./:/app ports: - $NODE_PORT_GENRE:$NODE_PORT_GENRE environment: - DB_USERNAME=$DB_USERNAME - DB_PASSWORD=$DB_PASSWORD_GENRE - DB_NAME=$DB_NAME_GENRE - DB_PORT=3306 # 容器内部固定端口 - DIALTEC=$DIALTEC - APP_PORT=$NODE_PORT_GENRE - HOST=$HOST - DB_HOST=genresqldb # 用服务名作为主机地址 stdin_open: true tty: true movieapp: depends_on: - moviesqldb build: ./movie command: sh -c './wait-for-it.sh -t 0 moviesqldb:3306' restart: unless-stopped env_file: ./.env volumes: - ./:/app ports: - $NODE_PORT_MOVIE:$NODE_PORT_MOVIE environment: - DB_USERNAME=$DB_USERNAME - DB_PASSWORD=$DB_PASSWORD_MOVIE - DB_NAME=$DB_NAME_MOVIE - DB_PORT=3306 - DIALTEC=$DIALTEC - APP_PORT=$NODE_PORT_MOVIE - HOST=$HOST - DB_HOST=moviesqldb # 修正环境变量名 stdin_open: true tty: true genresqldb: image: mysql:5 restart: unless-stopped env_file: ./.env environment: - MYSQL_ROOT_PASSWORD=$DB_PASSWORD_GENRE - MYSQL_DATABASE=$DB_NAME_GENRE ports: - $DB_PORT_GENRE:3306 # 宿主机端口映射到容器内部3306 volumes: - genredb:/var/lib/mysql # 独立数据卷 moviesqldb: image: mysql:5 restart: unless-stopped env_file: ./.env environment: - MYSQL_ROOT_PASSWORD=$DB_PASSWORD_MOVIE - MYSQL_DATABASE=$DB_NAME_MOVIE ports: - $DB_PORT_MOVIE:3306 volumes: - moviedb:/var/lib/mysql # 独立数据卷 volumes: genredb: moviedb:
内容的提问来源于stack exchange,提问作者Ndeem

