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
相关产品推荐
相关产品推荐

