Kubernetes 1.31:基于 OCI 制品的只读卷(alpha)

Kubernetes 社区正朝着未来满足更多人工智能 (AI) 和机器学习 (ML) 用例的方向发展。虽然该项目过去被设计用来满足微服务架构,但现在是时候听取最终用户的意见,并引入更侧重于 AI/ML 的功能了。

其中一个要求是直接支持与 开放容器倡议 (OCI) 兼容的镜像和工件(称为 OCI 对象)作为原生卷源。这允许用户专注于 OCI 标准,并使他们能够使用 OCI 注册表存储和分发任何内容。这样的功能使 Kubernetes 项目有机会发展到超出运行特定镜像的用例。

鉴于此,Kubernetes 社区很自豪地推出在 v1.31 中引入的新 alpha 功能:镜像卷源 (KEP-4639)。此功能允许用户在 Pod 中指定镜像引用作为卷,同时将其重用为容器内的卷挂载点。


kind: Pod
spec:
  containers:
    - …
      volumeMounts:
        - name: my-volume
          mountPath: /path/to/directory
  volumes:
    - name: my-volume
      image:
        reference: my-image:tag

上面的示例将导致将 my-image:tag 挂载到 Pod 容器中的 /path/to/directory

用例

此增强的目标是在 kubelet 中尽可能接近现有的容器镜像实现,同时引入新的 API 接口以允许更广泛的用例。

例如,用户可以在 Pod 中的多个容器之间共享一个配置文件,而无需将该文件包含在主镜像中,这样他们就可以最大限度地降低安全风险和整体镜像大小。他们还可以使用 OCI 镜像打包和分发二进制工件,并将其直接挂载到 Kubernetes Pod 中,这样他们就可以简化他们的 CI/CD 管道作为示例。

数据科学家、MLOps 工程师或 AI 开发人员可以将大型语言模型权重或机器学习模型权重与模型服务器一起挂载在 Pod 中,这样他们就可以高效地提供这些权重,而无需将其包含在模型服务器容器镜像中。他们可以将这些权重打包在 OCI 对象中,以利用 OCI 分发并确保高效的模型部署。这允许他们将模型规范/内容与处理它们的可执行文件分开。

另一个用例是安全工程师可以使用公开的恶意软件扫描器镜像,并挂载私有(商业)恶意软件签名的卷,这样他们就可以加载这些签名,而无需构建自己的组合镜像(这可能不被公开镜像的版权所允许)。这些文件与扫描器软件的操作系统或版本无关。

但从长远来看,作为该项目的最终用户,需要为新功能概述更多重要的用例。SIG Node 很高兴检索任何反馈或建议,以便进一步增强功能以允许更高级的用例。请随时通过使用 Kubernetes Slack (#sig-node) 频道或 SIG Node 邮件列表提供反馈。

详细示例

Kubernetes alpha 功能门 ImageVolume 需要在 API 服务器以及 kubelet 上启用,使其能够正常工作。如果满足这种情况,并且 容器运行时 支持该功能(例如 CRI-O ≥ v1.31),则可以创建如下所示的 pod.yaml 示例

apiVersion: v1
kind: Pod
metadata:
  name: pod
spec:
  containers:
    - name: test
      image: registry.k8s.io/e2e-test-images/echoserver:2.3
      volumeMounts:
        - name: volume
          mountPath: /volume
  volumes:
    - name: volume
      image:
        reference: quay.io/crio/artifact:v1
        pullPolicy: IfNotPresent

该 Pod 使用 quay.io/crio/artifact:v1image.reference 声明了一个新卷,该引用指向包含两个文件的 OCI 对象。pullPolicy 的行为方式与容器镜像相同,并允许以下值

  • Always:kubelet 始终尝试拉取引用,如果拉取失败,则容器创建将失败。
  • Never:kubelet 永远不会拉取引用,只会使用本地镜像或工件。如果引用不存在,则容器创建将失败。
  • IfNotPresent:如果磁盘上尚未存在引用,则 kubelet 会拉取该引用。如果引用不存在且拉取失败,则容器创建将失败。

volumeMounts 字段指示名称为 test 的容器应将卷挂载在路径 /volume 下。

如果您现在创建 Pod

kubectl apply -f pod.yaml

并 exec 进入它

kubectl exec -it pod -- sh

然后您可以调查已挂载的内容

/ # ls /volume
dir   file
/ # cat /volume/file
2
/ # ls /volume/dir
file
/ # cat /volume/dir/file
1

您成功地使用 Kubernetes 消费了一个 OCI 工件!

容器运行时会拉取镜像(或工件),将其挂载到容器,并使其最终可直接使用。该实现中有很多细节,这些细节与 kubelet 的现有镜像拉取行为密切相关。例如

  • 如果提供了 :latest 标签作为 reference,则如果未设置,则 pullPolicy 将默认为 Always,而在任何其他情况下,它将默认为 IfNotPresent
  • 如果 Pod 被删除并重新创建,则会重新解析该卷,这意味着新的远程内容将在 Pod 重新创建时可用。在 Pod 启动期间未能解析或拉取镜像会阻止容器启动,并可能增加显著的延迟。失败将使用正常的卷退避重试,并将在 Pod 原因和消息中报告。
  • 拉取密钥将通过查找节点凭据、服务帐户镜像拉取密钥和 Pod 规范镜像拉取密钥,以与容器镜像相同的方式进行组装。
  • OCI 对象通过与容器镜像相同的方式合并清单层来挂载在单个目录中。
  • 该卷以只读 (ro) 和不可执行文件 (noexec) 的形式挂载。
  • 不支持容器的子路径挂载 (spec.containers[*].volumeMounts.subpath)。
  • 字段 spec.securityContext.fsGroupChangePolicy 对此卷类型无效。
  • 如果启用,该功能还将与 AlwaysPullImages 准入插件一起工作。

感谢您阅读到本博客文章的末尾!SIG Node 很自豪也很高兴能将此功能作为 Kubernetes v1.31 的一部分交付。

作为这篇博文的作者,我想特别感谢参与其中的所有人!你们都很棒,让我们继续努力!

进一步阅读