本文发布已超过一年。较早的文章可能包含过时内容。请检查页面信息自发布以来是否已失效。

Kubernetes 1.25:使用 Secrets 进行 CSI 卷的节点驱动扩容

Kubernetes v1.25 于本月早些时候发布,引入了一项新功能,允许你的集群扩展存储卷,即使访问这些卷需要密钥(例如:访问 SAN 网络的凭据)才能执行节点扩展操作。这项新行为处于 Alpha 版本,你必须启用一个特性门控(CSINodeExpandSecret)才能使用它。你还必须使用 CSI 存储;这项更改与 Kubernetes 内建的存储驱动程序无关。

要开启这项新的 Alpha 特性,你需要在 kube-apiserver 和 kubelet 中启用 CSINodeExpandSecret 特性门控。这将开启一种机制,使 CSI 驱动程序在 NodeExpansion 过程中发送 secretRef 配置,从而利用该配置执行底层存储系统的节点侧扩展操作。

这到底是什么?

在 Kubernetes v1.24 之前,你可以定义使用 StorageClass Secrets 的集群级 StorageClass,但你没有机制来指定在存储挂载到节点上以及在节点侧需要扩展卷时用于执行操作的凭据。

Kubernetes CSI 已经实现了针对特定类型卷调整大小的类似机制;即与任何节点无关(称为 Controller Expansion)的 PersistentVolume 大小调整。在这种情况下,你将 PersistentVolume 与包含卷大小调整操作凭据的 Secret 关联起来,以便可以进行控制器扩展。CSI 还支持 nodeExpandVolume 操作,CSI 驱动程序可以独立于或与 Controller Expansion 一起使用此操作,其中大小调整操作是由集群中挂载了该卷的节点驱动的。请阅读 Kubernetes 1.24:卷扩展现已成为稳定特性

  • 有时,CSI 驱动程序需要在进行节点级文件系统扩展操作之前检查后端块存储(或镜像)的实际大小。这可以避免在文件系统扩展期间后端存储集群返回误报。

  • 当 PersistentVolume 表示加密块存储(例如使用 LUKS)时,你需要提供密码才能扩展设备,并才能在该设备上扩展文件系统。

  • 在节点扩展时进行各种验证,CSI 驱动程序必须连接到后端存储集群。如果 nodeExpandVolume 请求包含 secretRef,则 CSI 驱动程序可以使用该密钥连接到存储集群执行集群操作。

它是如何工作的?

为了从 Kubernetes 的这个版本开始启用此功能,SIG Storage 引入了一个名为 CSINodeExpandSecret 的新特性门控。一旦在集群中启用了该特性门控,NodeExpandVolume 请求就可以包含一个 secretRef 字段。NodeExpandVolume 请求是 CSI 的一部分;例如,在从 Kubernetes 控制平面发送到 CSI 驱动程序的请求中。

作为集群运维人员,你可以像指定其他 CSI 密钥数据一样,在 StorageClass 中将这些密钥指定为不透明参数。StorageClass 需要设置一些 CSI 特定的参数。下面是这些参数的一个示例

csi.storage.k8s.io/node-expand-secret-name: test-secret
csi.storage.k8s.io/node-expand-secret-namespace: default

如果特性门控已启用且 StorageClass 携带了上述密钥配置,CSI Provisioner 会在 NodeExpansion 请求中收到来自 Secret 的凭据。

需要密钥进行在线扩展的 CSI 卷将设置 NodeExpandSecretRef 字段。如果未设置,NodeExpandVolume CSI RPC 调用将不会包含密钥。

试用

  1. 启用 CSINodeExpandSecret 特性门控(请参考 特性门控)。

  2. 创建一个 Secret,然后创建一个使用该 Secret 的 StorageClass。

这是一个包含凭据的 Secret 的示例清单

apiVersion: v1
kind: Secret
metadata:
  name: test-secret
  namespace: default
data:
stringData:
  username: admin
  password: t0p-Secret

这是一个引用这些凭据的 StorageClass 的示例清单

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: csi-blockstorage-sc
parameters:
  csi.storage.k8s.io/node-expand-secret-name: test-secret   # the name of the Secret
  csi.storage.k8s.io/node-expand-secret-namespace: default  # the namespace that the Secret is in
provisioner: blockstorage.cloudprovider.example
reclaimPolicy: Delete
volumeBindingMode: Immediate
allowVolumeExpansion: true

示例输出

