镜像

容器镜像表示封装了应用程序及其所有软件依赖项的二进制数据。容器镜像是可独立运行的可执行软件包,它们对其运行时环境做出了明确的假设。

通常,你会为应用程序创建一个容器镜像并将其推送到一个注册中心,然后在 Pod 中引用它。

本页面概述了容器镜像的概念。

镜像名称

容器镜像通常会有一个名称,例如 pauseexample/mycontainerkube-apiserver。镜像还可以包含一个注册中心主机名;例如:fictional.registry.example/imagename,也可能包含一个端口号;例如:fictional.registry.example:10443/imagename

如果你未指定注册中心主机名,Kubernetes 假定你指的是 Docker 公共注册中心。你可以在容器运行时配置中设置默认镜像注册中心来更改此行为。

在镜像名称部分之后,你可以添加一个 标签(tag)摘要(digest)(与你使用 dockerpodman 等命令时的方式相同)。标签允许你识别同一系列镜像的不同版本。摘要是镜像特定版本的唯一标识符。摘要是镜像内容的哈希值,并且是不可变的。标签可以指向不同的镜像,但摘要是固定的。

镜像标签由小写和大写字母、数字、下划线 (_)、句点 (.) 和连字符 (-) 组成。标签最长可达 128 个字符,并且必须符合以下正则表达式模式:[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}。你可以在 OCI Distribution Specification 中阅读更多内容并找到验证正则表达式。如果你没有指定标签,Kubernetes 假定你指的是 latest 标签。

镜像摘要由哈希算法(例如 sha256)和哈希值组成。例如:sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07。你可以在 OCI Image Specification 中找到更多关于摘要格式的信息。

Kubernetes 可以使用的一些镜像名称示例:

  • busybox — 仅有镜像名称,没有标签或摘要。Kubernetes 将使用 Docker 公共注册中心和 latest 标签。等同于 docker.io/library/busybox:latest
  • busybox:1.32.0 — 带标签的镜像名称。Kubernetes 将使用 Docker 公共注册中心。等同于 docker.io/library/busybox:1.32.0
  • registry.k8s.io/pause:latest — 带自定义注册中心和 latest 标签的镜像名称。
  • registry.k8s.io/pause:3.5 — 带自定义注册中心和非 latest 标签的镜像名称。
  • registry.k8s.io/pause@sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07 — 带摘要的镜像名称。
  • registry.k8s.io/pause:3.5@sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07 — 带标签和摘要的镜像名称。仅使用摘要进行拉取。

更新镜像

当你首次创建 DeploymentStatefulSet、Pod 或其他包含 PodTemplate 的对象时,如果未明确指定拉取策略,则默认情况下,该 Pod 中所有容器的拉取策略将设置为 IfNotPresent。此策略会导致 kubelet 跳过拉取已存在的镜像。

镜像拉取策略

容器的 imagePullPolicy 和镜像的标签都会影响 kubelet 尝试拉取(下载)指定镜像的 时间

以下是你可以为 imagePullPolicy 设置的值及其影响的列表

IfNotPresent
仅当镜像在本地不存在时才拉取。
Always
每当 kubelet 启动容器时,它都会查询容器镜像注册中心,将名称解析为镜像摘要。如果 kubelet 在本地缓存了具有该确切摘要的容器镜像,则 kubelet 将使用其缓存的镜像;否则,kubelet 将拉取具有已解析摘要的镜像,并使用该镜像启动容器。
Never
kubelet 不会尝试获取镜像。如果镜像以某种方式已在本地存在,kubelet 会尝试启动容器;否则,启动失败。有关更多详细信息,请参阅预拉取镜像

只要注册中心可靠可访问,底层镜像提供程序的缓存语义即使是 imagePullPolicy: Always 也能高效运行。你的容器运行时可以注意到镜像层已存在于节点上,因此无需再次下载。

为确保 Pod 始终使用相同版本的容器镜像,你可以指定镜像的摘要;将 : 替换为 @(例如,image@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2)。

