宣布在亚马逊弹性容器注册表中提取 registry.k8s.io 的缓存

作者:贾斯汀·加里森 | 2023 年

简介

容器镜像存储在注册表中并提取到它们运行的环境中。有许多不同类型的注册表,从私有的、自运行的注册表到未经身份验证的公共注册表。您使用的注册表是一种直接依赖关系,可能会影响扩展速度、所运行软件的安全性以及系统的可用性。对于生产环境,建议客户限制影响这些区域的外部依赖关系,并将容器映像托管在私有注册表中。

亚马逊弹性容器注册表 ( Amazon ECR ) 是一项托管服务,用于托管您的开放容器计划 (OCI) 映像和构件。它也可以用作您依赖的来自外部注册表的容器映像的直通缓存。直通式缓存是一种缓存您从上游存储库中使用的图像的方法。容器镜像会被复制并保持最新状态,而无需直接依赖外部注册表。如果上游注册表或容器映像不可用,则仍可以使用您的缓存副本。

在发布时,亚马逊 ECR 支持 Ama zon ECR Public 和 Quay Container 注册表作为提取缓存源。从今天开始,你还可以使用亚马逊 ECR 作为 kubernetes 官方 Kubernetes 注册表的直通缓存,网址为 registry.k8s.io。有了直通缓存,你就不会对常用镜像(如 Kubernetes 指标服务器或集群自动扩缩器)的社区运行的注册表产生外部依赖关系。此功能现已正式上线,可在所有支持 Amazon ECR 直通缓存的地区使用。

Kubernetes 社区映像注册表 最近从 k8s.gcr.io 更改为 registr y.k8s.io , 以保持注册表的可持续性并提高 A WS 用户 的性能。此更改对用户来说基本上是透明的,但它需要更新清单才能继续收到新版本。Amazon EKS 集群的核心组件不使用社区注册表,基础映像来自亚马逊托管的存储库。但是,您部署到集群的工作负载可能来自社区注册表。

解决方案概述

即使 Kubernetes 注册表发生了变化,亚马逊云科技 和 Kubernetes 项目仍建议客户拥有其依赖项的所有权,以避免意外可用性事件并进行灾难恢复。拥有上游容器依赖关系的典型选项有两个:

  1. 手动将图像从一个注册表同步到另一个注册表
  2. 按要求缓存图像

在注册表之间同步图像需要您首先识别要同步的所有图像和标签,然后 使用诸如c ran e 或skop eo 之类的工具 从一个注册表中提取图像并将其推送到另一个注册表。如果你使用大量图片,或者如果你有多个账户和区域,这可能是一项繁琐的工作,而且容易出错。要使图像保持最新状态,您需要定期运行同步命令。

直通式缓存是一种在收到请求时自动将图像存储在新存储库中的方法。首次请求时,直通缓存会自动在您的注册表中创建图像存储库,并使图像保持最新状态并可供将来提取时使用。更新映像时,您无需手动识别上游依赖关系或手动同步图像。

为亚马逊 EKS 客户带来的其他好处包括:

  • 通过将图像存储在同一区域来缩短图像提取时间
  • 可选自动复制到多个区域和账户
  • 跨账户提取权限
  • 图像漏洞扫描和加密

除了这些好处外,您还可以通过减少从上游来源提取图像来支持上游 Kubernetes 项目。使用 Amazon ECR 直通缓存不会产生额外费用,标准的 ECR 存储定价 适用于缓存的图像。

草率排练

亚马逊 ECR 提取缓存入门

登录 亚马逊云科技 管理控制台 并创建新的直通缓存规则。选择左侧的 私有注册表 选项卡,然后选择 提取缓存 以 更新缓存规则。

选择 “ 添加规则 ”, 然后在 “ 公共注册表 ” 下拉列表中选择 registry.k8 s. io。在目标选项卡中创建命名空间。缓存的图像与上游的路径相同,命名空间以其路径为前缀。