如果 PersistentVolumeClaim (PVC) 成功创建,你可以在 PersistentVolume 的 spec.csi 字段中看到该配置(查找 spec.csi.nodeExpandSecretRef)。通过运行 kubectl get persistentvolume <pv_name> -o yaml 来检查它是否工作。你应该会看到类似以下内容:

apiVersion: v1
kind: PersistentVolume
metadata:
  annotations:
    pv.kubernetes.io/provisioned-by: blockstorage.cloudprovider.example
  creationTimestamp: "2022-08-26T15:14:07Z"
  finalizers:
  - kubernetes.io/pv-protection
  name: pvc-95eb531a-d675-49f6-940b-9bc3fde83eb0
  resourceVersion: "420263"
  uid: 6fa824d7-8a06-4e0c-b722-d3f897dcbd65
spec:
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 6Gi
  claimRef:
    apiVersion: v1
    kind: PersistentVolumeClaim
    name: csi-pvc
    namespace: default
    resourceVersion: "419862"
    uid: 95eb531a-d675-49f6-940b-9bc3fde83eb0
  csi:
    driver: blockstorage.cloudprovider.example
    nodeExpandSecretRef:
      name: test-secret
      namespace: default
    volumeAttributes:
      storage.kubernetes.io/csiProvisionerIdentity: 1648042783218-8081-blockstorage.cloudprovider.example
    volumeHandle: e21c7809-aabb-11ec-917a-2e2e254eb4cf
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: topology.hostpath.csi/node
          operator: In
          values:
          - racknode01
  persistentVolumeReclaimPolicy: Delete
  storageClassName: csi-blockstorage-sc
  volumeMode: Filesystem
status:
  phase: Bound

如果你随后触发在线存储扩展,kubelet 会通过加载该 Secret 并将数据传递给存储驱动程序,从而将相应的凭据传递给 CSI 驱动程序。

这是一个调试日志示例

I0330 03:29:51.966241       1 server.go:101] GRPC call: /csi.v1.Node/NodeExpandVolume
I0330 03:29:51.966261       1 server.go:105] GRPC request: {"capacity_range":{"required_bytes":7516192768},"secrets":"***stripped***","staging_target_path":"/var/lib/kubelet/plugins/kubernetes.io/csi/blockstorage.cloudprovider.example/f7c62e6e08ce21e9b2a95c841df315ed4c25a15e91d8fcaf20e1c2305e5300ab/globalmount","volume_capability":{"AccessType":{"Mount":{}},"access_mode":{"mode":7}},"volume_id":"e21c7809-aabb-11ec-917a-2e2e254eb4cf","volume_path":"/var/lib/kubelet/pods/bcb1b2c4-5793-425c-acf1-47163a81b4d7/volumes/kubernetes.io~csi/pvc-95eb531a-d675-49f6-940b-9bc3fde83eb0/mount"}
I0330 03:29:51.966360       1 nodeserver.go:459] req:volume_id:"e21c7809-aabb-11ec-917a-2e2e254eb4cf" volume_path:"/var/lib/kubelet/pods/bcb1b2c4-5793-425c-acf1-47163a81b4d7/volumes/kubernetes.io~csi/pvc-95eb531a-d675-49f6-940b-9bc3fde83eb0/mount" capacity_range:<required_bytes:7516192768 > staging_target_path:"/var/lib/kubelet/plugins/kubernetes.io/csi/blockstorage.cloudprovider.example/f7c62e6e08ce21e9b2a95c841df315ed4c25a15e91d8fcaf20e1c2305e5300ab/globalmount" volume_capability:<mount:<> access_mode:<mode:SINGLE_NODE_MULTI_WRITER > > secrets:<key:"XXXXXX" value:"XXXXX" > secrets:<key:"XXXXX" value:"XXXXXX" >

未来展望

由于此特性仍处于 Alpha 版本,Kubernetes Storage SIG 希望进行更新,或从 CSI 驱动程序作者那里获得更多测试和实现的反馈。社区计划最终在即将发布的版本中将此特性提升到 Beta 版本。

参与或了解更多?

该增强提案包含了关于此特性的历史和技术实现的许多详细信息。

要了解更多关于 Kubernetes 中基于 StorageClass 的动态供给,请参考存储类持久卷

请加入 Kubernetes Storage SIG (特别兴趣小组) 来帮助我们增强此特性。已经有很多好的想法,我们非常欢迎更多人加入!