当使用镜像标签时,如果镜像注册中心更改了该标签所代表的代码,你可能会遇到同时运行旧代码和新代码的 Pod 混合情况。镜像摘要唯一标识镜像的特定版本,因此 Kubernetes 每次使用指定的镜像名称和摘要启动容器时都会运行相同的代码。通过摘要指定镜像会固定你运行的代码,这样注册中心的变化就不会导致版本混合。

有一些第三方准入控制器会在 Pod(和 PodTemplates)创建时对其进行修改,使得运行中的工作负载是基于镜像摘要而不是标签来定义的。如果你想确保整个工作负载运行相同的代码,无论注册中心发生什么标签更改,这可能很有用。

默认镜像拉取策略

当你(或控制器)向 API 服务器提交新的 Pod 时,如果满足特定条件,集群将设置 imagePullPolicy 字段

  • 如果你省略 imagePullPolicy 字段并指定容器镜像的摘要,则 imagePullPolicy 将自动设置为 IfNotPresent
  • 如果你省略 imagePullPolicy 字段,并且容器镜像的标签是 :latest,则 imagePullPolicy 将自动设置为 Always
  • 如果你省略 imagePullPolicy 字段,并且你未指定容器镜像的标签,则 imagePullPolicy 将自动设置为 Always
  • 如果你省略 imagePullPolicy 字段,并且你指定了一个不是 :latest 的容器镜像标签,则 imagePullPolicy 将自动设置为 IfNotPresent

必需的镜像拉取

如果你想始终强制拉取,可以执行以下操作之一

  • 将容器的 imagePullPolicy 设置为 Always
  • 省略 imagePullPolicy 并使用 :latest 作为要使用的镜像标签;当你提交 Pod 时,Kubernetes 会将策略设置为 Always
  • 省略 imagePullPolicy 和要使用的镜像标签;当你提交 Pod 时,Kubernetes 会将策略设置为 Always
  • 启用 AlwaysPullImages 准入控制器。

ImagePullBackOff

当 kubelet 使用容器运行时开始为 Pod 创建容器时,容器可能由于 ImagePullBackOff 而处于 Waiting 状态。

状态 ImagePullBackOff 意味着容器无法启动,因为 Kubernetes 无法拉取容器镜像(原因可能是镜像名称无效,或者从私有注册中心拉取但没有 imagePullSecret)。BackOff 部分表示 Kubernetes 将继续尝试拉取镜像,并以逐渐增加的退避延迟。

Kubernetes 会增加每次尝试之间的延迟,直到达到编译的限制,即 300 秒(5 分钟)。

按运行时类拉取镜像

特性状态: Kubernetes v1.29 [alpha] (默认禁用)
Kubernetes 包含一个 alpha 支持,用于根据 Pod 的 RuntimeClass 执行镜像拉取。

如果启用 RuntimeClassInImageCriApi 特性门控,kubelet 将通过镜像名称和运行时处理器组成的元组(而不是仅仅镜像名称或摘要)引用容器镜像。你的容器运行时可以根据选定的运行时处理器调整其行为。基于运行时类拉取镜像对于基于虚拟机的容器(例如 Windows Hyper-V 容器)很有用。

串行和并行镜像拉取

默认情况下,kubelet 串行拉取镜像。换句话说,kubelet 一次只向镜像服务发送一个镜像拉取请求。其他镜像拉取请求必须等到正在处理的请求完成。

节点独立做出镜像拉取决策。即使你使用串行镜像拉取,两个不同的节点也可以并行拉取相同的镜像。

如果你想启用并行镜像拉取,可以在 kubelet 配置中将 serializeImagePulls 字段设置为 false。将 serializeImagePulls 设置为 false 后,镜像拉取请求将立即发送到镜像服务,并且多个镜像将同时拉取。

启用并行镜像拉取时,请确保容器运行时的镜像服务能够处理并行镜像拉取。

kubelet 永远不会为单个 Pod 并行拉取多个镜像。例如,如果你的 Pod 包含一个 Init 容器和一个应用容器,这两个容器的镜像拉取将不会并行化。但是,如果你有两个使用不同镜像的 Pod,并且启用了并行镜像拉取功能,kubelet 将会为这两个不同的 Pod 并行拉取镜像。

