投射卷

本文档描述 Kubernetes 中的投射卷(Projected Volumes)。 建议先熟悉概念。

介绍

一个 projected 卷可以将若干现有的卷源映射到同一个目录之上。

目前,以下类型的卷源可以被投射:

所有的卷源都要求处于 Pod 所在的同一个名字空间内。更多详细信息, 可参考一体化卷设计文档。

带有 Secret、DownwardAPI 和 ConfigMap 的配置示例

pods/storage/projected-secret-downwardapi-configmap.yaml投射卷 - 图1

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: volume-test
  5. spec:
  6. containers:
  7. - name: container-test
  8. image: busybox:1.28
  9. volumeMounts:
  10. - name: all-in-one
  11. mountPath: "/projected-volume"
  12. readOnly: true
  13. volumes:
  14. - name: all-in-one
  15. projected:
  16. sources:
  17. - secret:
  18. name: mysecret
  19. items:
  20. - key: username
  21. path: my-group/my-username
  22. - downwardAPI:
  23. items:
  24. - path: "labels"
  25. fieldRef:
  26. fieldPath: metadata.labels
  27. - path: "cpu_limit"
  28. resourceFieldRef:
  29. containerName: container-test
  30. resource: limits.cpu
  31. - configMap:
  32. name: myconfigmap
  33. items:
  34. - key: config
  35. path: my-group/my-config

带有非默认权限模式设置的 Secret 的配置示例

pods/storage/projected-secrets-nondefault-permission-mode.yaml投射卷 - 图2

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: volume-test
  5. spec:
  6. containers:
  7. - name: container-test
  8. image: busybox:1.28
  9. volumeMounts:
  10. - name: all-in-one
  11. mountPath: "/projected-volume"
  12. readOnly: true
  13. volumes:
  14. - name: all-in-one
  15. projected:
  16. sources:
  17. - secret:
  18. name: mysecret
  19. items:
  20. - key: username
  21. path: my-group/my-username
  22. - secret:
  23. name: mysecret2
  24. items:
  25. - key: password
  26. path: my-group/my-password
  27. mode: 511

每个被投射的卷源都列举在规约中的 sources 下面。参数几乎相同,只有两个例外:

  • 对于 Secret,secretName 字段被改为 name 以便于 ConfigMap 的命名一致;
  • defaultMode 只能在投射层级设置,不能在卷源层级设置。不过,正如上面所展示的, 你可以显式地为每个投射单独设置 mode 属性。

serviceAccountToken 投射卷

你可以将当前服务账号的令牌注入到 Pod 中特定路径下。例如:

pods/storage/projected-service-account-token.yaml投射卷 - 图3

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: sa-token-test
  5. spec:
  6. containers:
  7. - name: container-test
  8. image: busybox:1.28
  9. volumeMounts:
  10. - name: token-vol
  11. mountPath: "/service-account"
  12. readOnly: true
  13. serviceAccountName: default
  14. volumes:
  15. - name: token-vol
  16. projected:
  17. sources:
  18. - serviceAccountToken:
  19. audience: api
  20. expirationSeconds: 3600
  21. path: token

示例 Pod 中包含一个投射卷,其中包含注入的服务账号令牌。 此 Pod 中的容器可以使用该令牌访问 Kubernetes API 服务器, 使用 Pod 的 ServiceAccount 进行身份验证。audience 字段包含令牌所针对的受众。 收到令牌的主体必须使用令牌受众中所指定的某个标识符来标识自身,否则应该拒绝该令牌。 此字段是可选的,默认值为 API 服务器的标识。

字段 expirationSeconds 是服务账号令牌预期的生命期长度。默认值为 1 小时, 必须至少为 10 分钟(600 秒)。管理员也可以通过设置 API 服务器的命令行参数 --service-account-max-token-expiration 来为其设置最大值上限。 path 字段给出与投射卷挂载点之间的相对路径。

说明:

subPath 形式使用投射卷源的容器无法收到对应卷源的更新。

clusterTrustBundle 投射卷

特性状态: Kubernetes v1.29 [alpha]

说明:

要在 Kubernetes 1.30 中使用此特性,你必须通过 ClusterTrustBundle 特性门控--runtime-config=certificates.k8s.io/v1alpha1/clustertrustbundles=true kube-apiserver 标志启用对 ClusterTrustBundle 对象的支持,然后才能启用 ClusterTrustBundleProjection 特性门控。

clusterTrustBundle 投射卷源将一个或多个 ClusterTrustBundle 对象的内容作为一个自动更新的文件注入到容器文件系统中。

ClusterTrustBundle 可以通过名称签名者名称被选中。

要按名称选择,可以使用 name 字段指定单个 ClusterTrustBundle 对象。

