|
| 1 | +--- |
| 2 | +layout: blog |
| 3 | +title: "Kubernetes 1.31:基于 OCI 工件的只读卷 (Alpha)" |
| 4 | +date: 2024-08-16 |
| 5 | +slug: kubernetes-1-31-image-volume-source |
| 6 | +author: Sascha Grunert |
| 7 | +translator: > |
| 8 | + [Michael Yao](https://github.com/windsonsea) (DaoCloud) |
| 9 | +--- |
| 10 | +<!-- |
| 11 | +layout: blog |
| 12 | +title: "Kubernetes 1.31: Read Only Volumes Based On OCI Artifacts (alpha)" |
| 13 | +date: 2024-08-16 |
| 14 | +slug: kubernetes-1-31-image-volume-source |
| 15 | +author: Sascha Grunert |
| 16 | +--> |
| 17 | + |
| 18 | +<!-- |
| 19 | +The Kubernetes community is moving towards fulfilling more Artificial |
| 20 | +Intelligence (AI) and Machine Learning (ML) use cases in the future. While the |
| 21 | +project has been designed to fulfill microservice architectures in the past, |
| 22 | +it’s now time to listen to the end users and introduce features which have a |
| 23 | +stronger focus on AI/ML. |
| 24 | +--> |
| 25 | +Kubernetes 社区正朝着在未来满足更多人工智能(AI)和机器学习(ML)使用场景的方向发展。 |
| 26 | +虽然此项目在过去设计为满足微服务架构,但现在是时候听听最终用户的声音并引入更侧重于 AI/ML 的特性了。 |
| 27 | + |
| 28 | +<!-- |
| 29 | +One of these requirements is to support [Open Container Initiative (OCI)](https://opencontainers.org) |
| 30 | +compatible images and artifacts (referred as OCI objects) directly as a native |
| 31 | +volume source. This allows users to focus on OCI standards as well as enables |
| 32 | +them to store and distribute any content using OCI registries. A feature like |
| 33 | +this gives the Kubernetes project a chance to grow into use cases which go |
| 34 | +beyond running particular images. |
| 35 | +--> |
| 36 | +其中一项需求是直接支持与[开放容器倡议(OCI)](https://opencontainers.org) |
| 37 | +兼容的镜像和工件(称为 OCI 对象)作为原生卷源。 |
| 38 | +这使得用户能够专注于 OCI 标准,且能够使用 OCI 镜像仓库存储和分发任何内容。 |
| 39 | +与此类似的特性让 Kubernetes 项目有机会扩大其使用场景,不再局限于运行特定镜像。 |
| 40 | + |
| 41 | +<!-- |
| 42 | +Given that, the Kubernetes community is proud to present a new alpha feature |
| 43 | +introduced in v1.31: The Image Volume Source |
| 44 | +([KEP-4639](https://kep.k8s.io/4639)). This feature allows users to specify an |
| 45 | +image reference as volume in a pod while reusing it as volume mount within |
| 46 | +containers: |
| 47 | +--> |
| 48 | +在这一背景下,Kubernetes 社区自豪地展示在 v1.31 中引入的一项新的 Alpha 特性: |
| 49 | +镜像卷源([KEP-4639](https://kep.k8s.io/4639))。 |
| 50 | +此特性允许用户在 Pod 中指定一个镜像引用作为卷,并在容器内将其作为卷挂载进行复用: |
| 51 | + |
| 52 | +```yaml |
| 53 | +… |
| 54 | +kind: Pod |
| 55 | +spec: |
| 56 | + containers: |
| 57 | + - … |
| 58 | + volumeMounts: |
| 59 | + - name: my-volume |
| 60 | + mountPath: /path/to/directory |
| 61 | + volumes: |
| 62 | + - name: my-volume |
| 63 | + image: |
| 64 | + reference: my-image:tag |
| 65 | +``` |
| 66 | +
|
| 67 | +<!-- |
| 68 | +The above example would result in mounting `my-image:tag` to |
| 69 | +`/path/to/directory` in the pod’s container. |
| 70 | +--> |
| 71 | +上述示例的结果是将 `my-image:tag` 挂载到 Pod 的容器中的 `/path/to/directory`。 |
| 72 | + |
| 73 | +<!-- |
| 74 | +## Use cases |
| 75 | + |
| 76 | +The goal of this enhancement is to stick as close as possible to the existing |
| 77 | +[container image](/docs/concepts/containers/images/) implementation within the |
| 78 | +kubelet, while introducing a new API surface to allow more extended use cases. |
| 79 | +--> |
| 80 | +## 使用场景 |
| 81 | + |
| 82 | +此增强特性的目标是在尽可能贴近 kubelet 中现有的[容器镜像](/zh-cn/docs/concepts/containers/images/)实现的同时, |
| 83 | +引入新的 API 接口以支持更广泛的使用场景。 |
| 84 | + |
| 85 | +<!-- |
| 86 | +For example, users could share a configuration file among multiple containers in |
| 87 | +a pod without including the file in the main image, so that they can minimize |
| 88 | +security risks and the overall image size. They can also package and distribute |
| 89 | +binary artifacts using OCI images and mount them directly into Kubernetes pods, |
| 90 | +so that they can streamline their CI/CD pipeline as an example. |
| 91 | +--> |
| 92 | +例如,用户可以在 Pod 中的多个容器之间共享一个配置文件,而无需将此文件包含在主镜像中, |
| 93 | +这样用户就可以将安全风险最小化和并缩减整体镜像大小。用户还可以使用 OCI 镜像打包和分发二进制工件, |
| 94 | +并直接将它们挂载到 Kubernetes Pod 中,例如用户这样就可以简化其 CI/CD 流水线。 |
| 95 | + |
| 96 | +<!-- |
| 97 | +Data scientists, MLOps engineers, or AI developers, can mount large language |
| 98 | +model weights or machine learning model weights in a pod alongside a |
| 99 | +model-server, so that they can efficiently serve them without including them in |
| 100 | +the model-server container image. They can package these in an OCI object to |
| 101 | +take advantage of OCI distribution and ensure efficient model deployment. This |
| 102 | +allows them to separate the model specifications/content from the executables |
| 103 | +that process them. |
| 104 | +--> |
| 105 | +数据科学家、MLOps 工程师或 AI 开发者可以与模型服务器一起在 Pod 中挂载大语言模型权重或机器学习模型权重数据, |
| 106 | +从而可以更高效地提供服务,且无需将这些模型包含在模型服务器容器镜像中。 |
| 107 | +他们可以将这些模型打包在 OCI 对象中,以利用 OCI 分发机制,还可以确保高效的模型部署。 |
| 108 | +这一新特性允许他们将模型规约/内容与处理它们的可执行文件分开。 |
| 109 | + |
| 110 | +<!-- |
| 111 | +Another use case is that security engineers can use a public image for a malware |
| 112 | +scanner and mount in a volume of private (commercial) malware signatures, so |
| 113 | +that they can load those signatures without baking their own combined image |
| 114 | +(which might not be allowed by the copyright on the public image). Those files |
| 115 | +work regardless of the OS or version of the scanner software. |
| 116 | +--> |
| 117 | +另一个使用场景是安全工程师可以使用公共镜像作为恶意软件扫描器,并将私有的(商业的)恶意软件签名挂载到卷中, |
| 118 | +这样他们就可以加载这些签名且无需制作自己的组合镜像(公共镜像的版权要求可能不允许这样做)。 |
| 119 | +签名数据文件与操作系统或扫描器软件版本无关,总是可以被使用。 |
| 120 | + |
| 121 | +<!-- |
| 122 | +But in the long term it will be up to **you** as an end user of this project to |
| 123 | +outline further important use cases for the new feature. |
| 124 | +[SIG Node](https://github.com/kubernetes/community/blob/54a67f5/sig-node/README.md) |
| 125 | +is happy to retrieve any feedback or suggestions for further enhancements to |
| 126 | +allow more advanced usage scenarios. Feel free to provide feedback by either |
| 127 | +using the [Kubernetes Slack (#sig-node)](https://kubernetes.slack.com/messages/sig-node) |
| 128 | +channel or the [SIG Node mailinglist](https://groups.google.com/g/kubernetes-sig-node). |
| 129 | +--> |
| 130 | +但就长期而言,作为此项目的最终用户的你要负责为这一新特性的其他重要使用场景给出规划。 |
| 131 | +[SIG Node](https://github.com/kubernetes/community/blob/54a67f5/sig-node/README.md) |
| 132 | +乐于接收与进一步增强此特性以适应更高级的使用场景有关的所有反馈或建议。你可以通过使用 |
| 133 | +[Kubernetes Slack(#sig-node)](https://kubernetes.slack.com/messages/sig-node) |
| 134 | +频道或 [SIG Node 邮件列表](https://groups.google.com/g/kubernetes-sig-node)提供反馈。 |
| 135 | + |
| 136 | +<!-- |
| 137 | +## Detailed example {#example} |
| 138 | + |
| 139 | +The Kubernetes alpha feature gate [`ImageVolume`](/docs/reference/command-line-tools-reference/feature-gates) |
| 140 | +needs to be enabled on the [API Server](/docs/reference/command-line-tools-reference/kube-apiserver) |
| 141 | +as well as the [kubelet](/docs/reference/command-line-tools-reference/kubelet) |
| 142 | +to make it functional. If that’s the case and the [container runtime](/docs/setup/production-environment/container-runtimes) |
| 143 | +has support for the feature (like CRI-O ≥ v1.31), then an example `pod.yaml` |
| 144 | +like this can be created: |
| 145 | +--> |
| 146 | +## 详细示例 {#example} |
| 147 | + |
| 148 | +你需要在 [API 服务器](/zh-cn/docs/reference/command-line-tools-reference/kube-apiserver)以及 |
| 149 | +[kubelet](/zh-cn/docs/reference/command-line-tools-reference/kubelet) 上启用 |
| 150 | +Kubernetes Alpha 特性门控 [`ImageVolume`](/zh-cn/docs/reference/command-line-tools-reference/feature-gates), |
| 151 | +才能使其正常工作。如果启用了此特性, |
| 152 | +并且[容器运行时](/zh-cn/docs/setup/production-environment/container-runtimes)支持此特性 |
| 153 | +(如 CRI-O ≥ v1.31),那就可以创建这样一个示例 `pod.yaml`: |
| 154 | + |
| 155 | +```yaml |
| 156 | +apiVersion: v1 |
| 157 | +kind: Pod |
| 158 | +metadata: |
| 159 | + name: pod |
| 160 | +spec: |
| 161 | + containers: |
| 162 | + - name: test |
| 163 | + image: registry.k8s.io/e2e-test-images/echoserver:2.3 |
| 164 | + volumeMounts: |
| 165 | + - name: volume |
| 166 | + mountPath: /volume |
| 167 | + volumes: |
| 168 | + - name: volume |
| 169 | + image: |
| 170 | + reference: quay.io/crio/artifact:v1 |
| 171 | + pullPolicy: IfNotPresent |
| 172 | +``` |
| 173 | + |
| 174 | +<!-- |
| 175 | +The pod declares a new volume using the `image.reference` of |
| 176 | +`quay.io/crio/artifact:v1`, which refers to an OCI object containing two files. |
| 177 | +The `pullPolicy` behaves in the same way as for container images and allows the |
| 178 | +following values: |
| 179 | +--> |
| 180 | +此 Pod 使用值为 `quay.io/crio/artifact:v1` 的 `image.reference` 声明一个新卷, |
| 181 | +该字段值引用了一个包含两个文件的 OCI 对象。`pullPolicy` 的行为与容器镜像相同,允许以下值: |
| 182 | + |
| 183 | +<!-- |
| 184 | +- `Always`: the kubelet always attempts to pull the reference and the container |
| 185 | + creation will fail if the pull fails. |
| 186 | +- `Never`: the kubelet never pulls the reference and only uses a local image or |
| 187 | + artifact. The container creation will fail if the reference isn’t present. |
| 188 | +- `IfNotPresent`: the kubelet pulls if the reference isn’t already present on |
| 189 | + disk. The container creation will fail if the reference isn’t present and the |
| 190 | + pull fails. |
| 191 | +--> |
| 192 | +- `Always`:kubelet 总是尝试拉取引用,如果拉取失败,容器创建将失败。 |
| 193 | +- `Never`:kubelet 从不拉取引用,只使用本地镜像或工件。如果引用不存在,容器创建将失败。 |
| 194 | +- `IfNotPresent`:kubelet 会在引用已不在磁盘上时进行拉取。如果引用不存在且拉取失败,容器创建将失败。 |
| 195 | + |
| 196 | +<!-- |
| 197 | +The `volumeMounts` field is indicating that the container with the name `test` |
| 198 | +should mount the volume under the path `/volume`. |
| 199 | + |
| 200 | +If you now create the pod: |
| 201 | +--> |
| 202 | +`volumeMounts` 字段表示名为 `test` 的容器应将卷挂载到 `/volume` 路径下。 |
| 203 | + |
| 204 | +如果你现在创建 Pod: |
| 205 | + |
| 206 | +```shell |
| 207 | +kubectl apply -f pod.yaml |
| 208 | +``` |
| 209 | + |
| 210 | +<!-- |
| 211 | +And exec into it: |
| 212 | +--> |
| 213 | +然后通过 exec 进入此 Pod: |
| 214 | + |
| 215 | +```shell |
| 216 | +kubectl exec -it pod -- sh |
| 217 | +``` |
| 218 | + |
| 219 | +<!-- |
| 220 | +Then you’re able to investigate what has been mounted: |
| 221 | +--> |
| 222 | +那么你就能够查看已挂载的内容: |
| 223 | + |
| 224 | +```console |
| 225 | +/ # ls /volume |
| 226 | +dir file |
| 227 | +/ # cat /volume/file |
| 228 | +2 |
| 229 | +/ # ls /volume/dir |
| 230 | +file |
| 231 | +/ # cat /volume/dir/file |
| 232 | +1 |
| 233 | +``` |
| 234 | + |
| 235 | +<!-- |
| 236 | +**You managed to consume an OCI artifact using Kubernetes!** |
| 237 | + |
| 238 | +The container runtime pulls the image (or artifact), mounts it to the |
| 239 | +container and makes it finally available for direct usage. There are a bunch of |
| 240 | +details in the implementation, which closely align to the existing image pull |
| 241 | +behavior of the kubelet. For example: |
| 242 | +--> |
| 243 | +**你已经成功地使用 Kubernetes 访问了 OCI 工件!** |
| 244 | + |
| 245 | +容器运行时拉取镜像(或工件),将其挂载到容器中,并最终使其可被直接使用。 |
| 246 | +在实现中有很多细节,这些细节与 kubelet 现有的镜像拉取行为密切相关。例如: |
| 247 | + |
| 248 | +<!-- |
| 249 | +- If a `:latest` tag as `reference` is provided, then the `pullPolicy` will |
| 250 | + default to `Always`, while in any other case it will default to `IfNotPresent` |
| 251 | + if unset. |
| 252 | +- The volume gets re-resolved if the pod gets deleted and recreated, which means |
| 253 | + that new remote content will become available on pod recreation. A failure to |
| 254 | + resolve or pull the image during pod startup will block containers from |
| 255 | + starting and may add significant latency. Failures will be retried using |
| 256 | + normal volume backoff and will be reported on the pod reason and message. |
| 257 | +--> |
| 258 | +- 如果提供给 `reference` 的值包含 `:latest` 标签,`pullPolicy` 将默认为 `Always`, |
| 259 | + 而在任何其他情况下,`pullPolicy` 在未被设置的情况下都默认为 `IfNotPresent`。 |
| 260 | +- 如果 Pod 被删除并重新创建,卷将被重新解析,这意味着在 Pod 重新创建时将可以访问新的远端内容。 |
| 261 | + 如果在 Pod 启动期间未能解析或未能拉取镜像,将会容器启动会被阻止,并可能显著增加延迟。 |
| 262 | + 如果拉取镜像失败,将使用正常的卷回退机制进行重试,并将在 Pod 的原因和消息中报告出错原因。 |
| 263 | +<!-- |
| 264 | +- Pull secrets will be assembled in the same way as for the container image by |
| 265 | + looking up node credentials, service account image pull secrets, and pod spec |
| 266 | + image pull secrets. |
| 267 | +- The OCI object gets mounted in a single directory by merging the manifest |
| 268 | + layers in the same way as for container images. |
| 269 | +- The volume is mounted as read-only (`ro`) and non-executable files |
| 270 | + (`noexec`). |
| 271 | +--> |
| 272 | +- 拉取 Secret 的组装方式与容器镜像所用的方式相同,也是通过查找节点凭据、服务账户镜像拉取 Secret |
| 273 | + 和 Pod 规约中的镜像拉取 Secret 来完成。 |
| 274 | +- OCI 对象被挂载到单个目录中,清单层的合并方式与容器镜像相同。 |
| 275 | +- 卷以只读(`ro`)和非可执行文件(`noexec`)的方式被挂载。 |
| 276 | +<!-- |
| 277 | +- Sub-path mounts for containers are not supported |
| 278 | + (`spec.containers[*].volumeMounts.subpath`). |
| 279 | +- The field `spec.securityContext.fsGroupChangePolicy` has no effect on this |
| 280 | + volume type. |
| 281 | +- The feature will also work with the [`AlwaysPullImages` admission plugin](/docs/reference/access-authn-authz/admission-controllers/#alwayspullimages) |
| 282 | + if enabled. |
| 283 | +--> |
| 284 | +- 容器的子路径挂载不被支持(`spec.containers[*].volumeMounts.subpath`)。 |
| 285 | +- 字段 `spec.securityContext.fsGroupChangePolicy` 对这种卷类型没有影响。 |
| 286 | +- 如果已启用,此特性也将与 |
| 287 | + [`AlwaysPullImages` 准入插件](/zh-cn/docs/reference/access-authn-authz/admission-controllers/#alwayspullimages)一起工作。 |
| 288 | + |
| 289 | +<!-- |
| 290 | +Thank you for reading through the end of this blog post! SIG Node is proud and |
| 291 | +happy to deliver this feature as part of Kubernetes v1.31. |
| 292 | + |
| 293 | +As writer of this blog post, I would like to emphasize my special thanks to |
| 294 | +**all** involved individuals out there! You all rock, let’s keep on hacking! |
| 295 | +--> |
| 296 | +感谢你阅读到这篇博客文章的结尾!对于将此特性作为 Kubernetes v1.31 |
| 297 | +的一部分交付,SIG Node 感到很高兴也很自豪。 |
| 298 | + |
| 299 | +作为这篇博客的作者,我想特别感谢所有参与者!你们都很棒,让我们继续开发之旅! |
| 300 | + |
| 301 | +<!-- |
| 302 | +## Further reading |
| 303 | + |
| 304 | +- [Use an Image Volume With a Pod](/docs/tasks/configure-pod-container/image-volumes) |
| 305 | +- [`image` volume overview](/docs/concepts/storage/volumes/#image) |
| 306 | +--> |
| 307 | +## 进一步阅读 |
| 308 | + |
| 309 | +- [在 Pod 中使用镜像卷](/zh-cn/docs/tasks/configure-pod-container/image-volumes) |
| 310 | +- [`image` 卷概览](/zh-cn/docs/concepts/storage/volumes/#image) |
0 commit comments