Image shows AWS Console with a dropdown box selecting the Kubernetes public registry.

如果您创建命名空间 k8s ,则缓存的图像将在以下网址提供:

<account number>.dkr.ecr.<region>.amazonaws.com/k8s

您还可以使用以下命令从 亚马逊云科技 命令行接口 (AW S CLI ) 创建直通缓存规则:

aws ecr create-pull-through-cache-rule --ecr-repository-prefix k8s \
  --upstream-registry-url registry.k8s.io

使用缓存

要测试缓存,你可以使用新规则手动提取在 regist ry.k8s.io 中找到的图像。

首次使用拉取缓存命名空间提取图像时,它会自动创建存储库。此命令提取 busybox 映像,该映像创建存储库并使用上游映像填充存储库。

docker pull <account number>.dkr.ecr.<region>.amazonaws.com/k8s/busybox:latest

现在,您可以将所有工作负载和集群配置为从缓存中提取,而不是从社区注册表中提取。以下是三个示例,说明如何根据管理 Kubernetes 工作负载的方式使用新的缓存存储库。

手动更新清单

使用新的缓存图像的第一个选项是最简单的。如果你有静态的 Kubernetes 清单文件,那么你可以更新清单中的 image: 字段以使用新的存储库。这适用于包含手动应用到集群的清单的 Git 存储库或包含已渲染清单文件的 GitOps 存储库。

grep -lr 'image: registry.k8s.io/' \
  | xargs sed -i \
    's,registry.k8s.io,<account number>.dkr.ecr.<region>.amazonaws.com/k8s,g'

要识别使用 registry.k8s. io 或 k8s. gcr.io 注册表 的集群中正在运行的工作负载,你可以使用社区镜像 kubectl 插 件。

添加 helm 变量以覆盖存储库

如果你使用 helm 来安装和管理工作负载,那么你可以替换镜像存储库以从私有存储库中提取。大多数社区图表都有 image.repository 变量,但您可能需要验证图表的变量。

helm upgrade --install metrics-server \
  --set image.repository=<account number>.dkr.ecr.<region>.amazonaws.com/k8s/metrics-server/metrics-server \
  metrics-server/metrics-server

您还可以在 值文件 中设置此变量 ,以便更轻松地配置正确的区域设置。

使用策略自动重写注册表 URI

使用注册表的第三种选择是在向集群提交任务时修改映像规范。这可以通过自定义 webhook 或一般使用策略来实现。在这里,我们将向您展示如何为 Kyvern o 编写政策。

动态重写作业以使用缓存的好处是,它还可以修改可能没有预定义清单的侧车、初始化容器和调试容器。

你可以按照 Kyverno 的 安装说明 开始使用。要部署预构建的发行版,image 您可以在开发集群中以管理员用户身份使用此命令。

kubectl apply -f \
  
          
          
 
          
          
          
          
            https://github.com/kyverno/kyverno/releases/download/v1.9.0/install.yaml 
          

现在,您可以创建 ClusterPolicy,为尝试使用上游 registry.k8s.io 注册表的工作负载动态执行注册表重写。

apiVersion : kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: change-deprecated-registry
  annotations:
    policies.kyverno.io/title: Use ECR Pull Through Cache for registry.k8s.io
    policies.kyverno.io/category: Best Practices, EKS Best Practices
    policies.kyverno.io/severity: high
    policies.kyverno.io/minversion: 1.6.0
    policies.kyverno.io/description: >-
      Use a ECR Pull Through Cache instead of upstream registry.k8s.io community registry.
