本文档采用自动化机器翻译技术翻译。 尽管我们力求提供准确的译文,但不对翻译内容的完整性、准确性或可靠性作出任何保证。 若出现任何内容不一致情况,请以原始 英文 版本为准,且原始英文版本为权威文本。

嵌入式注册表镜像

版本门

嵌入式注册表镜像作为实验性功能自2024年1月的版本开始提供:v1.26.13+k3s1、v1.27.10+k3s1、v1.28.6+k3s1、v1.29.1+k3s1,并在2024年12月的版本中正式发布:v1.29.12+k3s1、v1.30.8+k3s1、v1.31.4+k3s1。

K3s 嵌入了 Spegel,这是一个无状态的分布式 OCI 注册表镜像,允许 Kubernetes 集群中的节点之间进行点对点的容器镜像共享。分布式注册表镜像默认是禁用的。为了让 K3s 利用它,您必须启用 分布式 OCI 注册表镜像注册表镜像,具体说明见以下小节。

启用分布式 OCI 注册表镜像

为了启用嵌入式注册表镜像,服务器节点必须使用 --embedded-registry 标志启动,或在配置文件中使用 embedded-registry: true。 此选项使嵌入式镜像可在集群中的所有节点上使用。

当在集群级别启用时,所有节点将在 6443 端口上托管本地 OCI 注册表,并通过 5001 端口通过点对点网络发布可用镜像的列表。 在任何节点的 containerd 容器镜像存储中可用的任何镜像,都可以被其他集群成员拉取,而无需访问外部注册表。 通过 隔离镜像 tar 文件 导入的镜像在 containerd 中被固定,以确保它们保持可用,并且不会被 Kubelet 垃圾回收清理。

通过为 K3s 服务设置 K3S_P2P_PORT 环境变量,可以将点对点端口从 5001 更改。所有节点上的端口必须设置为相同的值。 更改端口不受支持且不推荐。

要求

当嵌入式注册表镜像启用时,所有节点必须能够通过其内部 IP 地址相互访问,使用 TCP 端口 5001 和 6443。 如果节点无法相互访问,拉取镜像可能会花费更长时间,因为 containerd 会首先尝试分布式注册表,然后再回退到其他端点。

启用注册表镜像

为注册表启用镜像允许节点从其他节点拉取该注册表的镜像,并与其他节点共享该注册表的镜像。 如果某些节点启用了镜像的注册表,但其他节点没有启用,只有启用了注册表的节点才会从该注册表交换镜像。

为了启用从上游容器注册表的镜像,节点必须在 mirrorsregistries.yaml 部分中为该注册表添加条目。 注册表不需要列出任何端点,只需存在即可。 例如,要启用从 docker.ioregistry.k8s.io 的图像的分布式镜像,请在所有集群节点上将 registries.yaml 配置为以下内容:

mirrors:
  docker.io:
  registry.k8s.io:

注册表镜像的端点也可以像往常一样添加。 在以下配置中,图像拉取尝试将首先尝试嵌入的镜像,然后是 mirror.example.com,最后是 docker.io

mirrors:
  docker.io:
    endpoint:
      - https://mirror.example.com

如果您直接使用私有注册表,而不是作为上游注册表的镜像,您可以以与启用公共注册表相同的方式启用分布式镜像——通过在镜像部分列出它:

mirrors:
  mirror.example.com:
版本门

自2024年3月发布以来,支持通配符:v1.26.15+k3s1,v1.27.12+k3s1,v1.28.8+k3s1,v1.29.3+k3s1。

"*" 通配符镜像条目可用于启用所有注册表的分布式镜像。请注意,星号必须被引号引起来:

mirrors:
  "*":

如果在节点上没有启用任何注册表进行镜像,则该节点在分布式注册表中不以任何身份参与。

有关 registries.yaml 文件结构的更多信息,请参见 私有注册表配置

默认端点回退

默认情况下,containerd 在从配置了镜像端点的注册表拉取时将回退到默认端点。如果您想禁用此功能,并且仅从配置的镜像和/或嵌入的镜像中拉取图像,请参见私有注册表配置文档的 默认端点回退 部分。

请注意,如果您使用 --disable-default-registry-endpoint 选项并希望允许直接从特定注册表拉取,同时禁止其他注册表,您可以明确提供一个端点,以允许图像拉取回退到注册表本身:

mirrors:
  docker.io:           # no default endpoint, pulls will fail if not available on a node
  registry.k8s.io:     # no default endpoint, pulls will fail if not available on a node
  mirror.example.com:  # explicit default endpoint, can pull from upstream if not available on a node
    endpoint:
      - https://mirror.example.com

最新标签

当未为容器图像指定标签时,隐式默认标签为 latest。此标签经常更新,以指向图像的最新版本。由于此标签将根据拉取时间指向图像的不同修订,因此分布式注册表 将不会 从其他节点拉取 latest 标签。这迫使containerd访问上游注册表或注册表镜像,以确保对`latest`标签所指内容的一致视图。

这与Kubernetes在使用`latest`标签为容器镜像时观察到的https://kubernetes.io/docs/concepts/containers/images/#imagepullpolicy-defaulting[特殊`imagePullPolicy`默认]一致。

通过为K3s服务设置`K3S_P2P_ENABLE_LATEST=true`环境变量,可以启用对`latest`标签的镜像。 这不被支持且不推荐,原因如上所述。

安全性

身份验证

访问嵌入式镜像的注册表API需要有效的客户端证书,该证书由集群的客户端证书颁发机构签署。

访问分布式哈希表的点对点网络需要一个由服务器节点控制的预共享密钥。 节点使用预共享密钥和由集群证书颁发机构签署的证书相互认证。

潜在问题

分布式注册表建立在点对点原则之上,并假设所有集群成员之间具有相等的特权和信任级别。 如果这与您集群的安全态势不符,则不应启用嵌入式分布式注册表。

嵌入式注册表可能会提供节点本来无法访问的镜像。 例如,如果您的某些镜像是从需要通过 Kubernetes 镜像拉取密钥或 registries.yaml 中的凭据进行身份验证的注册表、项目或储存库中拉取的,分布式注册表将允许其他节点共享这些镜像,而无需向上游注册表提供任何凭据。

具有将镜像推送到一个节点的containerd镜像存储的用户,可能会利用这一点来“毒害”其他集群节点的镜像,因为其他节点将信任该节点所宣传的标签,并在未与上游注册表核对的情况下使用它。 如果镜像完整性很重要,您应该使用镜像摘要而不是标签,因为摘要无法以这种方式被毒害。

共享隔离或手动加载的镜像

镜像共享是基于源注册表进行控制的。 通过隔离tar包预导入或使用`ctr`命令行工具直接加载到containerd的镜像存储中的镜像,如果被标记为来自启用镜像的注册表,则在节点之间共享。

请注意,镜像看似来自的上游注册表实际上不必存在或可达。 例如,您可以将镜像标记为来自虚构的上游注册表,并将这些镜像导入到containerd的镜像存储中。 只要该注册表在`registries.yaml`中列出,您就可以从所有集群成员中拉取这些镜像。

推送镜像

嵌入式注册表是只读的,无法直接使用 docker push 或其他与 OCI 注册表交互的常用工具进行推送。

可以通过运行 ctr -n k8s.io image pull 拉取镜像,或通过 docker save 创建的镜像归档文件,使用 ctr -n k8s.io image import 命令或 预导入功能 手动使镜像在嵌入式注册表中可用。 请注意,在通过 ctr 管理镜像时,必须指定 k8s.io 名称空间,以便它们对 kubelet 可见。