如何不使用service containers连接GitHub Workflow中docker/docker-compose启动的服务
问题根因
两种访问方式失败的原因分别是:
- 使用
mysql作为主机名报错无法解析:docker-compose会为服务创建独立的自定义网桥,服务名仅在网桥内部可解析,GitHub Actions的工作流步骤直接运行在Runner宿主机上,不在该网桥范围内,因此无法解析该主机名。 - 使用
localhost访问失败:要么是docker-compose配置中没有显式将容器端口绑定到宿主机接口,要么是你的连接命令存在参数错误。需要注意mysql命令中指定端口的参数为大写-P,小写-p是密码参数,你示例中的-p3306属于语法错误,即使网络正常也无法连接。
可行解决方案
以下方案均不需要重写你已有的docker-compose逻辑,也不需要将整个工作流运行在额外容器中:
方案1:显式绑定端口后通过宿主机访问
首先确保你的docker-compose.yml中mysql服务配置了固定端口映射:
services: mysql: image: mysql:8 environment: MYSQL_ROOT_PASSWORD: password # 显式绑定宿主机127.0.0.1的3306端口到容器3306端口 ports: - "127.0.0.1:3306:3306"
修改工作流中的连接命令,使用127.0.0.1代替localhost,同时修正端口参数:
- name: Check connection run: mysql -uroot -ppassword -h127.0.0.1 -P3306
方案2:动态获取容器端口访问
如果你不想修改docker-compose的端口配置,也可以通过docker命令直接获取mysql容器动态绑定的宿主机端口,再用该端口连接:
- name: Get mysql exposed port id: get-mysql-port run: echo "port=$(docker port $(docker-compose ps -q mysql) 3306 | cut -d ':' -f 2)" >> $GITHUB_OUTPUT - name: Check connection run: mysql -uroot -ppassword -h127.0.0.1 -P${{ steps.get-mysql-port.outputs.port }}
方案3:复用docker-compose网络执行命令
如果需要保持使用服务名访问的逻辑,不需要修改任何现有脚本,只需要将你要执行的步骤通过docker-compose run在compose网桥内运行即可:
# 执行mysql命令访问同网络下的mysql服务 - name: Check connection in compose network run: docker-compose run --rm mysql mysql -uroot -ppassword -hmysql -P3306 -e "SELECT VERSION();" # 执行本地脚本,将当前目录挂载到容器内运行 - name: Run local test script run: docker-compose run --rm -v $(pwd):/workspace -w /workspace node node test.js
该方案完全复现你本地的docker-compose运行环境,不需要修改任何现有业务逻辑。
优化建议
不要使用固定时长sleep 120等待服务就绪,你可以在docker-compose中为服务配置健康检查,工作流中直接等待服务健康即可,大幅减少CI等待时间:
services: mysql: image: mysql:8 environment: MYSQL_ROOT_PASSWORD: password healthcheck: test: ["CMD", "mysqladmin" ,"ping", "-uroot", "-ppassword"] interval: 2s timeout: 3s retries: 10
工作流中等待服务就绪的步骤修改为:
- name: Wait for mysql ready run: docker-compose up --wait mysql
内容的提问来源于stack exchange,提问作者XZen
相关产品推荐
相关产品推荐

