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

GitHub Actions中Docker网络无法解析容器主机名问题求助

问题

搭建Next.js+Prisma/MongoDB应用的CI流水线时,需要运行本地MongoDB副本集,用docker-compose部署3个数据库实例和应用到同一网络,本地运行正常,但在GitHub Actions工作流中,mongo-bootstrapper无法解析数据库容器的主机名(报错MongoNetworkError: getaddrinfo ENOTFOUND mongo1)。

docker-compose.test.yml 配置

version: '3.8'

services:
  mongo-bootstrapper:
    container_name: mongo-bootstrapper
    image: mongo
    volumes:
      - ./.devcontainer/tests/init-mongo-db/entrypoint.sh:/init.sh
    entrypoint: /init.sh
    networks:
      - mongo-net
  mongo1:
    image: mongo
    container_name: mongo1
    restart: always
    ports:
      - "27017:27017"
    environment:
          - MONGO_INITDB_ROOT_USERNAME=root
          - MONGO_INITDB_ROOT_PASSWORD=root
    volumes:
      - ./.devcontainer/tests/replica.key:/opt/replica.key
    command: 
      - --replSet
      - rs0
      - --keyFile
      - /opt/replica.key
      - --port
      - "27017"
    networks:
      - mongo-net
  mongo2:
    image: mongo
    container_name: mongo2
    restart: always
    ports:
      - "27027:27027"
    environment:
        - MONGO_INITDB_ROOT_USERNAME=root
        - MONGO_INITDB_ROOT_PASSWORD=root
    volumes:
      - ./.devcontainer/tests/replica.key:/opt/replica.key
    command: 
      - --replSet
      - rs0
      - --keyFile
      - /opt/replica.key
      - --port
      - "27027"
    networks:
      - mongo-net
  mongo3:
    image: mongo
    container_name: mongo3
    restart: always
    ports:
      - "27037:27037"
    environment:
          - MONGO_INITDB_ROOT_USERNAME=root
          - MONGO_INITDB_ROOT_PASSWORD=root
    volumes:
      - ./.devcontainer/tests/replica.key:/opt/replica.key
    command: 
      - --replSet
      - rs0
      - --keyFile
      - /opt/replica.key
      - --port
      - "27037"
    networks:
      - mongo-net
  app:
    platform: linux/amd64
    build: 
      context: .
      dockerfile: .devcontainer/Dockerfile
    container_name: app
    env_file: ./.devcontainer/.env.test
    ports:
      - "80:80"
    volumes:
      - .:/app
    networks:
      - mongo-net
networks:
  mongo-net:

mongo-bootstrapper 入口脚本

#!/bin/bash

echo "########### Waiting for primary ###########"
until mongosh -u root -p root --host mongo1 --eval "printjson(db.runCommand({ serverStatus: 1}).ok)"
  do
    echo "########### Sleeping  ###########"
    sleep 5
  done


echo "########### Waiting for replica 01  ###########"
until mongosh -u root -p root --host mongo2 --port 27027 --eval "printjson(db.runCommand({ serverStatus: 1}).ok)"
  do
    echo "########### Sleeping  ###########"
    sleep 5
  done


echo "########### Waiting for replica 02  ###########"
until mongosh -u root -p root --host mongo3 --port 27037 --eval "printjson(db.runCommand({ serverStatus: 1}).ok)"
  do
    echo "########### Sleeping  ###########"
    sleep 5
  done

echo "########### All replicas are ready!!!  ###########"

echo "########### Initiating replica set ###########"
mongosh -u root -p root --host mongo1 <<EOF
  rs.initiate({
    _id: "rs0",
    members: [
      { _id: 0, host: "mongo1:27017" },
      { _id: 1, host: "mongo2:27027" },
      { _id: 2, host: "mongo3:27037" }
    ]
  })
EOF

echo "########### Getting replica set status again  ###########"
mongosh --host mongo1 -u root -p root   <<EOF
  rs.status()
EOF

echo "########### Stopping TEMP instance  ###########"
mongod --shutdown

GitHub Actions 工作流日志报错

mongo-bootstrapper    | MongoNetworkError: getaddrinfo ENOTFOUND mongo1
mongo-bootstrapper    | ########### Sleeping  ###########
mongo-bootstrapper    | Current Mongosh Log ID: 63fe0727c38672c5fda58e82
mongo-bootstrapper    | Connecting to:      mongodb://<credentials>@mongo1:27017/?directConnection=true&appName=mongosh+1.6.2

GitHub Actions 工作流配置

name: CI & CD

on:
  push:
    branches:
       - dev
       - staging
       - main
jobs:
  cintegration:
   name: Test
   runs-on: ubuntu-latest
   steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 16
      - name: Run tests
        run: ./.devcontainer/tests/runTests.sh
      - name: Install dependencies
        run: npm install
      - name: Build the app
        run: npm run build

自动化测试脚本 runTests.sh

#!/bin/bash

