本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
Kubernetes 1.31:基于 OCI 制品的只读卷(Alpha)
Kubernetes 社区正在朝着未来满足更多人工智能(AI)和机器学习(ML)用例的方向发展。虽然该项目过去一直被设计用于满足微服务架构,但现在是时候倾听最终用户的声音,并引入更专注于 AI/ML 的特性了。
其中一项需求是直接将兼容开放容器倡议(OCI)的镜像和制品(称为 OCI 对象)作为原生卷来源来支持。这允许用户专注于 OCI 标准,并使他们能够使用 OCI 镜像库来存储和分发任何内容。这样的功能为 Kubernetes 项目提供了机会,使其能够发展到超越运行特定镜像的用例中。
鉴于此,Kubernetes 社区自豪地推出在 v1.31 中引入的一个新的 Alpha 特性:镜像卷来源(Image Volume Source)(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 邮件列表提供反馈。
详细示例
要使其功能正常,需要在 API Server 以及 kubelet 上启用 Kubernetes Alpha 特性门控 ImageVolume
。如果已启用,并且容器运行时支持该特性(例如 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 使用 image.reference
为 quay.io/crio/artifact:v1
声明了一个新卷,该引用指向一个包含两个文件的 OCI 对象。pullPolicy
的行为与容器镜像相同,并允许以下值:
Always
:kubelet 总是尝试拉取该引用,如果拉取失败,容器创建将失败。Never
:kubelet 从不拉取该引用,只使用本地镜像或制品。如果该引用不存在,容器创建将失败。IfNotPresent
:如果该引用在磁盘上尚不存在,kubelet 就会拉取。如果该引用不存在且拉取失败,容器创建将失败。
volumeMounts
字段指示名为 test
的容器应将该卷挂载到路径 /volume
下。
现在,如果你创建这个 Pod:
kubectl apply -f pod.yaml
然后进入它的 shell:
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 的 reason 和 message 中报告。
- 拉取 Secret 将以与容器镜像相同的方式组装,即查找节点凭据、服务账号的 image pull secret 以及 Pod 规约中的 image pull secret。
- OCI 对象通过合并清单层的方式挂载到单个目录中,这与容器镜像的处理方式相同。
- 卷以只读(
ro
)和非可执行文件(noexec
)的方式挂载。 - 不支持容器的子路径挂载(
spec.containers[*].volumeMounts.subpath
)。 - 字段
spec.securityContext.fsGroupChangePolicy
对此卷类型没有影响。 - 如果启用,该功能也将与
AlwaysPullImages
准入插件一起工作。
感谢你阅读完这篇博客文章!SIG Node 很自豪也很高兴能将此功能作为 Kubernetes v1.31 的一部分交付。
作为这篇博客文章的作者,我想特别感谢所有参与其中的个人!你们都太棒了,让我们继续努力!