要按签名者名称选择,可以使用 signerName 字段(也可选用 labelSelector 字段) 指定一组使用给定签名者名称的 ClusterTrustBundle 对象。 如果 labelSelector 不存在,则针对该签名者的所有 ClusterTrustBundles 将被选中。

kubelet 会对所选 ClusterTrustBundle 对象中的证书进行去重,规范化 PEM 表示(丢弃注释和头部), 重新排序证书,并将这些证书写入由 path 指定的文件中。 随着所选 ClusterTrustBundles 的集合或其内容发生变化,kubelet 会保持更新此文件。

默认情况下,如果找不到指定的 ClusterTrustBundle,或者 signerName / labelSelector 与所有 ClusterTrustBundle 都不匹配,kubelet 将阻止 Pod 启动。如果这不是你想要的行为, 可以将 optional 字段设置为 true,Pod 将使用 path 处的空白文件启动。

pods/storage/projected-clustertrustbundle.yaml投射卷 - 图4

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: sa-ctb-name-test
  5. spec:
  6. containers:
  7. - name: container-test
  8. image: busybox
  9. command: ["sleep", "3600"]
  10. volumeMounts:
  11. - name: token-vol
  12. mountPath: "/root-certificates"
  13. readOnly: true
  14. serviceAccountName: default
  15. volumes:
  16. - name: root-certificates-vol
  17. projected:
  18. sources:
  19. - clusterTrustBundle:
  20. name: example
  21. path: example-roots.pem
  22. - clusterTrustBundle:
  23. signerName: "example.com/mysigner"
  24. labelSelector:
  25. matchLabels:
  26. version: live
  27. path: mysigner-roots.pem
  28. optional: true

与 SecurityContext 间的关系

关于在投射的服务账号卷中处理文件访问权限的提案 介绍了如何使得所投射的文件具有合适的属主访问权限。

Linux

在包含了投射卷并在 SecurityContext 中设置了 RunAsUser 属性的 Linux Pod 中,投射文件具有正确的属主属性设置, 其中包含了容器用户属主。

当 Pod 中的所有容器在其 PodSecurityContext 或容器 SecurityContext 中设置了相同的 runAsUser 时,kubelet 将确保 serviceAccountToken 卷的内容归该用户所有,并且令牌文件的权限模式会被设置为 0600

说明:

在某 Pod 被创建后为其添加的临时容器不会更改创建该 Pod 时设置的卷权限。

如果 Pod 的 serviceAccountToken 卷权限被设为 0600 是因为 Pod 中的其他所有容器都具有相同的 runAsUser, 则临时容器必须使用相同的 runAsUser 才能读取令牌。

Windows

在包含了投射卷并在 SecurityContext 中设置了 RunAsUsername 的 Windows Pod 中, 由于 Windows 中用户账号的管理方式问题,文件的属主无法正确设置。 Windows 在名为安全账号管理器(Security Account Manager,SAM) 的数据库中保存本地用户和组信息。每个容器会维护其自身的 SAM 数据库实例, 宿主系统无法窥视到容器运行期间数据库内容。Windows 容器被设计用来运行操作系统的用户态部分, 与宿主系统之间隔离,因此维护了一个虚拟的 SAM 数据库。 所以,在宿主系统上运行的 kubelet 无法动态为虚拟的容器账号配置宿主文件的属主。 如果需要将宿主机器上的文件与容器共享,建议将它们放到挂载于 C:\ 之外的独立卷中。

默认情况下,所投射的文件会具有如下例所示的属主属性设置:

  1. PS C:\> Get-Acl C:\var\run\secrets\kubernetes.io\serviceaccount\..2021_08_31_22_22_18.318230061\ca.crt | Format-List
  2. Path : Microsoft.PowerShell.Core\FileSystem::C:\var\run\secrets\kubernetes.io\serviceaccount\..2021_08_31_22_22_18.318230061\ca.crt
  3. Owner : BUILTIN\Administrators
  4. Group : NT AUTHORITY\SYSTEM
  5. Access : NT AUTHORITY\SYSTEM Allow FullControl
  6. BUILTIN\Administrators Allow FullControl
  7. BUILTIN\Users Allow ReadAndExecute, Synchronize
  8. Audit :
  9. Sddl : O:BAG:SYD:AI(A;ID;FA;;;SY)(A;ID;FA;;;BA)(A;ID;0x1200a9;;;BU)

这意味着,所有类似 ContainerAdministrator 的管理员用户都具有读、写和执行访问权限, 而非管理员用户将具有读和执行访问权限。

说明:

总体而言,为容器授予访问宿主系统的权限这种做法是不推荐的,因为这样做可能会打开潜在的安全性攻击之门。

在创建 Windows Pod 时,如果在其 SecurityContext 中设置了 RunAsUser, Pod 会一直阻塞在 ContainerCreating 状态。因此,建议不要在 Windows 节点上使用仅针对 Linux 的 RunAsUser 选项。