如何在GCP上基于docker-compose自动更新多容器实例的Docker镜像
不用Kubernetes实现GCP实例自动拉取GCR新镜像的方案
既然你不想用Kubernetes,又要在GCP实例上用docker-compose管理多容器,同时实现GCR新镜像自动更新,我给你几个靠谱的实战方案:
方案1:CI/CD远程SSH执行docker-compose命令(最直接)
你已经在用GitHub Actions构建推送镜像,那可以把更新实例的步骤直接整合到CI/CD流程里,通过SSH远程连接到实例执行更新命令:
- 给实例配置免密SSH访问:
- 把CI/CD服务(比如GitHub Actions)的公钥添加到GCP实例的
~/.ssh/authorized_keys里,或者在创建实例时通过metadata注入公钥,这样CI/CD能无密码登录实例。
- 把CI/CD服务(比如GitHub Actions)的公钥添加到GCP实例的
- 在GitHub Actions workflow里添加更新步骤:
推送镜像到GCR后,添加一个步骤,SSH到实例执行:
如果你只更新某个服务的镜像,可以指定服务名,避免重启所有容器:ssh username@instance-ip "cd /path/to/docker-compose && docker-compose pull && docker-compose up -d"ssh username@instance-ip "cd /path/to/docker-compose && docker-compose pull your-service-name && docker-compose up -d your-service-name"注意:建议不要用
latest标签,改用Git commit哈希或版本号作为镜像标签,这样能精准控制更新,避免本地镜像缓存导致拉取不到新镜像的问题。
方案2:用Pub/Sub + Cloud Functions触发更新(更自动化)
利用GCR的镜像推送事件,自动触发实例更新:
- 配置GCR的Pub/Sub事件:
当新镜像推送到GCR时,GCR会自动发送事件到Cloud Pub/Sub。你需要在GCP控制台给对应的镜像仓库配置Pub/Sub通知,指定一个主题。 - 编写Cloud Function订阅该主题:
函数的逻辑是:收到镜像推送事件后,通过gcloud compute ssh命令远程连接到实例,执行docker-compose更新命令。比如Python函数核心逻辑(也可以用Node.js/Bash):import subprocess def trigger_update(event, context): # 解析事件里的镜像信息(可选,用来判断是否需要更新) image_info = event.get('payload', {}) # 执行SSH命令更新实例 subprocess.run([ 'gcloud', 'compute', 'ssh', 'instance-name', '--zone', 'your-zone', '--command', 'cd /path/to/docker-compose && docker-compose pull && docker-compose up -d' ]) - 给Cloud Function配置权限:
确保函数的服务账号有compute.instances.osLogin权限,以及访问实例的SSH权限,同时实例的服务账号能拉取GCR镜像(添加roles/storage.objectViewer权限)。
方案3:实例组滚动更新(适合多实例场景)
如果你有多个相同的实例,用托管实例组来实现滚动更新会更优雅:
- 创建包含启动脚本的实例模板:
启动脚本要完成这些操作:安装Docker和docker-compose,从Cloud Storage下载你的docker-compose.yml文件(确保yml里的镜像标签是最新的,或者用唯一标签),然后启动容器。示例启动脚本:#!/bin/bash # 安装Docker apt-get update && apt-get install -y docker.io docker-compose # 下载docker-compose.yml gsutil cp gs://your-bucket/docker-compose.yml /opt/ # 启动容器 cd /opt && docker-compose up -d - 创建托管实例组:
用上面的实例模板创建托管实例组,配置好自动扩缩容(如果需要)。 - 触发滚动更新:
当新镜像推送后,你可以更新实例模板(比如给启动脚本加个版本注释,触发模板更新),然后执行命令触发滚动更新:
实例组会逐个替换旧实例为新实例,新实例启动时会自动拉取最新的镜像。gcloud compute instance-groups managed rolling-action replace example-group --zone=your-zone
一些关键注意事项
- 镜像标签策略:永远不要依赖
latest标签,改用唯一标识符(比如Git commit哈希、语义化版本号),这样能确保你拉取的是预期的新镜像。 - 权限配置:确保实例的服务账号有
roles/storage.objectViewer权限,这样才能拉取GCR里的镜像(GCR底层是Cloud Storage)。 - 缓存问题:执行
docker-compose pull时,如果用了唯一标签,会强制拉取新镜像;如果用了latest,可能需要加--no-cache参数,但还是推荐用唯一标签。
内容的提问来源于stack exchange,提问作者Tiago Gouvêa




