在设计云环境时,通常建议设置多个账户。虽然这种方法提供了资源独立性、隔离性、更好的安全性、访问权限和计费边界,但同时也带来了一系列问题。其中一个挑战是在不同环境之间高效地推广和跟踪应用程序。
GitOps方法以及ArgoCD和Kustomize等工具简化了跟踪和推广的过程。但是,“镜像推广”经常被忽视。许多企业采用共享镜像注册表,但很快就会积累许多未使用的版本。
本文探讨了最近的一次旅程,我们在这次旅程中研究了推广镜像的问题以及采用的创新解决方案,同时遵循GitOps的原则。
挑战
最近,一个公司正在考虑将共享的ECR注册表迁移到单独的ECR注册表,以实现成本效益、更好的治理和简化的生命周期管理。
以下是现有基础设施和流水线的状态:
- 每个环境都有一个专用的AWS账户,拥有自己的集群和ArgoCD安装。
- Kustomize用于管理不同环境之间的配置差异。
├── infra │ ├── charts/ └── overlays ├── dev │ ├── patch-image.yaml └── production ├── patch-image.yaml └── patch-replicas.yaml
- Jenkins用于在开发环境中持续构建新的镜像。
然而,这些工具都没有直接支持在ECR注册表之间推广镜像,因此需要探索创新解决方案。
考虑因素:
- 选择性推广:公司的应用程序包括多个模块和团队,具有不同的时间表。因此,需要支持每个发布中仅针对所选模块的镜像推广。
- 优化存储:生产等环境只需要存储推广的镜像版本,减少杂乱并优化资源使用。
- 镜像标签和摘要复制:在ECR注册表之间复制镜像标签和摘要对于安全性和可追溯性至关重要。
潜在解决方案
首先,提出了两种潜在解决方案:
- ECR跨账户复制: AWS的ECR原生支持在两个账户之间复制镜像。然而,目前还没有办法根据任何条件过滤要复制的镜像。作为替代方案,AWS建议基于标签命名规范选择性地复制镜像。然而,由于我们不知道哪些版本将被推广,这就需要在推广之前进行额外的重新标记。
- Jenkins推广流水线:一个Jenkins流水线,用于解析Kustomize Overlays中的镜像标签并以程序方式复制它们。
这两个选项都是可行的,但它们为推广过程引入了额外的复杂性。另外,您需要确保在更新Kustomize Overlays之前推广镜像。
成功策略:ArgoCD PreSync Job
在这种情况下,客户已经在使用ArgoCD进行应用程序更改的持续部署。因此,我们决定将将镜像的交付责任也交给ArgoCD,以交付到目标环境集群。
ArgoCD支持钩子,允许您在部署或同步过程之前或之后运行自定义脚本。
1. ECR Repository Permission: 为Docker镜像授权跨账户拉取访问权限
为了使ArgoCD能够从源ECR拉取镜像,我们需要向我们的仓库添加基于资源的策略。
// cross-account-ecr-read-policy.json{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowPull", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::{DESTINATION_ACCOUNT}:root" // 请替换为您的目标账号 }, "Action": [ "ecr:BatchCheckLayerAvailability", "ecr:BatchGetImage", "ecr:GetDownloadUrlForLayer" ] } ]}
将策略应用于 ECR 仓库:
aws ecr set-repository-policy --repository-name example --policy-text "file://cross-account-ecr-read-policy.json"// 对于多个仓库:aws ecr describe-repositories --query "repositories[].[repositoryName]" | xargs -I {} aws ecr set-repository-policy --repository-name {} --policy-text "file://cross-account-ecr-read-policy.json"
2. PreSync Hook 任务:在账号之间复制镜像
- 我们使用 Crane 在不改变标签和摘要的情况下复制镜像。
- PreSync Hook 任务与其他应用程序清单一起存储在 git 中,并由 ArgoCD 监控。ArgoCD 在同步更改之前运行该任务。
- 源账号是将要拉取镜像的开发或 DevOps 账号。
- 目标账号是需要复制镜像的生产环境或目标环境。
// Helm 模板示例apiVersion: batch/v1kind: Jobmetadata: generateName: argo-presync-promote-image- annotations: argocd.argoproj.io/hook: PreSyncspec: template: spec: volumes: - name: creds emptyDir: {} initContainers: - name: aws-creds image: public.ecr.aws/aws-cli/aws-cli command: - sh - -c - | aws ecr get-login-password > /creds/ecr volumeMounts: - name: creds mountPath: /creds containers: // 为了简洁起见,我假设所有 Helm 值都可在根目录下获取。 - name: promote-image image: gcr.io/go-containerregistry/crane:debug command: - sh - -c - | // 登录到两个 ECR 注册表 cat /creds/ecr | crane auth login {{.Values.sourceAccount}}.dkr.ecr.us-east-1.amazonaws.com -u AWS --password-stdin cat /creds/ecr | crane auth login {{.Values.destinationAccount}}.dkr.ecr.us-east-1.amazonaws.com -u AWS --password-stdin // 从源账号复制镜像到目标账号 crane copy {{.Values.image | replace .Values.destinationAccount .Values.sourceAccount}} {{.Values.image}} volumeMounts: - name: creds mountPath: /creds restartPolicy: Never backoffLimit: 2
结论
总之,团队能够通过使用 PreSync Hook 来按需推广镜像。这使得生产推广成为更新 Kustomize 叠加的单个步骤。
我很想听听您采用的其他选项。例如,另一种方法可能是使用 Kubernetes 动态准入控制来拦截和按需拉取缺失的镜像。