
使用NAS、OSS挂载慢的问题 现象: 在Kubernetes中部署应用时,如果使用了NAS、OSS这类存储卷,有时会出现Pod启动很慢的问题; 启动时间可能会是几分钟或者几十分钟; 原因: 出现这个情况,可以查看一下部署的应用,看看是否给pod配置了fsGroup(可能是主动配置的,也可能是istio注入的); 如果pod的spec中有fsGroup的配置,kubelet在执行完数据卷的挂载后会根据fsGroup进行挂载点的权限设置,即:执行chown、chmod操作; 由于您挂载的目录可能有数量较多的文件,导致linux在执行chown、chmod的时候就会非常慢,即最终表现为挂载很慢(其实纯粹挂载过程很快已经结束); 场景详解: Flexvolume: 如果应用挂载数据卷使用的是Flexvolume插件; pod配置了fsGroup; 数据卷不是只读类型; 符合上面的条件就会触发chmod、chown操作,可能导致挂载(pod启动)很慢; 解决: 去掉fsGroup的配置; 对挂载点预先配置其归属和权限; 例如,挂载某个NAS目录,可以预先手动挂载这个目录,执行chmod、chown后,就不需要在pod启动时候再配置了。 CSI: 如果应用挂载数据卷使用的是CSI插件; pod配置了fsGroup; 数据卷不是只读类型; 数据卷是ReadWriteOnce类型; 符合上面的条件就会触发chmod、chown操作,可能导致挂载(pod启动)很慢; 解决1: 去掉fsGroup的配置; 对挂载点预先配置其归属和权限; 例如,挂载某个NAS目录,可以预先手动挂载这个目录,执行chmod、chown后,就不需要在pod启动时候再配置了。 解决2: 将PV配置为非ReadWriteOnce类型;
背景: ACK1.16集群升级到1.18版本时,CSI Block Volume出现一个不兼容的问题需要处理; 即:需要将1.16版本的节点(Kubelet)上使用Block Volume的Pod先迁移到1.18版本的节点上,然后再升级1.16版本节点; 什么是Block Volume:https://kubernetes.io/zh/docs/concepts/storage/persistent-volumes/#raw-block-volume-support 原因: Kubernetes在1.17版本中对Block Volume的GlobalPath目录结构做了修改,这样就导致在1.16版本挂载的Block Volume在1.18版本上无法识别。 所以需要遵循:在一个版本挂载的Block Volume必须在相同版本上进行卸载;问题详见:https://v1-17.docs.kubernetes.io/docs/setup/release/notes/#storagehttps://github.com/kubernetes/kubernetes/pull/74026 ACK解决方案: ACK在1.18 Kubernetes(kubelet)做了兼容,即让1.18版本kubelet在卸载block volume时,也认识1.16版本的目录结构; 但此问题在不同场景的行为有区别,目前对以下场景具有不同的兼容性。 兼容直接升级: 以下场景在升级1.18集群,可以直接升级: 通过StatefulSet部署的应用挂载了Block Volume, 通过单个Pod部署的应用挂载了Block Volume, 不兼容直接升级: 以下场景还不兼容,您升级时需要遵循社区的Drain方案,进行排水或者先将挂载Block Volume的pod停掉: 单个Block Volume被同一个节点的多个Pod同时挂载的场景; 通过Deployment部署pod,并挂载了Block Volume; 升级注意: 对于不兼容的场景,您不要对进群进行升级,除非使用社区排水方案,或者联系我们一起看一下具体场景并给出升级方案;
1. 说明: Flexvolume是Kubernetes早期支持的存储插件类型,目前社区依然支持Flexvolume作为存储插件使用。但由于Flexvolume为非容器化方案,社区提出了CSI存储接入规范,并会对CSI规范长期维护和更新。阿里云容器服务从早期只支持Flexvolume插件,到目前即支持Flexvolume、也支持CSI。随着CSI的不断演进,Flexvolume在各种编排能力上和CSI逐步形成功能差异,所以从长期规划上会逐渐从Flexvolume演进到CSI的支持。本文介绍如何将Flexvolume插件挂载的NAS、OSS类型存储转换到CSI插件类型; 2. 使用限制: 执行此转换,请将集群升级到1.16或者以上;如果您的集群中有使用Flexvolume挂载云盘,暂不适合使用此方案;实现插件类型转换,需要重启运行中的pod,重新定义pv、pvc; 3. CSI插件准备: 在集群中部署CSI 插件,模板见链接(您可以使用最新版本,如后续的v1.0.6):https://github.com/kubernetes-sigs/alibaba-cloud-csi-driver/tree/release-v1.0.5/deploy/ack部署命令: # kubectl apply -f csi-plugin.yaml # kubectl apply -f csi-provisioner.yaml 部署时,需要将镜像地址换成您的集群所在的region地址,这样可以提高下载速度;例如:把:registry.cn-hangzhou.aliyuncs.com/acs/csi-plugin:v1.14.8.39-0d749258-aliyun改成:registry-vpc.cn-beijing.aliyuncs.com/acs/csi-plugin:v1.14.8.39-0d749258-aliyun部署完成后,检查是否部署成功: # kubectl get pod -nkube-system |grep csi csi-plugin-5jqf6 9/9 Running 0 4m15s csi-plugin-dt8fd 9/9 Running 0 4m15s csi-plugin-nlnpn 9/9 Running 0 4m15s csi-plugin-p5lv6 9/9 Running 0 4m15s csi-plugin-s29wp 9/9 Running 0 4m15s csi-provisioner-58cb59cf6c-5c9qj 8/8 Running 0 4m9s csi-provisioner-58cb59cf6c-k96v2 8/8 Running 0 4m9s 注意:部署csi-provisioner的时候,如果遇到StorageClass相关的error信息。原因是:Flexvolume、Disk-Controller插件也有相应的StorageClass,并和csi插件的StorageClass重名。您可以删除老的storageclass,再重新apply csi-provisioner;如下: # kubectl get sc NAME PROVISIONER AGE alicloud-disk-available alicloud/disk 5h11m alicloud-disk-efficiency alicloud/disk 5h11m alicloud-disk-essd alicloud/disk 5h11m alicloud-disk-ssd alicloud/disk 5h11m # kubectl delete sc alicloud-disk-available alicloud-disk-efficiency alicloud-disk-essd alicloud-disk-ssd storageclass.storage.k8s.io "alicloud-disk-available" deleted storageclass.storage.k8s.io "alicloud-disk-efficiency" deleted storageclass.storage.k8s.io "alicloud-disk-essd" deleted storageclass.storage.k8s.io "alicloud-disk-ssd" deleted # kubectl apply -f csi-provisioner.yaml # kubectl get sc NAME PROVISIONER AGE alicloud-disk-available diskplugin.csi.alibabacloud.com 84s alicloud-disk-efficiency diskplugin.csi.alibabacloud.com 84s alicloud-disk-essd diskplugin.csi.alibabacloud.com 84s alicloud-disk-ssd diskplugin.csi.alibabacloud.com 84s alicloud-disk-topology diskplugin.csi.alibabacloud.com 5m18s 4. 静态NAS卷迁移: 步骤: 保存Flexvolume版本的pvc、pv模板;创建csi类型的pvc、pv对象;更新应用,使用新创建的csi类型的pvc; 下面为deployment使用nas pvc的示例: # kubectl get deploy NAME READY UP-TO-DATE AVAILABLE AGE nas-static 2/2 2 2 6m21s # kubectl get pod NAME READY STATUS RESTARTS AGE nas-static-7f9446758b-2qfxj 1/1 Running 0 11m nas-static-7f9446758b-wcwc5 1/1 Running 0 11m # kubectl describe pod nas-static-7f9446758b-2qfxj |grep ClaimName ClaimName: nas-pvc # kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE nas-pvc Bound nas-pv 512Gi RWX nas 12m ## 登陆pod所在节点,查看挂载信息: 2564f49129-ysu87.cn-shenzhen.nas.aliyuncs.com:/aliyun on /var/lib/kubelet/pods/b9f14e39-86ed-4c39-b4b7-baba37b15bac/volumes/alicloud~nas/nas-pv type nfs4 (rw,relatime,vers=3,rsize=1048576,wsize=1048576,namlen=255,hard,noresvport,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.7.208,local_lock=none,addr=192.168.1.152) 步骤1:保存原始pvc(nas-pvc)、pv(nas-pv) # kubectl get pvc nas-pvc -oyaml > pvc.nas-pvc.yaml # cat pvc.nas-pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nas-pvc namespace: default spec: accessModes: - ReadWriteMany resources: requests: storage: 512Gi selector: matchLabels: alicloud-pvname: nas-pv storageClassName: nas # kubectl get pv nas-pv -oyaml > pv.nas-pv.yaml # cat pv.nas-pv.yaml apiVersion: v1 kind: PersistentVolume metadata: labels: alicloud-pvname: nas-pv name: nas-pv spec: accessModes: - ReadWriteMany capacity: storage: 512Gi flexVolume: driver: alicloud/nas options: path: /aliyun server: 2564f49129-ysu87.cn-shenzhen.nas.aliyuncs.com vers: "3" persistentVolumeReclaimPolicy: Retain storageClassName: nas 步骤2:创建CSI类型pvc(nas-pvc-new)、pv(nas-pv-new) # cat pvc.nas-pvc-new.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nas-pvc-new namespace: default spec: accessModes: - ReadWriteMany resources: requests: storage: 512Gi selector: matchLabels: alicloud-pvname: nas-pv-new storageClassName: nas ## flexvolume配置改为csi配置; ## options配置可以写到:mountOptions中 # cat pv.nas-pv-new.yaml apiVersion: v1 kind: PersistentVolume metadata: labels: alicloud-pvname: nas-pv-new name: nas-pv-new spec: accessModes: - ReadWriteMany capacity: storage: 512Gi csi: driver: nasplugin.csi.alibabacloud.com volumeHandle: nas-pv-new volumeAttributes: server: "2564f49129-ysu87.cn-shenzhen.nas.aliyuncs.com" path: "/aliyun" mountOptions: - nolock,tcp,noresvport - vers=3 persistentVolumeReclaimPolicy: Retain storageClassName: nas # kubectl apply -f pvc.nas-pvc-new.yaml # kubectl apply -f pv.nas-pv-new.yaml # kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE nas-pvc Bound nas-pv 512Gi RWX nas 30m nas-pvc-new Bound nas-pv-new 512Gi RWX nas 2s 步骤3:更新应用,使用新的csi类型pvc; # kubectl edit deploy nas-static 把数据卷配置改为新的pvc; volumes: - name: pvc-nas persistentVolumeClaim: claimName: nas-pvc-new ## 查看Pod已经重启: # kubectl get pod NAME READY STATUS RESTARTS AGE nas-static-6f7d965689-7sm5b 1/1 Running 0 70s nas-static-6f7d965689-8npxw 1/1 Running 0 53s ## 查看挂载信息: 2564f49129-ysu87.cn-shenzhen.nas.aliyuncs.com:/aliyun on /var/lib/kubelet/pods/ac02ea3f-125f-4b38-9bcf-9b117f62eaf0/volumes/kubernetes.io~csi/nas-pv-new/mount type nfs (rw,relatime,vers=3,rsize=1048576,wsize=1048576,namlen=255,hard,nolock,noresvport,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=192.168.1.152,mountvers=3,mountport=2049,mountproto=tcp,local_lock=all,addr=192.168.1.152) 通过上面3个步骤,即完成了deployment从使用flexvolume挂载nas转换成使用csi插件挂载nas; 5. 动态NAS场景: 步骤: 保存Flexvolume版本的storageclass、pvc、pv模板;创建csi类型的storageclass、pvc、pv对象;更新应用,使用新创建的csi类型的pvc;后续新创建pvc时,都使用csi类型的storageclass; 下面为statefulset使用动态nas pv的示例: # kubectl get sts NAME READY AGE web 2/2 3m11s # kubectl get pod NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 3m14s web-1 1/1 Running 0 118s # kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE nas-pvc-web-0 Bound default-nas-pvc-web-0-pvc-951911bd-b7f3-4551-8647-22f1f5d576b3 20Gi RWX alicloud-nas 3m32s nas-pvc-web-1 Bound default-nas-pvc-web-1-pvc-95eee8f9-54f4-42dc-a34f-b554423220eb 20Gi RWX alicloud-nas 2m16s # kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE default-nas-pvc-web-0-pvc-951911bd-b7f3-4551-8647-22f1f5d576b3 20Gi RWX Delete Bound default/nas-pvc-web-0 alicloud-nas 2m34s default-nas-pvc-web-1-pvc-95eee8f9-54f4-42dc-a34f-b554423220eb 20Gi RWX Delete Bound default/nas-pvc-web-1 alicloud-nas 2m14s # kubectl get sc alicloud-nas NAME PROVISIONER AGE alicloud-nas alicloud/nas 106m 步骤1:保存原始pvc、pv、storageclass ## 保存pvc模板: # kubectl get pvc nas-pvc-web-0 -oyaml > origin/nas-pvc-web-0.yaml # cat origin/nas-pvc-web-0.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: annotations: volume.beta.kubernetes.io/storage-provisioner: alicloud/nas finalizers: - kubernetes.io/pvc-protection labels: app: nginx name: nas-pvc-web-0 namespace: default spec: accessModes: - ReadWriteMany resources: requests: storage: 20Gi storageClassName: alicloud-nas # kubectl get pvc nas-pvc-web-1 -oyaml > origin/nas-pvc-web-1.yaml ## 保存pv模板: # kubectl get pv default-nas-pvc-web-0-pvc-951911bd-b7f3-4551-8647-22f1f5d576b3 -oyaml > origin/default-nas-pvc-web-0-pvc-951911bd-b7f3-4551-8647-22f1f5d576b3.yaml # cat origin/default-nas-pvc-web-0-pvc-951911bd-b7f3-4551-8647-22f1f5d576b3.yaml apiVersion: v1 kind: PersistentVolume metadata: annotations: pv.kubernetes.io/provisioned-by: alicloud/nas labels: createdby.aliyun.com: alicloud-nas-controller version.controller.aliyun.com: v1.14.3-58bf821 name: default-nas-pvc-web-0-pvc-951911bd-b7f3-4551-8647-22f1f5d576b3 spec: accessModes: - ReadWriteMany capacity: storage: 20Gi flexVolume: driver: alicloud/nas options: options: nolock,tcp,noresvport,vers=3 path: /root/default-nas-pvc-web-0-pvc-951911bd-b7f3-4551-8647-22f1f5d576b3 server: 2564f49129-ysu87.cn-shenzhen.nas.aliyuncs.com vers: "3" persistentVolumeReclaimPolicy: Delete storageClassName: alicloud-nas # kubectl get pv default-nas-pvc-web-1-pvc-95eee8f9-54f4-42dc-a34f-b554423220eb -oyaml > origin/default-nas-pvc-web-1-pvc-95eee8f9-54f4-42dc-a34f-b554423220eb.yaml ## 保存stroageclass模板: # kubectl get sc alicloud-nas -oyaml > origin/alicloud-nas.yaml # cat origin/alicloud-nas.yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: alicloud-nas mountOptions: - nolock,tcp,noresvport - vers=3 parameters: archiveOnDelete: "true" driver: flexvolume server: 2564f49129-ysu87.cn-shenzhen.nas.aliyuncs.com:/root/ provisioner: alicloud/nas reclaimPolicy: Delete volumeBindingMode: Immediate 步骤2:创建csi类型的storageclass、pvc、pv ## 老pvc:nas-pvc-web-0 对应新pvc: nas-pvc-new-web-0,这里nas-pvc字符是statefulset中配置的volume名字,更新为nas-pvc-new; ## provisioner改为:nasplugin.csi.alibabacloud.com ## name改为:nas-pvc-new-web-0 ## storageClassName改为:alicloud-nas-new ## alicloud-pvname改为:nas-pvc-new-web-0-pv (这个名字是任意的,但为了可读性,可以在pvc名字后面加上pv或者namespace等,保证全局唯一) # cat nas-pvc-new-web-0.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: annotations: volume.beta.kubernetes.io/storage-provisioner: nasplugin.csi.alibabacloud.com labels: app: nginx name: nas-pvc-new-web-0 namespace: default spec: accessModes: - ReadWriteMany resources: requests: storage: 20Gi storageClassName: alicloud-nas-new selector: matchLabels: alicloud-pvname: nas-pvc-new-web-0-pv ## 老pv:default-nas-pvc-web-0-pvc-951911bd-b7f3-4551-8647-22f1f5d576b3 更新为下面新pv; ## provisioned-by改为:nasplugin.csi.alibabacloud.com ## labels改为:nas-pvc-new-web-0-pv ## name改为:nas-pvc-new-web-0-pv ## flexvolume配置改为csi配置:volumeHandle改为pv的名字; ## storageClassName改为:alicloud-nas-new # cat nas-pvc-new-web-0-pv.yaml apiVersion: v1 kind: PersistentVolume metadata: annotations: pv.kubernetes.io/provisioned-by: nasplugin.csi.alibabacloud.com finalizers: - kubernetes.io/pv-protection labels: alicloud-pvname: nas-pvc-new-web-0-pv name: nas-pvc-new-web-0-pv spec: accessModes: - ReadWriteMany capacity: storage: 20Gi csi: driver: nasplugin.csi.alibabacloud.com volumeHandle: nas-pvc-new-web-0-pv volumeAttributes: server: "2564f49129-ysu87.cn-shenzhen.nas.aliyuncs.com" path: "/root/default-nas-pvc-web-0-pvc-951911bd-b7f3-4551-8647-22f1f5d576b3" mountOptions: - nolock,tcp,noresvport - vers=3 persistentVolumeReclaimPolicy: Delete storageClassName: alicloud-nas-new 同理创建另外的pvc、pv: 老pvc:nas-pvc-web-1更新为: nas-pvc-new-web-1 老pv:default-nas-pvc-web-1-pvc-95eee8f9-54f4-42dc-a34f-b554423220eb更新为: nas-pvc-new-web-1-pv # kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE nas-pvc-new-web-0 Bound nas-pvc-new-web-0-pv 20Gi RWX alicloud-nas-new 13m nas-pvc-new-web-1 Bound nas-pvc-new-web-1-pv 20Gi RWX alicloud-nas-new 10m 步骤3:更新应用,volume改为nas-pvc-new ## statefulset模板中的volume,从nas-pvc更新为nas-pvc-new: volumeClaimTemplates: - metadata: name: nas-pvc-new spec: ## 删除老的statefulset(statefulset的volumeClaimTemplates不能编辑),并创建新的; # kubectl delete sts web # kubectl apply -f sts.yaml 检查新建应用: # kubectl get pod NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 9m37s web-1 1/1 Running 0 9m20s # kubectl describe pod web-0 | grep ClaimName ClaimName: nas-pvc-new-web-0 # kubectl get pvc nas-pvc-new-web-0 NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE nas-pvc-new-web-0 Bound nas-pvc-new-web-0-pv 20Gi RWX alicloud-nas-new 17m 6. 静态OSS转换: 步骤: 保存Flexvolume版本的pvc、pv模板;创建csi类型的pvc、pv对象;更新应用,使用新创建的csi类型的pvc; 下面为deployment 使用 oss pvc/pv 的示例 # kubectl get deploy NAME READY UP-TO-DATE AVAILABLE AGE nginx-oss-deploy 1/1 1 1 5m37s # kubectl get pod NAME READY STATUS RESTARTS AGE nginx-oss-deploy-f49d8d6c4-df892 1/1 Running 0 6m1s # kubectl describe pod nas-static-7f9446758b-2qfxj |grep ClaimName ClaimName: pvc-oss # kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE pvc-oss Bound pv-oss 5Gi RWX 7m23s # kubectl get pv pv-oss -o yaml flexVolume: driver: alicloud/oss options: akId: xxxx akSecret: xxx bucket: oss-mount-test otherOpts: -o max_stat_cache_size=0 -o allow_other url: oss-cn-shanghai.aliyuncs.com 步骤一:保存原始的 pvc(pvc-oss), pv(pv-oss) # kubectl get pvc pvc-oss -oyaml > flex.oss-pvc.yaml # cat flex.oss-pvc.yaml apiVersion: v1 items: - apiVersion: v1 kind: PersistentVolumeClaim name: pvc-oss namespace: default spec: accessModes: - ReadWriteMany resources: requests: storage: 5Gi volumeMode: Filesystem volumeName: pv-oss status: accessModes: - ReadWriteMany capacity: storage: 5Gi phase: Bound kind: List metadata: resourceVersion: "" selfLink: "" # kubectl get pv pv-oss -oyaml > flex.oss-pv.yaml # cat flex.oss-pv.yaml apiVersion: v1 items: - apiVersion: v1 kind: PersistentVolume metadata: name: pv-oss spec: accessModes: - ReadWriteMany capacity: storage: 5Gi claimRef: apiVersion: v1 kind: PersistentVolumeClaim name: pvc-oss namespace: default flexVolume: driver: alicloud/oss options: akId: xxx akSecret: xxx bucket: oss-mount-test otherOpts: -o max_stat_cache_size=0 -o allow_other url: oss-cn-shanghai.aliyuncs.com persistentVolumeReclaimPolicy: Retain volumeMode: Filesystem status: phase: Bound kind: List metadata: resourceVersion: "" selfLink: "" 步骤二:创建CSI类型pvc(pvc-oss-new)、pv(pv-oss-new) # cat csi.oss-pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: oss-csi-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi selector: matchLabels: alicloud-pvname: oss-csi-pv # cat csi.oss-pv.yaml apiVersion: v1 kind: PersistentVolume metadata: name: oss-csi-pv labels: alicloud-pvname: oss-csi-pv spec: capacity: storage: 5Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain csi: driver: ossplugin.csi.alibabacloud.com # set volumeHandle same value pv name volumeHandle: oss-csi-pv volumeAttributes: bucket: "oss-mount-test" url: "oss-cn-shanghai.aliyuncs.com" otherOpts: "-o max_stat_cache_size=0 -o allow_other" akId: "***" akSecret: "***" path: "/" # kubectl apply -f csi.oss-pv.yaml # kubectl apply -f csi.oss-pvc.yaml # kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE oss-csi-pvc Bound oss-csi-pv 5Gi RWO 7m15s pvc-oss Bound pv-oss 5Gi RWX 52m 步骤3:更新应用,使用新的csi类型pvc; # kubectl edit deploy nginx-oss-deploy volumes: - name: oss1 persistentVolumeClaim: claimName: oss-csi-pvc // 查看pod已重启 # kubectl get pods NAME READY STATUS RESTARTS AGE nginx-oss-deploy-d84b9bb86-nxbf5 1/1 Running 0 21s 通过上面3个步骤,即完成了deployment从使用flexvolume挂载oss转换成使用csi插件挂载oss; 对应oss数据卷使用Secret的场景: 步骤 获取 flexvolume deployment 使用的secret使用 secret 创建静态卷 oss pvc/pv,编辑 flexvolume deployment 引用新创建的 pvc/pv 步骤一:获取 flexvolume deployment 使用的secret # kubectl get secret osssecret -o yaml apiVersion: v1 data: akId: xxxx akSecret: xxxx kind: Secret metadata: name: oss-secret namespace: default type: alicloud/oss 步骤二: 使用 secret 创建静态卷 oss-csi pvc/pv, # kubectl apply -f secret-pvc-pv.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: oss-csi-pvc-secret spec: accessModes: - ReadWriteMany resources: requests: storage: 5Gi selector: matchLabels: alicloud-pvname: oss-csi-pv-secret --- apiVersion: v1 kind: PersistentVolume metadata: name: oss-csi-pv-secret labels: alicloud-pvname: oss-csi-pv-secret spec: capacity: storage: 5Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain csi: driver: ossplugin.csi.alibabacloud.com volumeHandle: oss-csi-pv-secret // 需要和PV名字一致。 nodePublishSecretRef: name: oss-secret namespace: default volumeAttributes: bucket: "oss" url: "oss-cn-hangzhou.aliyuncs.com" otherOpts: "-o max_stat_cache_size=0 -o allow_other" # kubectl get pvc oss-csi-pvc-secret NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE oss-csi-pvc-secret Bound oss-csi-pv-secret 5Gi RWX 3m35s 步骤三: 更改deployment 引用,使用新创建的pvc # kubectl edit deploy nginx-oss-deploy volumes: - name: oss1 persistentVolumeClaim: claimName: oss-csi-pvc-secret // 查看pod已重启 # kubectl get pods NAME READY STATUS RESTARTS AGE nginx-oss-deploy-d84bxxrs6-nxbf5 1/1 Running 0 2s
在阿里云ACK集群中部署有状态服务通常使用云盘数据卷做数据存储,云盘本身提供了数据的备份(快照)恢复机制,但是如何将底层能力和K8S服务集成并灵活的提供给应用使用,是云原生存储服务需要解决的问题。K8S使用如下两个特性来实现备份恢复能力: 通过VolumeSnapshot对象实现云盘的备份(快照功能); 通过PVC中的DataSource功能实现数据的恢复(快照恢复); 由于VolumeSnapshot在K8S 1.16版本处于Alpha状态,所以ACK集群当前没有默认部署快照功能,需要手动安装插件才能使用; K8S快照说明: 在Kubernetes中为了实现快照相关功能,通过CRD定义了下面3个相关资源类型: VolumeSnapshotContent:描述存储后端的快照实例,由系统管理员创建维护,无NameSpace;类比于PV概念; VolumeSnapshot:声明一个快照实例,由用户创建维护,属于特定NameSpace;类比于PVC概念; VolumeSnapshotClass:定义一个快照类,描述创建快照使用的参数、Controller;类比于StorageClass概念; 快照资源绑定规则: 在使用Snapshot对象时,和pv、pvc一样,VolumeSnapshot与VolumeSnapshotContent需要首先进行绑定; VolumeSnapshot如果没有静态VolumeSnapshotContent可以绑定,则会创建动态VolumeSnapshotContent; VolumeSnapshotContent 与 VolumeSnapshot 绑定是一对一; 删除VolumeSnapshotContent 同时会把后端的快照也删除; 1.卷快照模板 下面是一个VolumeSnapshotClass定义模板: apiVersion: snapshot.storage.k8s.io/v1beta1 kind: VolumeSnapshotClass metadata: name: default-snapclass driver: diskplugin.csi.alibabacloud.com parameters: forceDelete: "false" deletionPolicy: Delete 其中: driver:定义了使用这个快照类的VolumeSnapshot所使用的controller; deletionPolicy: 表示删除volumeSnapshot的时候,volumeSnapshotContent是否删除; forceDelete: 表示是否允许在云盘引用快照的时候删除快照(默认是不允许删除的,因为以快照为数据源创建云盘时,创建过程会有时延,强制删除可能会造成数据丢失); 下面是一个VolumeSnapshot定义模板: apiVersion: snapshot.storage.k8s.io/v1beta1 kind: VolumeSnapshot metadata: name: new-snapshot-demo spec: volumeSnapshotClassName: default-snapclass source: persistentVolumeClaimName: disk-ssd-web-0 其中: persistentVolumeClaimName:定义使用哪个pvc作为快照源; volumeSnapshotClassName:定义了打快照使用的快照类; 2.通过快照恢复数据 通过云盘快照创建云盘是阿里云云盘提供的基础功能。在容器服务中通过在pvc定义DataSource指定使用哪个快照,动态创建云盘的时候即可实现使用快照创建云盘; kind: PersistentVolumeClaim apiVersion: v1 metadata: name: disk-snapshot spec: accessModes: - ReadWriteOnce storageClassName: alicloud-disk-ssd dataSource: name: new-snapshot-demo kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io resources: requests: storage: 20Gi 其中: storageClassName:定创建pv的存储类,指向的disk controller需要支持DataSource特性; dataSource:指定snapshot资源,说明创建云盘会使用这个快照数据; 插件部署: 集群准备: 部署csi-snapshotter前,您需要创建一个ACK 1.16版本集群,并在创建集群的时候选择使用CSI插件;集群创建 部署CRD & Snapshot: 下载snapshotter crd模板:https://github.com/kubernetes-sigs/alibaba-cloud-csi-driver/blob/master/deploy/disk/snapshot/crd.yaml 下载csi-snapshotter模板:https://github.com/kubernetes-sigs/alibaba-cloud-csi-driver/blob/master/deploy/disk/snapshot/csi-snapshotter.yaml 部署插件: $ kubectl apply -f crd.yaml $ kubectl apply -f csi-snapshotter.yaml 部署完成后集群中csi插件如下: # kubectl get crd NAME CREATED AT volumesnapshotclasses.snapshot.storage.k8s.io 2020-06-17T09:36:32Z volumesnapshotcontents.snapshot.storage.k8s.io 2020-06-17T09:36:32Z volumesnapshots.snapshot.storage.k8s.io 2020-06-17T09:36:32Z # kubectl get pod -nkube-system |grep csi-snap csi-snapshotter-d78f57d4d-rmjhp 3/3 Running 0 54m 使用: 下图是一个使用示例流程图,分成1、2、3三个步骤: 步骤1:创建原始应用,创建云盘卷保存数据; 步骤2:创建VolumeSnapshot,这时会自动创建VolumeSnapshotContent和存储端的快照实例; 步骤3:创建新的应用,并配置PVC引用步骤2中创建的快照对象; 通过上述三步实现了: 备份:Volume1中的数据备份到Snapshot1; 恢复:Snapshot1的数据(Volume1的数据)恢复成Volume2卷; 创建VolumeSnapshotClass快照类: 下载VolumeSnapshotClass模板:https://github.com/kubernetes-sigs/alibaba-cloud-csi-driver/blob/master/examples/disk/snapshot/snapshotclass.yaml $ kubectl apply -f calss.yaml apiVersion: snapshot.storage.k8s.io/v1beta1 kind: VolumeSnapshotClass metadata: name: default-snapclass driver: diskplugin.csi.alibabacloud.com deletionPolicy: Delete # kubectl get VolumeSnapshotClass NAME AGE default-snapclass 4h40m 步骤1:创建原始应用并写入数据: $ kubectl apply -f sts.yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: selector: matchLabels: app: nginx serviceName: "nginx" replicas: 1 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx volumeMounts: - name: disk-ssd mountPath: /data volumeClaimTemplates: - metadata: name: disk-ssd spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "alicloud-disk-snap" resources: requests: storage: 20Gi 往pod中写入数据: # kubectl exec -ti web-0 touch /data/test # kubectl exec -ti web-0 ls /data lost+found test 步骤2:创建VolumeSnapshot: $ kubectl apply -f snapshot.yaml apiVersion: snapshot.storage.k8s.io/v1beta1 kind: VolumeSnapshot metadata: name: new-snapshot-demo spec: volumeSnapshotClassName: default-snapclass source: persistentVolumeClaimName: disk-ssd-web-0 检查集群状态,VolumeSnapshot、VolumeSnapshotContent创建完成,同时到ECS控制台查看快照实例也创建完成: # kubectl get volumesnapshots.snapshot.storage.k8s.io NAME AGE new-snapshot-demo 36m # kubectl get VolumeSnapshotContent NAME AGE snapcontent-222d4dbb-beb4-49e5-8e11-ca6358c62123 36m 步骤3:数据恢复 $ kubectl apply -f sts-snapshot.yaml apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1beta2 kind: StatefulSet metadata: name: web-restore spec: selector: matchLabels: app: nginx serviceName: "nginx" replicas: 1 template: metadata: labels: app: nginx spec: hostNetwork: true containers: - name: nginx image: nginx command: ["sh", "-c"] args: ["sleep 10000"] volumeMounts: - name: disk-ssd mountPath: /data volumeClaimTemplates: - metadata: name: disk-ssd spec: accessModes: [ "ReadWriteOnce" ] storageClassName: alicloud-disk-ssd resources: requests: storage: 20Gi dataSource: name: new-snapshot-demo kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io 在volumeClaimTemplates定义中指定dataSource为VolumeSnapshot类型,且选择步骤2创建的名字为new-snapshot-demo的VolumeSnapshot。 查看容器数据,验证是否恢复成功: # kubectl exec -ti web-restore-0 ls /data lost+found test 可见实现了数据的恢复。 本方案只给出了创建一个快照并进行恢复的场景,后续我们会提供创建定时快照的方案。
在 K8S 1.16中,云盘数据卷在线扩容已经进入Beta阶段,功能会默认开启;本文描述了在CSI/Flexvolume环境中如何进行云盘的动态扩容步骤: 使用说明: 1. 数据备份: 切记:做数据卷扩容前,先对云盘打快照备份,以防扩容过程异常导致数据出现问题; 2. 适用范围: 只有动态存储卷才可以进行数据卷动态扩容,即:配置了StorageClassName的PV才可以; 不支持InlineVolume类型(非PV、PVC方式)云盘数据卷扩容; 普通云盘类型不支持动态扩容,请参考使用手动扩容云盘方案; StorageClass需要配置为:AllowVolumeExpansion: True,ACK集群默认为 True; 3. 集群添加扩容权限: 给云盘扩容需要为集群的”RAM 角色“添加ResizeDisk权限: 专有集群(CSI插件): 在集群 --> 管理 --> 集群资源 点击”Master RAM 角色“;编辑Ram权限,添加ResizeDisk如下图: 专有集群(Flexvolume插件)、托管集群: 在集群 --> 管理 --> 集群资源 点击”Worker RAM 角色“;编辑Ram权限,添加ResizeDisk如下图: 4. 插件升级到最新版本: 升级您使用Flexvolume或者CSI Plugin到最新版本; 云盘数据卷卷扩容: 云盘数据卷扩容包括 ”云盘扩容“ 和 ”文件系统扩容“ 两部分,云盘和文件系统都支持应用在线扩容(设备mount到目录状态下扩容),但是从文件系统扩容最佳实践角度,最稳定的扩容方案是:先停止应用层服务,umount挂载目录,再进行数据卷扩容。 基于稳定性需求,提供以下两种扩容的方式: pod不重启实现数据卷扩容:在负载高IO情况下,有小概率造成文件系统问题; Pod重启时实现数据卷扩容:应用停止后,扩容更安全; K8S 从1.16 开始默认实现了为Pod不重启即可以实现数据卷扩容。 1.容器不重启: 假设应用当前状态如下: # kubectl get pod web-0 1/1 Running 0 42s # kubectl exec web-0 df /data Filesystem 1K-blocks Used Available Use% Mounted on /dev/vdb 20511312 45080 20449848 1% /data # kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE disk-ssd-web-0 Bound d-wz9hpoifm43yn9zie6gl 20Gi RWO alicloud-disk-available 57s # kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE d-wz9hpoifm43yn9zie6gl 20Gi RWO Delete Bound default/disk-ssd-web-0 alicloud-disk-available 65s 在符合 ”使用说明“ 的各个条件下,可以通过下面命令进行数据卷扩容(也可以在控制台编辑pvc的size): # kubectl patch pvc disk-ssd-web-0 -p '{"spec":{"resources":{"requests":{"storage":"30Gi"}}}}' 等待一定时间(一般一分钟以内)后扩容完成,检查状态如下: # kubectl get pv d-wz9hpoifm43yn9zie6gl NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE d-wz9hpoifm43yn9zie6gl 30Gi RWO Delete Bound default/disk-ssd-web-0 alicloud-disk-available 5m23s # kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE disk-ssd-web-0 Bound d-wz9hpoifm43yn9zie6gl 30Gi RWO alicloud-disk-available 5m10s # kubectl exec web-0 df /data Filesystem 1K-blocks Used Available Use% Mounted on /dev/vdb 30832548 45036 30771128 1% /data 综上:只需要执行一条命令既可以完成所有扩容操作。 2.容器重启时扩容: 假设应用当前状态如下: # kubectl get pod web-0 1/1 Running 0 42s # kubectl exec web-0 df /data /dev/vdb 20511312 45080 20449848 1% /data # kubectl get pvc disk-ssd-web-0 Bound d-wz9g2j5qbo37r2lamkg4 20Gi RWO alicloud-disk-available 7m4s # kubectl get pv d-wz9g2j5qbo37r2lamkg4 d-wz9g2j5qbo37r2lamkg4 20Gi RWO Delete Bound default/disk-ssd-web-0 alicloud-disk-available 7m18s 1)对于Flexvolume插件挂载的云盘: 查看pv的调度信息: # kubectl get pv d-wz9g2j5qbo37r2lamkg4 -oyaml | grep failure-domain.beta.kubernetes.io/zone failure-domain.beta.kubernetes.io/zone: cn-shenzhen-e 修改调度信息label,在zone后面添加字段,促使这个pv关联的pod不可调度(例如:把原来的cn-shenzhen-e 改为 cn-shenzhen-e-nozone): # kubectl label pv d-wz9g2j5qbo37r2lamkg4 failure-domain.beta.kubernetes.io/zone=cn-shenzhen-e-nozone --overwrite persistentvolume/d-wz9g2j5qbo37r2lamkg4 labeled 重启Pod,由于修改了调度信息,pod会暂时pending: # kubectl delete pod web-0 # kubectl get pod web-0 0/1 Pending 0 27s 执行数据卷扩容命令: # kubectl patch pvc disk-ssd-web-0 -p '{"spec":{"resources":{"requests":{"storage":"30Gi"}}}}' 将pv的调度信息label改回去,促使pod启动完成(把 cn-shenzhen-e-nozone 改为起初的 cn-shenzhen-e): # kubectl label pv d-wz9g2j5qbo37r2lamkg4 failure-domain.beta.kubernetes.io/zone=cn-shenzhen-e --overwrite persistentvolume/d-wz9g2j5qbo37r2lamkg4 labeled 这时整个扩容步骤结束,可以等待一定时间(一般1分钟内)后检查扩容是否符合预期; # kubectl get pod web-0 1/1 Running 0 3m23s # kubectl get pvc disk-ssd-web-0 Bound d-wz9g2j5qbo37r2lamkg4 30Gi RWO alicloud-disk-available 17m # kubectl get pv d-wz9g2j5qbo37r2lamkg4 d-wz9g2j5qbo37r2lamkg4 30Gi RWO Delete Bound default/disk-ssd-web-0 alicloud-disk-available 17m # kubectl exec web-0 df /data /dev/vdb 30832548 45036 30771128 1% /data 2)CSI插件挂载的云盘: 向pv中添加调度labels,其value值为一个不存在对应zone的随意字符串,命令如下: # kubectl label pv d-wz9g2j5qbo37r2lamkg4 failure-domain.beta.kubernetes.io/zone=cn-nozone persistentvolume/d-wz9g2j5qbo37r2lamkg4 labeled 重启Pod,由于修改了调度信息,pod会暂时pending: # kubectl delete pod web-0 # kubectl get pod web-0 0/1 Pending 0 27s 执行数据卷扩容命令: # kubectl patch pvc disk-ssd-web-0 -p '{"spec":{"resources":{"requests":{"storage":"30Gi"}}}}' 将pv的调度信息label删除,促织pod启动完成: # kubectl label pv d-wz9g2j5qbo37r2lamkg4 failure-domain.beta.kubernetes.io/zone- persistentvolume/d-wz9g2j5qbo37r2lamkg4 labeled 这时整个扩容步骤结束,可以等待一定时间(一般1分钟内)后检查扩容是否符合预期; # kubectl get pod web-0 1/1 Running 0 3m23s # kubectl get pvc disk-ssd-web-0 Bound d-wz9g2j5qbo37r2lamkg4 30Gi RWO alicloud-disk-available 17m # kubectl get pv d-wz9g2j5qbo37r2lamkg4 d-wz9g2j5qbo37r2lamkg4 30Gi RWO Delete Bound default/disk-ssd-web-0 alicloud-disk-available 17m # kubectl exec web-0 df /data /dev/vdb 30832548 45036 30771128 1% /data
2021年01月
2020年07月
2020年01月
2019年11月
2019年10月
2019年09月
2019年08月
2019年07月
-------------------------
功能依然在添加,实现依然在优化,欢迎大家体验、反馈~~~
-------------------------
-------------------------
-------------------------
-------------------------
-------------------------
-------------------------
-------------------------
-------------------------
-------------------------
-------------------------