Kubernetes 应用存储和持久化数据卷 电脑版发表于:2021/3/16 14:49  >#Kubernetes 应用配置管理 [TOC] Volumes介绍 ------------ ### Pod Volumes <p style=" font-weight: 400; line-height: 1.5; color: #212529; -webkit-tap-highlight-color: transparent; box-sizing: border-box; padding: 0px 20px 20px 20px; border: 1px solid #e9ecef; border-left-width: .25rem; border-radius: .25rem; display: block; border-left-color: #5bc0de;"> 1. 如果一个Pod中某一个容器异常退出,被kubelet拉起如何保证之前的重要数据不丢? 2. 同一个Pod的多个容器如何共享数据? Kubernetes Volume 类型: 1. 本地存储: emptydir/hostpath... 2. 网络存储: - in-tree: awsElasticBlockStore/gcePersistentDisk/nfs ... - out-of-tree: flexvolume/csi等网络存储volume plugins 3. Projected Volume: secret/configmap/downwardAPI/serviceAccountToken 4. PVC与PV体系 </p> ### Persistent Volumes(持久卷) <p style=" font-weight: 400; line-height: 1.5; color: #212529; -webkit-tap-highlight-color: transparent; box-sizing: border-box; padding: 0px 20px 20px 20px; border: 1px solid #e9ecef; border-left-width: .25rem; border-radius: .25rem; display: block; border-left-color: #5bc0de;"> Pod中声明的volume的生命周期与Pod相同,以下常见场景: 1. Pod销毁重建(如Deployment管理的Pod镜像升级) 2. 宿主机故障迁移(如StatefulSet管理的Pod带远程volume迁移) 3. 多Pod共享同一个数据volume 4. 数据volume snapshot,resize等功能的扩展实现 **不足之处:** 使用Pod Volumes无法准确表达数据volume复用/共享语义,新功能扩展很难实现。 **优化:** 如果能将存储与计算分离,使用不同的组件(Controllers)管理存储与计算资源,解耦Pod与Volume的生命周期关联,可以很好的解决这些场景下的问题。 </p> ### PersistentVolumeClaim(PVC)设计意图 <p style=" font-weight: 400; line-height: 1.5; color: #212529; -webkit-tap-highlight-color: transparent; box-sizing: border-box; padding: 0px 20px 20px 20px; border: 1px solid #e9ecef; border-left-width: .25rem; border-radius: .25rem; display: block; border-left-color: #5bc0de;"> 有了PV,为什么又设计了PVC? 1. **职责分离**,PVC中只声明自己需要的存储size,access mode(单node独占还是多node共享?只读还是读写访问?)等业务真正关心的存储需求(不用关心存储实现细节),PV和其对应的后端存储信息则由交给cluster admin统一运维和管控,安全访问策略更容易控制。 2. **PVC简化了User对存储的需求,PV才是存储的实际信息的承载体**,通过kube-controller-manager中的PersisentVolumeController将PVC与合适的PV bound到一起,从而满足User对存储的实际需求。 3. PVC像是面向对象编程中抽象出来的接口,PV是接口对应的实现。 </p> ### Static Volume Provisioning  <p style=" font-weight: 400; line-height: 1.5; color: #212529; -webkit-tap-highlight-color: transparent; box-sizing: border-box; padding: 0px 20px 20px 20px; border: 1px solid #e9ecef; border-left-width: .25rem; border-radius: .25rem; display: block; border-left-color: #5bc0de;"> **Static Volume Provisioning的不足:** Cluster Admin需要提前规划或预测存储需求,而User的需求是多样化的,很容易导致User提交的PVC找不到合适的PV。 (举例我只需要20G,但你告诉我只有50G和100G的PV,这样就造成了资源浪费) **更好的方式:** Cluster Admin只创建不同类型存储的模板,User在PVC中指定使用哪种存储模板以及自己需要的大小、访问方式等参数,然后K8s自动生成相应的PV对象。 </p> ### Dynamic Volume Provisioning  <p style=" font-weight: 400; line-height: 1.5; color: #212529; -webkit-tap-highlight-color: transparent; box-sizing: border-box; padding: 0px 20px 20px 20px; border: 1px solid #e9ecef; border-left-width: .25rem; border-radius: .25rem; display: block; border-left-color: #5bc0de;"> 这里的StorageClass就是前文所说的创建PV的模板,**它包含了创建某种具体类型的PV所需要的参数信息**,User无需关心这些PV的细节。 而K8s则会结合PVC和SC两者的信息动态创建PV对象 </p> ### Pod Volumes使用   <p style=" font-weight: 400; line-height: 1.5; color: #212529; -webkit-tap-highlight-color: transparent; box-sizing: border-box; padding: 0px 20px 20px 20px; border: 1px solid #e9ecef; border-left-width: .25rem; border-radius: .25rem; display: block; border-left-color: #5bc0de;"> .spec.volumes 声明pod的volumes信息 .spec.containers.volumeMounts声明container如何使用pod的volumes 多个container共享同一个volume时,可以通过.spec.containers.volumeMounts.subPath隔离不同容器在同个volume上数据存储的路径 </p> ### Static Volume Provisioning <p style=" font-weight: 400; line-height: 1.5; color: #212529; -webkit-tap-highlight-color: transparent; box-sizing: border-box; padding: 0px 20px 20px 20px; border: 1px solid #e9ecef; border-left-width: .25rem; border-radius: .25rem; display: block; border-left-color: #5bc0de;"> 以使用阿里云文件存储(NAS)为例: Cluster Admin: 1. 通过阿里云文件存储控制台,创建NAS文件系统和添加挂载点。 2. 创建PV对象,将NAS文件系统大小,挂载点,以及PV的access mode,reclaim policy等信息添加到PV对象中。 User: 1. 创建PVC对象,声明存储需求。 2. 创建应员工pod并通过.spec.volumes中通过PVC声明volume,通过.spec.containers.volumeMounts声明container挂载使用该volume。 </p> >系统管理员预先创建PV ```yaml apiVersion: v1 kind: PersistentVolume metadata: name: pv-nas labels: alicloud-pvname: pv-nas spec: capacity: storage: 5Gi # 该volume的总容量大小 accessModes: - ReadWriteMany # 该volume可以被多个node上的pod挂载使用且都具有读写权限 persisentVolumeReclaimPolicy: Retain # 该volume使用后被release之后的回收策略 csi: driver: nasplugin.csi.alibabacloud.com # 指定由什么volume plugin来挂载该volume(需要提前在node上部署) volumeHandle: pv-nas volumeAttributes: server: "2564f49129-ysu87.cn-shenzhen.nas.aliyuncs.com" path: "/csi" mountOptions: - nolock,tcp,noresvport - vers=3 ``` | 参数 | 描述 | | ------------ | ------------ | | driver | 定义驱动类型。本例中取值为`nasplugin.csi.alibabacloud.com`,表示使用阿里云NAS CSI插件。 | | volumeHandle | 配置PV的名称。 | | server | NAS挂载点。 | | path | 挂载子目录,极速NAS需要以/share开头 | | vers | 挂载NAS数据卷的NFS协议版本号,推荐使用v3;极速类型NAS只支持v3。 | | AccessModes | PV访问策略控制列表,必须同PVC的访问策略控制列表匹配才能绑定(bound)<br/> - ReadWriteOnce只允许单node访问 <br/> - ReadOnlyMany允许多个node只读访问 <br/> - ReadWriteMany允许多node读写访问 <br/> 一个PV可以设置多个访问策略,PVC与PV bound时,PV Controller会优先找到 AccessModes 列表最短并且匹配PVC AccessModes 列表的 PV 集合,然后从该集合中找到Capacity最小且符合PVC size 需求的PV对象 | | PersistentVolumeReclaimPolicy | PV被release之后(与之bound的PVC被删除)回收再利用策略 <br/> - Recycle <br/> - Delete: volume被release之后直接delete,需要volume plugin支持 <br/> - Retain: 默认策略,由系统管理员来手动管理该volume | | StorageClassName | PVC可通过该字段找到相同值的PV(静态provisioning),也可通过字段对应的storageclass从而动态provisioning新PV对象 | | NodeAffinity | 限制可以访问该volume的nodes,对使用该volume的pod的调度有影响(因为使用该volume的pod只能调度访问该PV的node上才能正常访问) | >用户创建PVC对象 ```yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: pvc-nas spec: accessModes: - ReadWriteMany resources: requests: storage: 5Gi selector: matchLabels: alicloud-pvname: pv-nas ``` >创建应用示例 ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-nas labels: app: nginx spec: selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80 volumeMounts: - name: pv-nas mountPath: "/data" volumes: - name: pv-nas persistentVolumeClaim: claimName: pvc-nas ``` ### Dynamic Volume Provisioning ```bash # 创建storage-class-topology.yaml文件。 vim storage-class-topology.yaml ``` ```yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: alicloud-disk-topology-ssd provisioner: diskplugin.csi.alibabacloud.com parameters: type: cloud_ssd reclaimPolicy: Retain volumeBindingMode: WaitForFirstConsumer allowVolumeExpansion: true ``` | 参数 | 描述 | | ------------ | ------------ | | provisioner | 配置为diskplugin.csi.alibabacloud.com。标识StorageClass使用阿里云云盘provisioner插件创建。 | | type | 标识云盘类型,支持cloud_efficiency、cloud_ssd、cloud_essd、available四种参数,其中available会对ESSD、SSD、高效依次尝试创建,直到创建成功。 | | reclaimPolicy | 云盘的回收策略,默认为Delete,支持Retain。<br/>Delete模式:删除PVC的时候,PV和云盘会一起删除。<br/> Retain模式:删除PVC的时候,PV和云盘数据不会被删除,需要您手动删除。<br/> 如果数据安全性要求高,推荐使用Retain方式以免误删数据。 | | encrypted | 可选参数,标识创建的云盘是否加密。默认情况是false,创建的云盘不加密。 | | volumeBindingMode | WaitForFirstConsumer时表示使用延迟绑定,即调度器先调度pod,并根据pod的可用区信息创建云盘。 | | allowVolumeExpansion | 配置为true时,可以实现云盘的自动扩容。 | | performanceLevel | 值为PL1、PL2、或PL3。更多信息,请参见容量范围与性能级别的关系。 | ```bash # 执行以下命令,创建StorageClass。 kubectl apply -f storage-class-csi.yaml ``` >创建 PVC 以下模板为创建动态卷PV的示例YAML。 ```yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: disk-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 25Gi storageClassName: alicloud-disk-ssd ``` tn>注意:storage:定义申请云盘大小,最小为20GiB。 >创建应用 ```yaml apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: selector: matchLabels: app: nginx serviceName: "nginx" template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 name: web volumeMounts: - name: pvc-disk mountPath: /data volumes: - name: pvc-disk persistentVolumeClaim: claimName: disk-pvc ``` tn>更多请参考:https://help.aliyun.com/document_detail/134859.html?spm=a2c4g.11186623.6.817.65287567mk0TJz ### PV状态流转  <p style=" font-weight: 400; line-height: 1.5; color: #212529; -webkit-tap-highlight-color: transparent; box-sizing: border-box; padding: 0px 20px 20px 20px; border: 1px solid #e9ecef; border-left-width: .25rem; border-radius: .25rem; display: block; border-left-color: #5bc0de;"> 达到released状态的PV无法根据Reclaim Policy回到available状态而再次bound新的PVC。此时,如果想复用原来PV对应的存储中的数据,只有两种方式: 1. 复用old PV中记录的存储信息新建PV对象。 2. 直接从PVC对象复用,即不unbound PVC和PV(即:StatefulSet处理存储状态的原理)。 </p>