本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。

Kubernetes 1.30:只读卷挂载终于可以真正地只读了

只读卷挂载从一开始就是 Kubernetes 的一个特性。但令人惊讶的是,在 Linux 上的某些条件下,只读挂载并非完全只读。从 v1.30 版本开始,通过对**递归只读挂载**的 Alpha 支持,它们可以被设置为完全只读。

默认情况下,只读卷挂载并非真正的只读

卷挂载可能比看起来要复杂得多。

你可能期望下面的清单会让容器中 `/mnt` 下的所有内容都变为只读。

---
apiVersion: v1
kind: Pod
spec:
  volumes:
    - name: mnt
      hostPath:
        path: /mnt
  containers:
    - volumeMounts:
        - name: mnt
          mountPath: /mnt
          readOnly: true

然而,`/mnt` 下的任何子挂载点可能仍然是可写的!例如,假设主机上的 `/mnt/my-nfs-server` 是可写的。在容器内部,对 `/mnt/*` 的写入会被拒绝,但对 `/mnt/my-nfs-server/*` 的写入仍然是可行的。

新的挂载选项:recursiveReadOnly

Kubernetes 1.30 添加了一个新的挂载选项 `recursiveReadOnly`,以便将子挂载点递归地设置为只读。

该选项可以按如下方式启用

---
apiVersion: v1
kind: Pod
spec:
  volumes:
    - name: mnt
      hostPath:
        path: /mnt
  containers:
    - volumeMounts:
        - name: mnt
          mountPath: /mnt
          readOnly: true
          # NEW
          # Possible values are `Enabled`, `IfPossible`, and `Disabled`.
          # Needs to be specified in conjunction with `readOnly: true`.
          recursiveReadOnly: Enabled

这是通过在 Linux 内核 v5.12 中添加的 mount_setattr(2) 系统调用,并使用 `AT_RECURSIVE` 标志来应用 `MOUNT_ATTR_RDONLY` 属性来实现的。

为了向后兼容,`recursiveReadOnly` 字段并不是 `readOnly` 的替代品,而是**与**它一起使用。要获得一个正确的递归只读挂载,你必须同时设置这两个字段。

功能可用性

要启用 `recursiveReadOnly` 挂载,必须使用以下组件

  • Kubernetes:v1.30 或更高版本,并启用 `RecursiveReadOnlyMounts` 特性门控。自 v1.30 起,该门控被标记为 Alpha 阶段。

  • CRI 运行时

    • containerd:v2.0 或更高版本
  • OCI 运行时

    • runc: v1.1 或更高版本
    • crun: v1.8.6 或更高版本
  • Linux 内核:v5.12 或更高版本

接下来是什么?

Kubernetes SIG Node 希望并期望该功能在未来的 Kubernetes 版本中能晋升为 Beta 阶段并最终正式发布(GA),这样用户就不再需要手动启用该特性门控了。

为了向后兼容,`recursiveReadOnly` 的默认值将仍然是 `Disabled`。

我如何了解更多信息?

有关 `recursiveReadOnly` 挂载的更多详情,请查阅文档

如何参与?

此功能由 SIG Node 社区推动。欢迎加入我们,与社区建立联系,分享你对上述功能及其他方面的想法和反馈。我们期待你的回音!