最大并行镜像拉取

特性状态: Kubernetes v1.32 [beta]

serializeImagePulls 设置为 false 时,kubelet 默认对同时拉取的最大镜像数量不设限制。如果你想限制并行镜像拉取的数量,可以在 kubelet 配置中设置 maxParallelImagePulls 字段。将 maxParallelImagePulls 设置为 n,则最多只能同时拉取 n 个镜像,任何超出 n 的镜像拉取都必须等待至少一个正在进行的镜像拉取完成。

当启用并行镜像拉取时,限制并行镜像拉取的数量可以防止镜像拉取消耗过多的网络带宽或磁盘 I/O。

你可以将 maxParallelImagePulls 设置为一个大于或等于 1 的正数。如果你将 maxParallelImagePulls 设置为大于或等于 2,则必须将 serializeImagePulls 设置为 false。kubelet 将因 maxParallelImagePulls 设置无效而无法启动。

带镜像索引的多架构镜像

除了提供二进制镜像外,容器注册中心还可以提供容器镜像索引。镜像索引可以指向多个镜像清单,用于容器的特定架构版本。其思想是你可以为镜像提供一个名称(例如:pauseexample/mycontainerkube-apiserver),并允许不同的系统为它们正在使用的机器架构获取正确的二进制镜像。

Kubernetes 项目通常会为其发布的容器镜像创建名称中包含后缀 -$(ARCH) 的镜像。为了向后兼容,会生成带有后缀的旧镜像。例如,名为 pause 的镜像将是一个包含所有受支持架构的清单的多架构镜像,而 pause-amd64 将是用于旧配置或硬编码镜像名称包含后缀的 YAML 文件的向后兼容版本。

使用私有注册中心

私有注册中心可能需要身份验证才能从中发现和/或拉取镜像。凭据可以通过以下几种方式提供

  • 在定义 Pod 时指定 imagePullSecrets

    只有提供自己密钥的 Pod 才能访问私有注册中心。

  • 配置节点以对私有注册中心进行身份验证

    • 所有 Pod 都可以读取任何配置的私有注册中心。
    • 需要集群管理员进行节点配置。
  • 使用 kubelet 凭据提供程序 插件动态获取私有注册中心的凭据

    kubelet 可以配置为使用凭据提供程序 exec 插件来获取相应私有注册中心的凭据。

  • 预拉取镜像

    • 所有 Pod 都可以使用节点上缓存的任何镜像。
    • 需要对所有节点进行 root 访问才能设置。
  • 供应商特定或本地扩展

    如果你正在使用自定义节点配置,你(或你的云提供商)可以实现自己的机制来对节点进行容器注册中心身份验证。

这些选项将在下面详细解释。

在 Pod 上指定 imagePullSecrets

Kubernetes 支持在 Pod 上指定容器镜像注册中心密钥。所有 imagePullSecrets 都必须是与 Pod 位于同一个命名空间中的 Secret。这些 Secret 必须是 kubernetes.io/dockercfgkubernetes.io/dockerconfigjson 类型。

配置节点以对私有注册中心进行身份验证

设置凭据的具体说明取决于你选择使用的容器运行时和注册中心。你应该参考你的解决方案文档以获取最准确的信息。

有关配置私有容器镜像注册中心的示例,请参阅从私有注册中心拉取镜像任务。该示例使用 Docker Hub 中的私有注册中心。

用于经过身份验证的镜像拉取的 Kubelet 凭证提供者

你可以配置 kubelet 以调用插件二进制文件,从而动态获取容器镜像的注册中心凭证。这是获取私有注册中心凭证最健壮和最通用的方法,但同时也需要 kubelet 级别的配置才能启用。

此技术对于运行需要私有注册中心中托管的容器镜像的静态 Pod 尤其有用。在静态 Pod 的规范中无法使用ServiceAccountSecret 提供私有注册中心凭证,因为它的规范中不能引用其他 API 资源。

有关更多详细信息,请参阅配置 kubelet 镜像凭证提供者

config.json 的解释

