跳至主要内容

嵌入式注册表镜像

版本门

嵌入式注册表镜像从 2024 年 1 月发布的版本开始提供为实验性功能:v1.26.13+k3s1、v1.27.10+k3s1、v1.28.6+k3s1、v1.29.1+k3s1

K3s 嵌入了 Spegel,一个无状态的分布式 OCI 注册表镜像,允许 Kubernetes 集群中的节点之间进行对等共享容器镜像。默认情况下,分布式注册表镜像处于禁用状态。

启用分布式 OCI 注册表镜像

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

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

对等端口可以从 5001 更改,方法是为 K3s 服务设置 K3S_P2P_PORT 环境变量。该端口必须在所有节点上设置为相同的值。更改端口不受支持,也不建议这样做。

要求

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

启用注册表镜像

为注册表启用镜像允许节点从其他节点拉取来自该注册表的镜像,并将该注册表的镜像共享给其他节点。如果在某些节点上为注册表启用了镜像,而在其他节点上没有启用,则只有启用了注册表的节点才会交换来自该注册表的镜像。

为了启用从上游容器注册表镜像镜像,节点必须在 registries.yaml 文件的 mirrors 部分中为该注册表有一个条目。该注册表不需要有任何列出的端点,只需要存在即可。例如,要启用从 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-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 标签时观察到的 特殊 imagePullPolicy 默认值 相一致。

可以通过为 K3s 服务设置 K3S_P2P_ENABLE_LATEST=true 环境变量来启用 latest 标签的镜像。这不受支持,也不建议这样做,原因如上所述。

安全

身份验证

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

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

潜在问题

警告

分布式注册表基于对等原理构建,假设所有集群成员之间具有同等特权和信任。如果这与您的集群安全态势不符,则您不应该启用嵌入式分布式注册表。

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

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

共享断开网络或手动加载的镜像

镜像共享的控制基于源注册表。如果通过断开网络 tarball 直接加载到 containerd 中,或使用 ctr 命令行工具直接加载到 containerd 的镜像存储区中,则如果这些镜像被标记为来自已启用镜像的注册表,则这些镜像将在节点之间共享。

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

推送镜像

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

可以通过运行 ctr -n k8s.io image pull 拉取镜像,或通过使用 ctr -n k8s.io image import 命令加载 docker save 创建的镜像存档,来手动使镜像可通过嵌入式注册表访问。请注意,在通过 ctr 管理镜像时,必须指定 k8s.io 命名空间,以便 kubelet 可以看到它们。