docker-compose -f docker-compose.test.yml up -d
# Wait for the replica set to be ready
mongo_bootstrapper_running=true
until [ "$mongo_bootstrapper_running" == "false" ]; do
  echo "Waiting for MongoDB replica set to be ready..."
  sleep 5
  mongo_bootstrapper_running=$(docker ps --filter "name=mongo-bootstrapper" -q | wc -l | grep -q "0" && echo false || echo true)
done

# MongoDB replica set is ready, run the tests
echo "MongoDB replica set is ready, run the tests"
# Push database schema
docker-compose -f ./docker-compose.test.yml run app npx prisma db push
docker-compose -f ./docker-compose.test.yml run app npm run test:ci
test_exit_code=$?

# Stop the local MongoDB replica set
echo "Stopping the local MongoDB replica set."
docker-compose -f docker-compose.test.yml down

exit $test_exit_code

解决方法

1. 给mongo-bootstrapper添加容器依赖

Docker Compose默认并行启动所有服务,mongo-bootstrapper可能在数据库容器完全加入网络前就开始运行脚本。修改docker-compose.test.yml的mongo-bootstrapper服务,添加依赖确保数据库容器先启动:

mongo-bootstrapper:
    container_name: mongo-bootstrapper
    image: mongo
    volumes:
      - ./.devcontainer/tests/init-mongo-db/entrypoint.sh:/init.sh
    entrypoint: /init.sh
    networks:
      - mongo-net
    depends_on:
      - mongo1
      - mongo2
      - mongo3

注意:depends_on仅保证启动顺序,不保证服务就绪,原有脚本的重试逻辑需保留。

2. 优化runTests.sh的等待逻辑

原脚本只等待bootstrapper容器退出,未验证副本集是否真正初始化完成。修改等待逻辑,直接检查副本集状态:

docker-compose -f docker-compose.test.yml up -d

# 等待副本集初始化完成
echo "Waiting for MongoDB replica set to be initialized..."
until docker-compose -f docker-compose.test.yml exec mongo1 mongosh -u root -p root --eval "rs.status().ok" | grep -q "1"; do
  echo "Sleeping..."
  sleep 5
done

3. 清理GitHub Actions环境中的Docker缓存

GitHub Actions的Ubuntu Runner可能存在网络缓存或DNS残留问题,在测试前清理Docker环境:
修改GitHub Actions工作流,在Run tests步骤前添加:

- name: Clean Docker environment
  run: |
    docker system prune -af
    sudo systemctl restart docker

4. 指定mongo-bootstrapper使用Docker内置DNS

强制bootstrapper容器使用Docker内置DNS服务,避免解析异常:

mongo-bootstrapper:
    # ... 其他配置
    dns:
      - 127.0.0.11 # Docker内置DNS服务器地址

5. 用容器IP替代主机名(备选方案)

如果DNS解析问题无法解决,可在启动时获取数据库容器IP,传递给bootstrapper脚本:
修改runTests.sh:

docker-compose -f docker-compose.test.yml up -d mongo1 mongo2 mongo3

# 获取容器IP
MONGO1_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mongo1)
MONGO2_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mongo2)
MONGO3_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mongo3)

# 启动bootstrapper并传递IP环境变量
docker-compose -f docker-compose.test.yml run -e MONGO1_IP=$MONGO1_IP -e MONGO2_IP=$MONGO2_IP -e MONGO3_IP=$MONGO3_IP mongo-bootstrapper

同时修改entrypoint.sh,替换主机名为环境变量:

#!/bin/bash

echo "########### Waiting for primary ###########"
until mongosh -u root -p root --host $MONGO1_IP --eval "printjson(db.runCommand({ serverStatus: 1}).ok)"
  do
    echo "########### Sleeping  ###########"
    sleep 5
  done

# 替换mongo2、mongo3的主机名为对应IP变量
echo "########### Waiting for replica 01  ###########"
until mongosh -u root -p root --host $MONGO2_IP --port 27027 --eval "printjson(db.runCommand({ serverStatus: 1}).ok)"
  do
    echo "########### Sleeping  ###########"
    sleep 5
  done

echo "########### Waiting for replica 02  ###########"
until mongosh -u root -p root --host $MONGO3_IP --port 27037 --eval "printjson(db.runCommand({ serverStatus: 1}).ok)"
  do
    echo "########### Sleeping  ###########"
    sleep 5
  done

echo "########### All replicas are ready!!!  ###########"

echo "########### Initiating replica set ###########"
mongosh -u root -p root --host $MONGO1_IP <<EOF
  rs.initiate({
    _id: "rs0",
    members: [
      { _id: 0, host: "$MONGO1_IP:27017" },
      { _id: 1, host: "$MONGO2_IP:27027" },
      { _id: 2, host: "$MONGO3_IP:27037" }
    ]
  })
EOF

echo "########### Getting replica set status again  ###########"
mongosh --host $MONGO1_IP -u root -p root   <<EOF
  rs.status()
EOF

echo "########### Stopping TEMP instance  ###########"
mongod --shutdown

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 13:21:29