4. 容器镜像仓库与制品管理
在云原生应用交付链路中,镜像仓库不只是“存放镜像的地方”,它是构建产物进入生产环境前的最后一道可控关口。Amazon ECR(Elastic Container Registry)提供私有仓库、镜像扫描、跨区域复制、生命周期策略、镜像签名等能力,配合 ECR Public 可以形成从构建、存储、分发到验证的完整制品供应链。本节围绕“如何把镜像安全地管起来”展开,重点讲清仓库创建、扫描机制、复制策略、生命周期规则以及签名验证的实际做法。
私有仓库的创建与访问控制
ECR 私有仓库的最小创建单元是 repository,命名通常采用 应用名/组件名 的形式,例如 order-service/api。创建时建议开启 tag immutability(标签不可变),这样同一个 tag 不能被重复推送覆盖,避免“latest 被悄悄替换”导致生产环境拉取到非预期镜像。访问控制通过 IAM 策略和仓库策略两层实现:IAM 决定“谁可以调用 ECR API”,仓库策略决定“哪些账号或角色可以拉取/推送该仓库”。在跨账号场景中,通常由共享账号在仓库策略中授予业务账号 ecr:BatchGetImage、ecr:GetDownloadUrlForLayer 等拉取权限,而不是直接共享凭证。
推送镜像的标准流程如下,其中 aws ecr get-login-password 返回的临时令牌有效期约 12 小时,适合在 CI 流水线中动态获取:
aws ecr create-repository \
--repository-name order-service/api \
--image-tag-mutability IMMUTABLE \
--image-scanning-configuration scanOnPush=true \
--region cn-north-1
aws ecr get-login-password --region cn-north-1 | \
docker login --username AWS --password-stdin \
123456789012.dkr.ecr.cn-north-1.amazonaws.com
docker tag order-api:v1.4.2 \
123456789012.dkr.ecr.cn-north-1.amazonaws.com/order-service/api:v1.4.2
docker push 123456789012.dkr.ecr.cn-north-1.amazonaws.com/order-service/api:v1.4.2
镜像扫描:基础扫描与增强扫描
ECR 提供两种扫描方式。基础扫描(Basic scanning)基于开源 Clair 规则库,支持 scanOnPush 在推送时自动触发,也可手动调用 start-image-scan;它覆盖操作系统包漏洞,但不检测编程语言依赖。增强扫描(Enhanced scanning,基于 Amazon Inspector)可以同时检测 OS 包和语言级依赖(如 Maven、npm、Python 包),并支持持续扫描——当新漏洞披露时自动重新评估已有镜像。对于生产级供应链,建议对关键仓库启用增强扫描,并把 scan frequency 设为 CONTINUOUS_SCAN。
扫描结果可通过 describe-image-scan-findings 查看,关键字段是 severity(CRITICAL/HIGH/MEDIUM/LOW)和 fixAvailable。实践中常见的门禁做法是:在 CI 中拉取扫描结果,若存在 CRITICAL 且 fixAvailable=true 的漏洞,则阻断部署并输出漏洞列表。需要注意,扫描是异步的,推送后立即查询可能返回 IN_PROGRESS,应轮询直到 COMPLETE 再判断。
跨区域复制与生命周期策略
跨区域复制用于把镜像自动同步到其他 Region,典型场景是多地部署时让各 Region 就近拉取,降低跨区流量和拉取延迟。复制在仓库级别配置,可指定目标 Region、目标仓库前缀,甚至跨账号复制。复制是异步的,源仓库推送成功后目标仓库通常在数十秒内出现同名镜像;若目标仓库不存在且未开启自动创建,复制会失败,因此建议在规则中允许自动创建目标仓库。
生命周期策略(Lifecycle Policy)解决“镜像越积越多”的问题。策略由规则组成,每条规则包含 selection(tagStatus、tagPrefixList、countType、countNumber)和 action(expire)。例如:保留最近 30 个带 v 前缀的发布镜像,超过 30 天且未被任何 tag 引用的 untagged 镜像自动过期。规则按优先级从低到高执行,rulePriority 越小越先匹配。一个常见误区是把 countType 设为 imageCountMoreThan 时忘记限制 tagStatus,导致把正在使用的发布镜像也清理掉,因此建议对发布 tag 和临时 tag 分别建规则。
镜像签名与供应链验证
扫描解决“已知漏洞”,签名解决“来源可信与未被篡改”。ECR 本身不内置签名服务,但支持存储 OCI 关联制品,因此可以用 cosign 把签名作为独立制品推送到同一仓库。典型做法是:CI 构建完成后用私钥对镜像 digest 签名,部署侧在准入控制器(如 Kyverno、OPA Gatekeeper)中调用 cosign verify,只有签名有效且公钥匹配的镜像才允许创建 Pod。签名应绑定 digest 而非 tag,因为 tag 可变,digest 才是内容寻址的唯一标识。
cosign sign --key aws-kms://arn:aws:kms:cn-north-1:123456789012:key/abcd-... \
123456789012.dkr.ecr.cn-north-1.amazonaws.com/order-service/api@sha256:9f2c...
cosign verify --key aws-kms://arn:aws:kms:cn-north-1:123456789012:key/abcd-... \
123456789012.dkr.ecr.cn-north-1.amazonaws.com/order-service/api@sha256:9f2c...
ECR Public 则用于托管可公开分发的镜像,例如团队自研的基础镜像、CLI 工具镜像。它支持匿名拉取,适合作为公共依赖源,但绝不能把含内部配置、密钥或业务代码的镜像推到 Public。实践中常见的组合是:基础镜像发布到 ECR Public,业务镜像存放在私有 ECR,构建时从 Public 拉取基础层,最终制品只进私有仓库。
一个可落地的仓库治理参数示例
下表给出一组示例参数,用于说明如何把上述能力组合成可执行的治理规则。参数为教学示例,实际取值需结合团队发布节奏和合规要求调整。
| 治理项 | 示例配置 | 作用 |
|---|---|---|
| tag 不可变 | IMMUTABLE | 防止发布 tag 被覆盖 |
| 推送扫描 | scanOnPush=true,增强扫描 | 推送即检测 OS 与语言依赖漏洞 |
| 扫描门禁 | CRITICAL 且 fixAvailable 则阻断 | 阻止高危镜像进入部署 |
| 跨区复制 | cn-north-1 → cn-south-1 | 就近拉取,降低延迟与流量 |
| 生命周期 | 保留 30 个 v*,untagged 30 天过期 | 控制存储成本,保留发布版本 |
| 签名验证 | cosign + KMS 密钥,按 digest 校验 | 确保镜像来源可信、未被篡改 |
把以上能力串起来,ECR 就不只是镜像存储,而是可审计、可复制、可清理、可验证的制品供应链节点。构建产物从进入仓库那一刻起,就带着扫描结论、复制状态、生命周期归属和签名信息,部署侧只需按 digest 拉取并验证签名,即可在“能跑”之外回答“这个镜像是否可信、是否安全、是否该保留”。