本文已发布一年多。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否仍是准确的。

Kubernetes 中的拓扑感知卷供应

在 Kubernetes 1.12 中,借助拓扑感知的动态配置 Beta 特性,多区域集群与持久卷的结合体验得到了改进。此特性通过获取调度器关于为 Pod 配置卷最佳位置的输入,使得 Kubernetes 在动态配置卷时能够做出智能决策。在多区域集群中,这意味着卷将被配置到能够运行 Pod 的合适区域中,使您能够轻松地在故障域之间部署和扩展您的有状态工作负载,从而提供高可用性和容错能力。

之前的挑战

在此特性出现之前,在多区域集群中使用区域性持久磁盘 (如 AWS ElasticBlockStore、Azure Disk、GCE PersistentDisk) 运行有状态工作负载面临许多挑战。动态配置独立于 Pod 调度处理,这意味着一旦创建 PersistentVolumeClaim (PVC),就会立即配置卷。这使得配置器不知道哪些 Pod 使用该卷,以及任何可能影响调度的 Pod 约束。

这导致 Pod 无法调度,因为卷配置在了以下区域:

  • 没有足够的 CPU 或内存资源来运行 Pod
  • 与节点选择器、Pod 亲和性或反亲和性策略冲突
  • 由于污点无法运行 Pod

另一个常见问题是,一个非 StatefulSet 的 Pod 使用多个持久卷时,每个卷可能被配置在不同的区域,再次导致 Pod 无法调度。

次优的权宜之计包括过度配置节点,或在正确的区域手动创建卷,这使得动态部署和扩展有状态工作负载变得困难。

拓扑感知的动态配置特性解决了上述所有问题。

支持的卷类型

在 1.12 中,以下驱动支持拓扑感知的动态配置:

  • AWS EBS
  • Azure Disk
  • GCE PD (包括区域 PD)
  • CSI (Alpha) - 目前只有 GCE PD CSI 驱动实现了拓扑支持

设计原则

虽然最初支持的插件集都是基于区域的,但我们在设计此特性时遵循了 Kubernetes 环境可移植性的原则。拓扑规范是通用的,并使用类似于 Pod nodeSelectors 和 nodeAffinity 中的基于标签的规范。此机制允许您定义自己的拓扑边界,例如本地集群中的机架,而无需修改调度器来理解这些自定义拓扑。

此外,拓扑信息从 Pod 规范中抽象出来,因此 Pod 不需要了解底层存储系统的拓扑特征。这意味着您可以在多个集群、环境和存储系统上使用相同的 Pod 规范。

入门

要启用此特性,您只需创建一个 StorageClass,并将其 volumeBindingMode 设置为 WaitForFirstConsumer

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: topology-aware-standard
provisioner: kubernetes.io/gce-pd
volumeBindingMode: WaitForFirstConsumer
parameters:
  type: pd-standard

此新设置指示卷配置器不要立即创建卷,而是等待使用关联 PVC 的 Pod 运行通过调度。请注意,以前的 StorageClass zonezones 参数不再需要指定,因为现在由 Pod 策略驱动决定在哪个区域配置卷。

接下来,使用此 StorageClass 创建 Pod 和 PVC。此序列与之前相同,只是在 PVC 中指定了不同的 StorageClass。以下是一个假设示例,通过指定许多 Pod 约束和调度策略来演示新特性的功能:

  • 一个 Pod 中的多个 PVC
  • 跨区域子集的 nodeAffinity
  • 区域上的 Pod 反亲和性
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:   
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: failure-domain.beta.kubernetes.io/zone
                operator: In
                values:
                - us-central1-a
                - us-central1-f
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - nginx
            topologyKey: failure-domain.beta.kubernetes.io/zone
      containers:
      - name: nginx
        image: gcr.io/google_containers/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
        - name: logs
          mountPath: /logs
 volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: topology-aware-standard
      resources:
        requests:
          storage: 10Gi
  - metadata:
      name: logs
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: topology-aware-standard
      resources:
        requests:
          storage: 1Gi

之后,您可以看到卷已按照 Pod 设置的策略配置到了相应的区域中

$ kubectl get pv -o=jsonpath='{range .items[*]}{.spec.claimRef.name}{"\t"}{.metadata.labels.failure\-domain\.beta\.kubernetes\.io/zone}{"\n"}{end}'
www-web-0       us-central1-f
logs-web-0      us-central1-f
www-web-1       us-central1-a
logs-web-1      us-central1-a

我如何了解更多信息?

关于拓扑感知的动态配置特性的官方文档可在此处获取:此处

CSI 驱动的文档可在 https://kubernetes-csi.github.io/docs/ 获取

接下来是什么?

我们正在积极改进此特性以支持:

  • 更多卷类型,包括本地卷的动态配置
  • 每个节点的动态卷可连接数量和容量限制

我如何参与?

如果您对此特性有反馈或有兴趣参与设计和开发,请加入 Kubernetes 存储特别兴趣小组 (SIG)。我们正在快速发展,始终欢迎新的贡献者。

特别感谢所有帮助将此特性带到 Beta 版本的贡献者,包括 Cheng Xing (verult)、Chuqiang Li (lichuqiang)、David Zhu (davidz627)、Deep Debroy (ddebroy)、Jan Šafránek (jsafrane)、Jordan Liggitt (liggitt)、Michelle Au (msau42)、Pengfei Ni (feiskyer)、Saad Ali (saad-ali)、Tim Hockin (thockin) 和 Yecheng Fu (cofyc)。