
# 存储多可用区部署的推荐配置
#### 应用场景
- 在多可用区构成的集群下，业务可以指定可用区部署。
- 多可用区部署可以减少可用区资源不足带来的故障问题。
通过存储多可用区部署优化，可以帮您最大限度地减少应用发布中断，确保关键业务系统和应用在各种故障情况下能持续运行。
#### 前提条件
- 您已创建一个安装CCE容器存储（Everest）的集群，并且集群版本≥1.21。若没有可用集群 ，请参照[购买Standard/Turbo集群](https://support.huaweicloud.com/usermanual-cce/cce_10_0028.html)创建。
- 集群的节点至少分布在三个不同的可用区，若当前集群的节点分布尚未覆盖三个可用区，请参照[创建节点](https://support.huaweicloud.com/usermanual-cce/cce_10_0363.html)或[创建节点池](https://support.huaweicloud.com/usermanual-cce/cce_10_0012.html)在未部署的可用区中创建新节点。
 
#### 操作步骤
1. kubectl连接集群，具体请参见[kubectl连接集群](https://support.huaweicloud.com/usermanual-cce/cce_10_0107.html)。
2. 创建存储类StorageClass的Yaml文件。 
   ```
   vi storageclass.yaml
   ```
   向storageclass.yaml中填入以下内容，该内容仅是StorageClass配置的模板，您可以根据需求自行修改。
   ```
   apiVersion: storage.k8s.io/v1
   kind: StorageClass
   metadata:
     name: test-disk-topology-alltype
   provisioner: everest-csi-provisioner
   parameters:
     csi.storage.k8s.io/csi-driver-name: disk.csi.everest.io
     csi.storage.k8s.io/fstype: ext4  
     everest.io/disk-volume-type: SAS #表示高I/O类型云硬盘 
     everest.io/passthrough: "true"
   reclaimPolicy: Delete
   allowVolumeExpansion: true
   volumeBindingMode: WaitForFirstConsumer
   ```
   表1StorageClass部分参数说明 
   | 参数                   | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
   |:---|:---|
   | provisioner          | 存储资源提供商，CCE均由everest插件提供，此处只能填写everest-csi-provisioner。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
   | parameters           | 存储参数，不同类型的存储支持的参数不同。详情请参见[parameters参数说明](https://support.huaweicloud.com/bestpractice-cce/cce_bestpractice_00281.html#:~:text=PV操作失败。-,表2 parameters参数说明,-存储类型)。 须知： everest.io/disk-volume-type表示云硬盘类型，有多种选择。 - SAS：高I/O。  - SSD：超高I/O。  - GPSSD：通用型SSD。  - ESSD：极速型SSD。  - GPSSD2：通用型SSD v2，everest版本为2.4.4及以上支持使用，使用时需同时指定everest.io/disk-iops和everest.io/disk-throughput注解。  - ESSD2：极速型SSD v2，everest版本为2.4.4及以上支持使用，使用时需指定everest.io/disk-iops注解。   |
   | reclaimPolicy        | 用来指定创建PV的persistentVolumeReclaimPolicy字段值，支持Delete和Retain。如果StorageClass对象被创建时没有指定reclaimPolicy，它将默认为Delete。 - Delete：表示动态创建的PV，在PVC销毁的时候PV也会自动销毁。  - Retain：表示动态创建的PV，在PVC销毁的时候PV不会自动销毁。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
   | allowVolumeExpansion | 定义由此存储类创建的PV是否支持动态扩容，默认为false。是否能动态扩容是由底层存储插件来实现的，这里只是一个开关。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
   | volumeBindingMode    | 表示卷绑定模式，即动态创建PV的时间，分为立即创建和延迟创建。 - Immediate：创建PVC时完成PV绑定和动态创建。  - WaitForFirstConsumer：延迟PV的绑定和创建，当在工作负载中使用该PVC时才执行PV创建和绑定流程。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
      
   
   
3. 创建StorageClass。 
   ```
   kubectl create -f storageclass.yaml
   ```
   
   
4. 创建StatefulSet的Yaml文件。 
   ```
   vi statefulset.yaml
   ```
   向statefulset.yaml文件中填入以下内容，该内容仅是标准StatefulSet应用配置的模板，您可以根据需求自行定义。
   ```
   apiVersion: apps/v1
   kind: StatefulSet
   metadata:
     name: nginx 
   spec:
     replicas: 3
     serviceName: "nginx"
     selector:
       matchLabels: 
         app: nginx
     template:
       metadata:
         labels: 
           app: nginx
       spec:
         topologySpreadConstraints:
         - labelSelector:   # 用于查找匹配的Pod，对匹配此标签选择器的Pod进行计数，以确定其相应拓扑域中的Pod数量
             matchLabels:
               app: nginx
           maxSkew: 1       # 表示在给定的拓扑类型中，任意两个拓扑域上匹配的Pod数量所允许的最大差异
           topologyKey: topology.kubernetes.io/zone    # 表示节点标签的键
           whenUnsatisfiable: DoNotSchedule    # 表示当Pod不满足传播约束时，调度器处理该Pod的方式
         containers:
         - image: nginx:latest
           name: nginx
           env:
           - name: NGINX_ROOT_PASSWORD
             value: "nginx"
           volumeMounts: 
           - name: disk-csi
             mountPath: /var/lib/nginx
         imagePullSecrets:
         - name: default-secret
         tolerations:
         - key: "app"
           operator: "Exists"
           effect: "NoSchedule"
     volumeClaimTemplates:    # 根据指定的Replicas数量自动创建对应数量的云硬盘，便于快速扩展
     - metadata:
         name: disk-csi
       spec:
         accessModes: [ "ReadWriteOnce" ]   # 云硬盘只支持以读写模式被单个节点挂载和访问，即ReadWriteOnce
         storageClassName: test-disk-topology-alltype
         resources:
           requests:
             storage: 40Gi
   ```
   表2StatefulSet部分参数说明 
   | 参数                                          | 说明                                                                                                                                                                                                                                                                                                                                                                                                             |
   |:---|:---|
   | topologySpreadConstraints                   | 拓扑分布约束，用来控制Pod在集群内拓扑域之间的分布，如区域、可用区、节点和其他用户自定义拓扑域。了解更多信息，请参见[Pod 拓扑分布约束](https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/topology-spread-constraints/)。                                                                                                                                                                                                                                           |
   | topologySpreadConstraints.labelSelector     | 用于查找匹配的Pod。对匹配此标签选择器的Pod进行计数，以确定其相应拓扑域中的Pod数量。                                                                                                                                                                                                                                                                                                                                                                 |
   | topologySpreadConstraints.maxSkew           | 表示在给定的拓扑类型中，任意两个拓扑域上匹配的Pod数量所允许的最大差异。这个值用来衡量Pod分布的不均匀程度，且取值必须大于0。                                                                                                                                                                                                                                                                                                                                              |
   | topologySpreadConstraints.topologyKey       | 表示节点标签的键。当两个节点都使用此键标记且标签值相同时，调度器会认为这两个节点处于相同的拓扑中，调度器试图向每个拓扑域放入数量均衡的Pod。                                                                                                                                                                                                                                                                                                                                        |
   | topologySpreadConstraints.whenUnsatisfiable | 表示当Pod不满足传播约束时，调度器处理该Pod的方式。whenUnsatisfiable有两种取值： - DoNotSchedule（默认）：当Pod不满足传播约束时，不调度该Pod。  - ScheduleAnyway：当Pod不满足传播约束时，仍然调度该Pod，并且优先考虑最小化偏斜的节点。   |
   | volumeClaimTemplates                        | 根据指定的Replicas数量自动创建对应数量的云盘，便于快速扩展。                                                                                                                                                                                                                                                                                                                                                                             |
      
   
   
5. 创建StatefulSet应用。 
   ```
   kubectl create -f statefulset.yaml
   ```
   
   
 
#### 配置验证
验证动态创建的存储卷（PV）是否跟随Pod实例部署在不同可用区。
1. 通过以下命令查看新建的PV。 
   ```
   kubectl get pv
   ```
   回显如下，其中前3条为随Pod实例动态创建的PV。
   ```
   NAME           CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                      STORAGECLASS                 VOLUMEATTRIBUTESCLASS   REASON   AGE
   pvc-699eda75   40Gi       RWO            Delete           Bound    default/disk-csi-nginx-0   test-disk-topology-alltype   <unset>                          132m
   pvc-6c68f5a7   40Gi       RWO            Delete           Bound    default/disk-csi-nginx-1   test-disk-topology-alltype   <unset>                          131m
   pvc-8f74ce3a   40Gi       RWO            Delete           Bound    default/disk-csi-nginx-2   test-disk-topology-alltype   <unset>                          131m
   pvc-f738f8aa   10Gi       RWO            Delete           Bound    default/pvc                csi-disk                     <unset>                          6d4h
   ```
   
   
2. 根据PV名称查看PV所在的可用区。 
   ```
   kubectl describe pv pvc-699eda75 pvc-6c68f5a7 pvc-8f74ce3a | grep zone
   ```
   回显如下，由结果可知3个PV分别位于不同可用区，实现存储多可用区部署。
   ```
   Labels:            failure-domain.beta.kubernetes.io/zone=cn-east-3d
       Term 0:        failure-domain.beta.kubernetes.io/zone in [cn-east-3d]
   Labels:            failure-domain.beta.kubernetes.io/zone=cn-east-3b
       Term 0:        failure-domain.beta.kubernetes.io/zone in [cn-east-3b]
   Labels:            failure-domain.beta.kubernetes.io/zone=cn-east-3c
       Term 0:        failure-domain.beta.kubernetes.io/zone in [cn-east-3c]
   ```
   
   
 
