如何在GitHub Actions中自动清理Google Cloud Artifact Registry未引用Docker镜像
问题
已通过GitHub Actions工作流,使用docker/build-push-action构建并推送Docker镜像至Google Cloud Artifact Registry,再部署到Cloud Run。希望通过GitHub Actions自动清理Artifact Registry中未使用/未引用的镜像,目前遇到两个核心问题:
- 层缓存镜像的时间戳均为UNIX纪元(1970/01/01 00:00:00),导致按更新时间排序清理的逻辑失效。
- 执行
gcloud container images delete时,偶尔会尝试删除仍被父镜像引用的镜像,触发错误:
Manifest is still referenced by one or more parent images: ocarry-api/manifests/sha256:93eec65fc56910c8c8012a385e7769fae87885f6459bc8e1613855730ef07007: None
现有清理脚本及GitHub Actions片段如下:
清理脚本
gcloud container images list-tags "${BASE_IMAGE}" \ --filter="NOT tags:${GITHUB_SHA}" --format="table(digest, tags)" | \ tail -n +2 | \ while read row do arr=($row) if [ ${#arr[@]} -eq 2 ]; then start="true" fi if [[ -v start ]]; then digest=${arr[0]} gcloud container images delete -q --force-delete-tags "${BASE_IMAGE}@sha256:$digest" fi done
GitHub Actions YAML片段
- name: Build and push id: docker-build uses: docker/build-push-action@v6 with: platforms: linux/amd64 context: . push: true tags: ${{ env.IMAGE }} cache-from: type=gha cache-to: type=gha,mode=max - name: Deploy to Cloud Run id: deploy uses: google-github-actions/deploy-cloudrun@v2 with: service: /* my service id */ image: ${{ env.IMAGE }} region: ${{ env.GCP_REGION }} - name: Clean up Container images run: | gcloud container images list-tags "${BASE_IMAGE}" \ /* 上述shell脚本后续内容 */
可行的自动清理方案
方案1:利用Artifact Registry生命周期策略(推荐)
Artifact Registry原生支持生命周期策略,无需自定义脚本,可直接通过GCP控制台或gcloud命令配置,自动清理符合条件的镜像:
- 创建生命周期策略
通过gcloud命令创建策略文件并应用,例如设置保留最近30天的带标签镜像、7天的无标签镜像,以及7天内未被引用的镜像:
示例gcloud artifacts repositories set-lifecycle-policy ${REPO_NAME} \ --location=${GCP_REGION} \ --lifecycle-policy-file=lifecycle-policy.yamllifecycle-policy.yaml内容:rules: - action: DELETE condition: age: 30d tagState: TAGGED - action: DELETE condition: age: 7d tagState: UNTAGGED - action: DELETE condition: unusedFor: 7d - 触发策略执行(可选)
默认策略每日自动执行,若需部署后立即触发,可在GitHub Actions中添加步骤:- name: Trigger Artifact Registry lifecycle policy run: | gcloud artifacts repositories trigger-lifecycle-policy ${REPO_NAME} \ --location=${GCP_REGION}
方案2:优化自定义清理脚本
若必须使用自定义脚本,针对现有问题优化如下:
- 过滤缓存层镜像
通过--filter排除UNIX纪元时间的缓存层,只保留带标签的镜像,并按时间倒序排列:gcloud container images list-tags "${BASE_IMAGE}" \ --filter="NOT tags:${GITHUB_SHA} AND NOT timestamp.timestamp()=0 AND tags:*" \ --format="value(digest)" \ --sort-by="~timestamp" - 避免删除被引用的镜像
使用--delete-tags-only参数只删除标签,不删除镜像本身,直到镜像无引用后再自动清理:gcloud container images delete -q --delete-tags-only "${BASE_IMAGE}@sha256:$digest" - 完整优化脚本
gcloud container images list-tags "${BASE_IMAGE}" \ --filter="NOT tags:${GITHUB_SHA} AND NOT timestamp.timestamp()=0 AND tags:*" \ --format="value(digest)" \ --sort-by="~timestamp" | \ while read digest do gcloud container images delete -q --delete-tags-only "${BASE_IMAGE}@sha256:$digest" done
方案3:结合Cloud Run当前部署镜像清理
先获取Cloud Run正在使用的镜像摘要,再清理未被使用且符合条件的镜像:
- 获取当前活跃镜像摘要
CURRENT_DIGEST=$(gcloud run services describe ${SERVICE_NAME} \ --region=${GCP_REGION} \ --format="value(status.traffic.latestRevision.image)" | cut -d'@' -f2) - 清理非活跃镜像
gcloud container images list-tags "${BASE_IMAGE}" \ --filter="NOT tags:${GITHUB_SHA} AND NOT digest:${CURRENT_DIGEST#sha256:} AND NOT timestamp.timestamp()=0" \ --format="value(digest)" \ --sort-by="~timestamp" | \ while read digest do gcloud container images delete -q --delete-tags-only "${BASE_IMAGE}@sha256:$digest" done
内容的提问来源于stack exchange,提问作者Harineko
相关产品推荐
相关产品推荐