spec:
  mutateExistingOnPolicyUpdate: false
  rules:
  - name: change-deprecated-containers
    match:
      any:
      - resources:
          kinds:
          - Pod
    preconditions:
      all:
      - key: "{{request.operation || 'BACKGROUND'}}"
        operator: AnyIn
        value:
        - CREATE
        - UPDATE
      - key: registry.k8s.io
        operator: AnyIn
        value: "{{ images.containers.*.registry[] || `[]` }}"
    mutate:
      foreach:
      - list: "request.object.spec.containers"
        patchStrategicMerge:
          spec:
            containers:
            - name: "{{ element.name }}"
              image: <account number>.dkr.ecr.<region>.amazonaws.com/k8s/{{ images.containers."{{element.name}}".path}}:{{images.containers."{{element.name}}".tag}}
  - name: change-deprecated-initcontainers
    match:
      any:
      - resources:
          kinds:
          - Pod
    preconditions:
      all:
      - key: "{{request.operation || 'BACKGROUND'}}"
        operator: AnyIn
        value:
        - CREATE
        - UPDATE
      - key: "{{ request.object.spec.initContainers[] || '' | length(@) }}"
        operator: GreaterThanOrEquals
        value: 1
      - key: registry.k8s.io
        operator: AnyIn
        value: "{{ images.initContainers.*.registry[] || `[]` }}"
    mutate:
      foreach:
      - list: "request.object.spec.initContainers"
        patchStrategicMerge:
          spec:
            initContainers:
            - name: "{{ element.name }}"
              image: <account number>.dkr.ecr.<region>.amazonaws.com/k8s/{{ images.initContainers."{{element.name}}".name}}:{{images.initContainers."{{element.name}}".tag}}

值得注意的是,根据为 你的 Kyverno webhook 设置的 失败策略,此策略 可能无法捕获部署到集群的所有工作负载。 在中断期间,可能需要在出现故障时忽略 webhook,但应如何配置策略 webhook 由您决定。

其他使用选项

以下是一些其他方法,您可以利用直通缓存和其他 Amazon ECR 功能。

复制和跨账户权限

仅在创建直通缓存规则的区域中才需要复制规则。您应该 在 提取映像之前 创建复制规则,因为在填充存储库时会进行复制。如果 us-east-1 中存在直通缓存规则,并且我们想要复制到 us-west-2 和 us-east-2,则可以使用以下复制规则。

{
  "rules": [
    {
      "destinations": [
        {
          "region": "us-west-2",
          "registryId": "<account number>"
        },
        {
          "region": "us-east-2",
          "registryId": "<account number>"
        }
      ],
      "repositoryFilters": [
        {
          "filter": "k8s",
          "filterType": "PREFIX_MATCH"
        }
      ]
    }
  ]
}

创建规则后,将在主区域中提取和缓存的所有存储库自动创建并复制到其他区域。

如果您需要从其他账户提取镜像,则需要为每个区域的每个存储库添加权限。在添加跨账户权限之前,请确保已经创建并复制了存储库。

首先创建一个 repo-policy.txt 文件以允许从所需的其他帐户中提取图像。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "pull access",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<your 2nd account>:root"
      },
      "Action": [
        "ecr:BatchGetImage",
        "ecr:GetDownloadUrlForLayer"
      ]
    }
  ]
}

然后获取需要该策略的所有存储库的列表。

aws ecr describe-repositories --query 'repositories[].[repositoryName]' \
  --output text | grep 'k8s/'

如果存储库列表看起来正确,则可以使用以下命令为所有存储库设置策略:

for REPO in $(aws ecr describe-repositories \
    --query 'repositories[].[repositoryName]' \
    --output text | grep 'k8s/'); do \
        AWS_PAGER="" aws ecr set-repository-policy \
            --repository-name "${REPO}" \
            --policy-text file://repo-policy.json
done

确保对存储容器的每个区域重复该步骤。

工作节点提取映像时自动创建 repo

一些公司对在其环境中可以使用哪些图像有限制。如果您有这些限制,则应识别并预先填充直通式缓存图像和标签。默认情况下,Kubernetes 工作节点将无法从拉取缓存中提取新镜像,因为它需要额外的 亚马逊云科技 身份和访问管理 (亚马逊云科技 I AM ) 权限才能创建存储库。