config.json 的解释在原始 Docker 实现和 Kubernetes 解释之间有所不同。在 Docker 中,auths 键只能指定根 URL,而 Kubernetes 允许全局 URL 以及前缀匹配的路径。唯一的限制是全局模式(*)必须为每个子域包含点(.)。匹配的子域数量必须等于全局模式(*.)的数量,例如

  • *.kubernetes.io 匹配 kubernetes.io,但会匹配 abc.kubernetes.io
  • *.*.kubernetes.io 匹配 abc.kubernetes.io,但会匹配 abc.def.kubernetes.io
  • prefix.*.io 将匹配 prefix.kubernetes.io
  • *-good.kubernetes.io 将匹配 prefix-good.kubernetes.io

这意味着这样的 config.json 是有效的

{
    "auths": {
        "my-registry.example/images": { "auth": "…" },
        "*.my-registry.example/images": { "auth": "…" }
    }
}

镜像拉取操作会将凭据传递给 CRI 容器运行时,以匹配每个有效模式。例如,以下容器镜像名称将成功匹配

  • my-registry.example/images
  • my-registry.example/images/my-image
  • my-registry.example/images/another-image
  • sub.my-registry.example/images/my-image

但是,这些容器镜像名称将 匹配

  • a.sub.my-registry.example/images/my-image
  • a.b.sub.my-registry.example/images/my-image

kubelet 会为每个找到的凭据顺序执行镜像拉取。这意味着 config.json 中针对不同路径的多个条目也是可能的

{
    "auths": {
        "my-registry.example/images": {
            "auth": "…"
        },
        "my-registry.example/images/subpath": {
            "auth": "…"
        }
    }
}

如果现在容器指定要拉取的镜像为 my-registry.example/images/subpath/my-image,那么如果其中一个认证源失败,kubelet 将尝试使用这两个认证源下载它。

预拉取镜像

默认情况下,kubelet 尝试从指定的注册中心拉取每个镜像。但是,如果容器的 imagePullPolicy 属性设置为 IfNotPresentNever,则使用本地镜像(分别为优先或独占)。

如果你想依赖预拉取镜像作为注册中心身份验证的替代方案,你必须确保集群中的所有节点都具有相同的预拉取镜像。

这可以用于预加载某些镜像以提高速度,或者作为对私有注册中心进行身份验证的替代方案。

与使用kubelet 凭据提供程序类似,预拉取镜像也适用于启动依赖于私有注册中心中托管镜像的静态 Pod

确保镜像拉取凭证验证

特性状态: `Kubernetes v1.33 [alpha]`(默认启用:false)

如果集群的 KubeletEnsureSecretPulledImages 特性门控已启用,Kubernetes 将验证每个需要凭证才能拉取的镜像的镜像凭证,即使该镜像已存在于节点上。此验证可确保 Pod 请求中未能使用所提供的凭证成功拉取的镜像必须从注册中心重新拉取。此外,如果镜像在本地可用,重新使用相同凭证并已成功拉取镜像的请求将无需从注册中心重新拉取,而是通过本地验证(不访问注册中心)。这由 Kubelet 配置中的 imagePullCredentialsVerificationPolicy 字段控制。

此配置控制当镜像已存在于节点上时,何时必须验证镜像拉取凭证

  • NeverVerify:模拟禁用此功能门控的行为。如果镜像在本地存在,则不验证镜像拉取凭证。
  • NeverVerifyPreloadedImages:不验证在 kubelet 外部拉取的镜像,但所有其他镜像都将验证其凭证。这是默认行为。
  • NeverVerifyAllowListedImages:不验证在 kubelet 外部拉取并在 kubelet 配置中指定的 preloadedImagesVerificationAllowlist 中提到的镜像。
  • AlwaysVerify:所有镜像在使用前都将验证其凭证。

此验证适用于预拉取镜像、使用节点范围 Secrets 拉取的镜像以及使用 Pod 级别 Secrets 拉取的镜像。

创建带 Docker 配置的 Secret

你需要知道用于向注册中心进行身份验证的用户名、注册中心密码和客户端电子邮件地址,以及其主机名。运行以下命令,将占位符替换为相应的值

