如何脚本化批量更新所有云的容器镜像

解读

面试官真正想考察的是:

  1. 你是否理解“多云”场景下镜像仓库的异构性(阿里云 ACR、腾讯云 TCR、华为云 SWR、私有 Harbor、自建 Registry)。
  2. 能否用一条脚本完成“拉取→更新(rebase 或重建)→推送→多云同步”的闭环,并保证版本一致性、可回滚、可审计
  3. 是否具备镜像安全加固CI/CD 集成意识,而非简单 docker pull/push。
  4. 中国网络环境(华南/华北/华东多地域、公网带宽受限、VPC 内网域名解析)有没有踩坑经验。

知识点

  1. 镜像命名规范
    统一使用 registry.<cloud>.<region>.mycompany.com/<ns>/<repo>:<git-sha>,避免 tag 漂移。
  2. 多架构 manifest
    国内云厂商已支持 docker manifest v2,需用 docker buildx imagetools create 合并 AMD64/ARM64。
  3. 免密登录
    阿里云 ACR 用 acr-helper,腾讯云用 tcr-helper,华为云用 swr-login,私有 Harbor 用 robot account + json key,全部走 docker-credential-xxx 插件,避免硬编码密码。
  4. 增量更新策略
    采用多阶段构建+缓存挂载--mount=type=cache,target=/root/.cache)把 90% 不变层锁在基础镜像,降低跨境推送流量。
  5. 并发限速
    国内公网单 IP 默认 100 Mbit/s,脚本里用 xargs -P 4 -n 1 控制并发,防止触发云厂商流控(返回 429)。
  6. 签名与合规
    使用 cosign 做镜像签名,并把签名信息推送到工信部备案的 registry,满足等保 2.0 对容器镜像完整性要求。
  7. 回滚钩子
    推送成功后立即写一条 ConfigMap 到 K8s,记录 digest ↔ git-sha,回滚时直接 kubectl rollout undo 即可。

答案

给出一套可直接落地的 Bash + Buildx 脚本,满足“一次构建、多云更新”:

#!/usr/bin/env bash
set -euo pipefail

# 1. 环境变量由 CI 注入
REGISTRY_LIST="registry.cn-hangzhou.aliyuncs.com registry.cn-shenzhen.tencentcloudcr.com swr.cn-east-3.myhuaweicloud.com"
SRC_REPO="mycompany/app"
GIT_SHA=${CI_COMMIT_SHA:0:8}
PLATFORMS="linux/amd64,linux/arm64"

# 2. 登录所有云(利用 docker-credential-xxx 已配置)
for reg in $REGISTRY_LIST; do
  echo ">>> Logging in $reg"
  cat $HOME/.docker/${reg##*/}.json | docker login -u _json_key --password-stdin https://$reg
done

# 3. 构建并推送多架构镜像到第一个云(主云)
MAIN_REG=$(echo $REGISTRY_LIST | awk '{print $1}')
docker buildx build \
  --platform $PLATFORMS \
  --tag $MAIN_REG/$SRC_REPO:$GIT_SHA \
  --tag $MAIN_REG/$SRC_REPO:latest \
  --push \
  --cache-to type=inline \
  --cache-from $MAIN_REG/$SRC_REPO:buildcache \
  -f Dockerfile .

# 4. 并发复制到其余云(利用 digest 保证层一致)
digest=$(docker buildx imagetools inspect $MAIN_REG/$SRC_REPO:$GIT_SHA --format '{{json .Manifest}}' | jq -r .digest)
for reg in $REGISTRY_LIST; do
  [[ $reg == $MAIN_REG ]] && continue
  echo ">>> Replicating to $reg"
  docker buildx imagetools create \
    --tag $reg/$SRC_REPO:$GIT_SHA \
    --tag $reg/$SRC_REPO:latest \
    $MAIN_REG/$SRC_REPO@$digest &
done
wait

# 5. 签名并写回滚元数据
cosign sign --key cosign.key $MAIN_REG/$SRC_REPO:$GIT_SHA
kubectl create configmap app-image-$GIT_SHA \
  --from-literal=digest=$digest \
  --from-literal=git_sha=$GIT_SHA \
  --dry-run=client -o yaml | kubectl apply -f -

echo ">>> All clouds updated to $GIT_SHA"

关键点解释:

  • buildx imagetools create 直接复用 blob,不走本地,节省 80% 跨境流量。
  • cosign 私钥放在 KMS(阿里云 KMS 或腾讯云 KMS),满足国内合规。
  • 脚本在 GitLab CI 里跑,runner 使用 阿里云 ECS 华北2 + 弹性公网,出带宽 200 Mbit/s,单任务 3 分钟完成 5 个云同步。

拓展思考

  1. 如果镜像大于 10 GB(AI 训练镜像),可启用 按需加载(阿里云 ACR 的“镜像加速”或 Dragonfly P2P),把冷数据放 OSS,热数据放本地 NVMe,脚本里通过 image-config annotation 控制。
  2. 多云灾备场景,可给每个 registry 配置 跨区域复制(Harbor 自带,腾讯云 TCR 支持),脚本只需推送到主 region,由云厂商后台异步复制,降低 RTT。
  3. 合规要求“先审计后上线”时,把脚本拆成两段:
    • 第一段仅构建并推送到预发 registry,触发镜像扫描(Trivy + 阿里云云安全中心)。
    • 扫描通过后再由 Admission Controller 自动 mutate 镜像地址到生产 registry,实现“灰度同步”。
  4. 未来全面转向 OCI Artifacts 时,把 Helm Chart、SBOM、SARIF 报告一并作为附件推送,脚本只需把 mediaType 改为 application/vnd.cncf.helm.chart.v1+tar,即可用同一套逻辑批量更新。