如果您希望在 Amazon EKS 节点请求上游映像时自动创建存储库,则需要向工作节点添加以下 亚马逊云科技 IAM 权限。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "EksPtc",
            "Effect": "Allow",
            "Action": [
                "ecr:CreateRepository",
                "ecr:ReplicateImage",
                "ecr:BatchImportUpstreamImage"
            ],
            "Resource": "*"
        }
    ]
}

如果您的 Kubernetes 集群与 Amazon ECR 注册表位于同一个账户和区域,则可以部署以下 Pod 来验证映像拉取是否有效。

kind: Pod
metadata:
  name: busybox
  namespace: default
spec:
  restartPolicy: OnFailure
  containers:
  - name: busybox
    image: <account number>.dkr.ecr.<region>.amazonaws.com/k8s/busybox:latest
    command: ['sh', '-c', 'echo "Success!" && sleep 1m']

这会提取图像注册表.k8s.io/busybox: latest 并将其缓存在亚马逊 ECR 存储库中 k8s/ 命名空间下。

如果您的工作节点位于无法访问互联网的私有子网上,则需要预先填充要使用的映像,因为直通式缓存需要访问互联网才能向上游注册表查询图像元数据。你可以从具有互联网访问权限的单独集群中执行此操作,也可以使用 docker 或 fin ch 通过命令行手动执行此操作。创建图像存储库后,它会保持最新状态,无需额外同步。

自托管 Kubernetes

如果您在 亚马逊云科技 上托管自己的 Kubernetes 控制平面,则应使用控制平面组件的直通缓存。这可确保您无需依赖社区注册表即可继续部署和管理集群。

Kubespray 这样的工具有容器镜像选项 KOps 也有镜像 选项。 您需要研究您的工具对私有、经过身份验证的镜像的支持。 包括 KOP 在内的一些工具尚不支持经过身份验证的镜像,这是 Amazon ECR 提取缓存的必要条件。

正在清理

如果您不想再使用 Amazon ECR 直通缓存,可以使用以下命令将其删除:

aws ecr delete-pull-through-cache-rule --ecr-repository-prefix k8s

删除通过首先列出所有存储库而创建的每个存储库:

aws ecr describe-repositories --query 'repositories[].[repositoryName]' \
  --output text | grep 'k8s/'

并使用以下命令将其删除:

for REPO in $(aws ecr describe-repositories \
    --query 'repositories[].[repositoryName]' \
    --output text | grep 'k8s/'); do \
        AWS_PAGER="" aws ecr delete-repository \
            --repository-name "${REPO}"
done

你需要更新 Kubernetes 清单、Helm 图表或政策规则,才能将图片 URI 恢复为 registry.k8s.io。

结论

在这篇文章中,我们向您展示了如何为来自 registry.k8s.io 的 Kubernetes 镜像创建容器镜像拉取缓存。上游 Kubernetes 注册表由 Kubernetes 社区的志愿者运营,资金来自于 亚马逊云科技 和其他云提供商的积分。没有关于可用性的待命时间表或服务等级协议 (SLA)。虽然社区在扩展和提高性能方面做得非常出色,但谢谢大家!— 关键可用性依赖外部风险。

通过容器提取缓存和更新的工作负载定义,您可以进一步控制工作负载依赖关系和可靠性。这些更改有初始设置成本,但它们对上游注册表有帮助,可以更好地控制和深入了解这些映像在您的环境中是如何使用的。

Justin Garrison

贾斯汀·加里森

贾斯汀·加里森是 亚马逊云科技 容器团队的高级开发倡导者。他长期以来一直是开源贡献者,并且非常关心开放社区。在 亚马逊云科技 之前,贾斯汀为 Disney+ 和《冰雪奇缘 II》和《莫阿娜》等动画电影构建了基础设施。你可以通过 @rothgar 在 Twitter 上联系他


*前述特定亚马逊云科技生成式人工智能相关的服务仅在亚马逊云科技海外区域可用,亚马逊云科技中国仅为帮助您发展海外业务和/或了解行业前沿技术选择推荐该服务。