kubectl create secret docker-registry <name> \
  --docker-server=<docker-registry-server> \
  --docker-username=<docker-user> \
  --docker-password=<docker-password> \
  --docker-email=<docker-email>

如果你已经有 Docker 凭证文件,那么你可以将其作为 Kubernetes Secret 导入,而不是使用上述命令。基于现有 Docker 凭证创建 Secret 解释了如何进行设置。

如果你使用多个私有容器注册中心,这尤其有用,因为 kubectl create secret docker-registry 创建的 Secret 仅适用于单个私有注册中心。

在 Pod 上引用 imagePullSecrets

现在,你可以通过在 Pod 定义中添加 imagePullSecrets 部分来创建引用该 Secret 的 Pod。imagePullSecrets 数组中的每个项只能引用同一个命名空间中的一个 Secret。

例如

cat <<EOF > pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: foo
  namespace: awesomeapps
spec:
  containers:
    - name: foo
      image: janedoe/awesomeapp:v1
  imagePullSecrets:
    - name: myregistrykey
EOF

cat <<EOF >> ./kustomization.yaml
resources:
- pod.yaml
EOF

对于每个使用私有注册中心的 Pod,都需要执行此操作。

但是,你可以通过在 ServiceAccount 资源中指定 imagePullSecrets 部分来自动执行此过程。有关详细说明,请参阅向 ServiceAccount 添加 ImagePullSecrets

你可以将其与每个节点的 .docker/config.json 结合使用。凭据将合并。

用例

有许多用于配置私有注册中心的解决方案。以下是一些常见的用例和建议的解决方案。

  1. 集群仅运行非专有(例如开源)镜像。无需隐藏镜像。
    • 使用公共注册中心的公共镜像
      • 无需配置。
      • 一些云提供商会自动缓存或镜像公共镜像,这提高了可用性并减少了拉取镜像的时间。
  2. 集群运行一些专有镜像,这些镜像应向公司外部人员隐藏,但对所有集群用户可见。
    • 使用托管的私有注册中心
      • 可能需要在需要访问私有注册中心的节点上进行手动配置。
    • 或者,在防火墙后运行一个具有开放读取权限的内部私有注册中心。
      • 无需 Kubernetes 配置。
    • 使用控制镜像访问的托管容器镜像注册中心服务
      • 与手动节点配置相比,它在节点自动扩缩方面表现更好。
    • 或者,在不方便更改节点配置的集群上,使用 imagePullSecrets
  3. 带有专有镜像的集群,其中少数需要更严格的访问控制。
    • 确保AlwaysPullImages 准入控制器处于活动状态。否则,所有 Pod 都可能访问所有镜像。
    • 将敏感数据移动到 Secret 资源中,而不是将其打包到镜像中。
  4. 一个多租户集群,每个租户都需要自己的私有注册中心。
    • 确保AlwaysPullImages 准入控制器处于活动状态。否则,所有租户的所有 Pod 都可能访问所有镜像。
    • 运行一个需要授权的私有注册中心。
    • 为每个租户生成注册中心凭据,存储到 Secret 中,并将 Secret 传播到每个租户命名空间。
    • 然后租户将该 Secret 添加到每个命名空间的 imagePullSecrets 中。

如果你需要访问多个注册中心,可以为每个注册中心创建一个 Secret。

旧版内置 kubelet 凭证提供者

在较旧版本的 Kubernetes 中,kubelet 与云提供商凭据直接集成。这提供了动态获取镜像注册中心凭据的能力。

kubelet 凭证提供程序集成有三个内置实现:ACR (Azure Container Registry)、ECR (Elastic Container Registry) 和 GCR (Google Container Registry)。

从 Kubernetes 1.26 版本开始,旧机制已删除,因此你需要

  • 在每个节点上配置 kubelet 镜像凭证提供者;或者
  • 使用 imagePullSecrets 和至少一个 Secret 指定镜像拉取凭证。

下一步

上次修改时间:2025 年 5 月 20 日太平洋标准时间上午 11:03:更新 content/en/docs/concepts/containers/images.md (32e235b281)