关于PV、PVC、StorageClass ,这篇文章讲的不错:https://www.cnblogs.com/rexcheny/p/10925464.html
容器的设计理念就是一次性,也就是容器销毁后容器里的所有数据都会销毁,所以需要将容器里面需要保留的数据挂载到持久性存储中,这里就涉及到三个概念:PV、PVC、StorageClass 。
HostPath
当使用docker创建container的时候,一般都是加参数 -v 挂载宿主机的目录到container里面,k8s 也可以实现该功能,先讲解一下 挂载到宿主机目录的方法。
创建一个deployment资源配置文件,挂载到宿主机目录:
[root@ylserver10686071 ~]# cat volumes001.yml apiVersion: apps/v1 kind: Deployment metadata: name: volumes001 namespace: prod spec: replicas: 1 selector: matchLabels: k8s-app: volumes001 template: metadata: labels: k8s-app: volumes001 spec: containers: - name: nginx image: nginx:1.21 volumeMounts: - mountPath: /usr/share/nginx/html/ name: html volumes: - name: html hostPath: path: /data/nginx/html/ type: DirectoryOrCreate
- volumeMounts 挂载到container 指定目录的相关配置,根据name来匹配volumes对象的下的name,据此来找到挂载对象
- volumes 声明挂载对象
- hostPath 存储类型
- type: DirectoryOrCreate 如果宿主机路径不存在则创造该路径,当值为Directory 是,宿主机必须有该目录,否则会导致pod创建失败
创建deployment资源,查看pod在哪台Node上运行:
[root@ylserver10686071 ~]# kubectl apply -f volumes001.yml deployment.apps/volumes001 created [root@ylserver10686071 ~]# kubectl get pods -n prod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES volumes001-66767f866f-rc5qk 1/1 Running 0 21s 10.233.72.59 ylserver10686073 <none> <none> [root@ylserver10686071 ~]#
在ylserver10686071 Node上查看目录是否创建,然后到Pod运行的节点上查看目录是否创建:
[root@ylserver10686071 ~]# ll /data/nginx/html/ ls: cannot access /data/nginx/html/: No such file or directory [root@ylserver10686071 ~]# [root@ylserver10686073 ~]# ll /data/nginx/html/ total 0 [root@ylserver10686073 ~]#
给挂载目录创建文件,验证是否挂载到Pod里面:
[root@ylserver10686073 ~]# echo "Hello K8S" > /data/nginx/html/index.html [root@ylserver10686073 ~]# curl http://10.233.72.59/index.html Hello K8S [root@ylserver10686073 ~]#
PV
上面的实验中宿主机挂载的目录只有在 Pod 运行的 Node 上才会创建,换言之,Pod要挂载的目录必须跟Node做绑定,这会增加运维的难度,也失去k8s的故障转移特性。
针对这个问题,可以使用存储券解决,这里就要引入一个概念:PV。
PV全称叫做Persistent Volume,持久化存储卷。它是用来描述或者说用来定义一个存储卷的,这个通常都是有运维或者数据存储工程师来定义。本节使用NFS来作为存储端,NFS搭建这里不做讲解。
先创建一个PV资源配置文件:
[root@ylserver10686071 ~]# cat pv001.yml apiVersion: v1 kind: PersistentVolume ###PV资源不属于任何命名空间,属于集群级别的 ###kubectl api-resources --namespaced=true 命令可以查看哪些资源属于命名空间 metadata: name: pv001 labels: ###Label可以不定义 name: pv001 storetype: nfs spec: ###定义PV资源规格 storageClassName: normal accessModes: ###设置访问模型 - ReadWriteMany - ReadWriteOnce - ReadOnlyMany capacity: ###设置存储空间大小 storage: 500Mi persistentVolumeReclaimPolicy: Retain ###回收策略 nfs: path: /data/nfs/k8s/ server: 10.68.60.193 [root@ylserver10686071 ~]#
accessModes 有3种属性值:
- ReadWriteMany 多路读写,卷能被集群多个节点挂载并读写
- ReadWriteOnce 单路读写,卷只能被单一集群节点挂载读写
- ReadOnlyMany 多路只读,卷能被多个集群节点挂载且只能读
persistentVolumeReclaimPolicy 回收策略也有3种属性值:
- Retain
当删除与之绑定的PVC时候,这个PV被标记为released(PVC与PV解绑但还没有执行回收策略)且之前的数据依然保存在该PV上,但是该PV不可用,需要手动来处理这些数据并删除该PV
这种方式是最常用的,可以避免误删pvc或者pv而造成数据的丢失
- Delete 删除存储资源,AWS EBS, GCE PD, Azure Disk, and Cinder volumes支持这种方式
- Recycle 这个在1.14版本中以及被废弃,取而代之的是推荐使用动态存储供给策略,它的功能是当删除与该PV关联的PVC时,自动删除该PV中的所有数据
创建完PV后,PV会有几种状态:
- Available(可用) 块空闲资源还没有被任何声明绑定
- Bound(已绑定) 卷已经被声明绑定
- Released(已释放) 声明被删除,但是资源还未被集群重新声明
- Failed(失败) 该卷的自动回收失败
创建PV资源,并查看PV信息:
[root@ylserver10686071 ~]# kubectl apply -f pv001.yml persistentvolume/pv001 created [root@ylserver10686071 ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv001 500Mi RWO,ROX,RWX Retain Available normal 6s
PVC
PV只是定义了一个存储卷实体,还需要一层抽象的接口使其与POD关联,这层抽象的接口就是PVC,全称 Persistent Volume Claim,也就是持久化存储声明。开发人员使用这个来描述该容器需要一个什么存储。
创建一个PVC资源配置文件:
[root@ylserver10686071 ~]# cat pvc001.yml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc001 namespace: prod ###PVC资源属于命名空间级别 labels: ###Label可以不定义 name: pvc001 storetype: nfs capacity: 500Mi spec: storageClassName: normal accessModes: ###PVC也需要定义访问模式,不过它的模式一定是和现有PV相同或者是它的子集,否则匹配不到PV - ReadWriteMany resources: ###定义资源要求PV满足这个PVC的要求才会被匹配到 requests: storage: 500Mi # 定义要求有多大空间
创建PVC资源,查看PVC资源和PV资源绑定情况,可以看到PV和PVC已经实现绑定:
[root@ylserver10686071 ~]# kubectl apply -f pvc001.yml persistentvolumeclaim/pvc001 created [root@ylserver10686071 ~]# kubectl get pvc -n prod NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE pvc001 Bound pv001 500Mi RWO,ROX,RWX normal 15s [root@ylserver10686071 ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv001 500Mi RWO,ROX,RWX Retain Bound prod/pvc001 normal 62m [root@ylserver10686071 ~]#
PVC是如何跟PVC绑定的呢,有以下几个原则:
- PV和PVC中的spec关键字段要匹配,比如存储(storage)大小
- PVC的访问模式一定是和现有PV相同或者是它的子集,否则匹配不到PV
- PV和PVC中的 StorageClass Name字段必须一致,StorageClass后面会讲到
- Label 标签在这里只做描述作用,跟 PV 和 PVC 的绑定没有任何关系
看到这里,回想总结一下就会发现 k8s 里面会通过定义一层抽象概念来管理实体或者连接实体,类似于 Pod 和 Container , PVC 和 PV ;对象和对象的匹配设计原理也是一直,例如 deployment匹配replicaset通过matchLabels ,PV 和 PVC通过 StorageClass Name以及 resources等,即对象与对象之间通过匹配关系进行绑定。
更新上面的deployment资源配置文件,使其使用创建好的PVC资源:
[root@ylserver10686071 ~]# cat volumes001.yml apiVersion: apps/v1 kind: Deployment metadata: name: volumes001 namespace: prod ###要和指定的PVC同一个命名空间 spec: replicas: 1 selector: matchLabels: k8s-app: volumes001 template: metadata: labels: k8s-app: volumes001 spec: containers: - name: nginx image: nginx:1.21 volumeMounts: ###container的挂载声明没有改变 - mountPath: /usr/share/nginx/html/ name: html volumes: ###依然使用volumes声明挂载卷 - name: html persistentVolumeClaim: ###指定PVC claimName: pvc001
更新资源deployment资源配置文件,查看pod关于volumes相关信息:
[root@ylserver10686071 ~]# kubectl apply -f volumes001.yml deployment.apps/volumes001 configured [root@ylserver10686071 ~]# kubectl describe pod volumes001 -n prod|grep -5 Volumes Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: html: Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) ClaimName: pvc001 ReadOnly: false default-token-lx75g: [root@ylserver10686071 ~]#
写一个文件到NFS挂载目录中,测试一下效果:
[root@ylserver106860193 ~]# echo "K8S PV" > /data/nfs/k8s/index.html [root@ylserver10686071 ~]# kubectl get pods -n prod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES volumes001-55f5bb9585-nx9xd 1/1 Running 0 11m 10.233.72.60 ylserver10686073 <none> <none> [root@ylserver10686071 ~]# curl http://10.233.72.60 K8S PV [root@ylserver10686071 ~]#
给原来的Node打上Taint,重启deployment资源,查看Pod在其他Node上运行时,原来的挂载文件是否还存在:
[root@ylserver10686071 ~]# kubectl taint node ylserver10686073 web=nginx:NoSchedule node/ylserver10686073 tainted [root@ylserver10686071 ~]# kubectl rollout restart deployment volumes001 -n prod deployment.apps/volumes001 restarted [root@ylserver10686071 ~]# kubectl get pods -n prod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES volumes001-7fcd68c5b8-hcwcf 1/1 Running 0 30s 10.233.67.54 ylserver10686072 <none> <none> [root@ylserver10686071 ~]#
验证一下,可以看到挂载的文件依然存在:
[root@ylserver10686071 ~]# curl http://10.233.67.54 K8S PV [root@ylserver10686071 ~]#
PV回收时需要删除PVC,删除PVC需要先删除关联的Pod,验证一下:
[root@ylserver10686071 ~]# kubectl delete deployments volumes001 -n prod deployment.apps "volumes001" deleted [root@ylserver10686071 ~]# kubectl delete pvc pvc001 -n prod persistentvolumeclaim "pvc001" deleted [root@ylserver10686071 ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv001 500Mi RWO,ROX,RWX Retain Released prod/pvc001 normal 18m [root@ylserver10686071 ~]#
可以看到删除pvc后,pv处于Released状态,此时pv只能删除重新创建才能继续使用,验证一下:
[root@ylserver10686071 ~]# kubectl apply -f pvc001.yml persistentvolumeclaim/pvc001 created [root@ylserver10686071 ~]# kubectl get pvc -n prod NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE pvc001 Pending normal 17s [root@ylserver10686071 ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv001 500Mi RWO,ROX,RWX Retain Released prod/pvc001 normal 19m
删除PV,因为回收策略是Retain,所以NFS端的数据依然存在,验证一下:
[root@ylserver10686071 ~]# kubectl delete pv pv001 persistentvolume "pv001" deleted [root@ylserver106860193 ~]# cat /data/nfs/k8s/index.html K8S PV [root@ylserver106860193 ~]#
重新创建PV,PVC就可以继续绑定:
[root@ylserver10686071 ~]# kubectl apply -f pv001.yml persistentvolume/pv001 created [root@ylserver10686071 ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv001 500Mi RWO,ROX,RWX Retain Bound prod/pvc001 normal 18s [root@ylserver10686071 ~]# kubectl get pvc -n prod NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE pvc001 Bound pv001 500Mi RWO,ROX,RWX normal 4m11s [root@ylserver10686071 ~]#
StorageClass
PV是运维人员创建的,开发操作PVC,一个PV只能被一个PVC绑定,如果这些PV都需要运维手动来处理将会是一件十分繁琐的事情,所以就有了动态供给概念,也就是Dynamic Provisioning。而我们上面的创建的PV都是静态供给方式,也就是Static Provisioning。而动态供给的关键就是StorageClass,它的作用就是创建PV模板。
创建StorageClass里面需要定义PV属性比如存储类型、大小等;另外创建这种PV需要用到存储插件。最终效果是,用户提交PVC,里面指定存储类型,如果符合我们定义的StorageClass,则会为其自动创建PV并进行绑定。
Kubernetes本身支持的动态PV创建不包括nfs,所以需要使用额外插件实现。nfs-client
GitHub的部署里面使用的镜像地址国内无法下载,这里修改了一下,用国内的镜像地址,这里使用helm部署nfs插件,先下载 chart文件: https://www.mediafire.com/file/pzi7skcwdm0v64a/nfs-subdir-external-provisioner.tar.gz/file
下载文件后,解压到 /opt 目录下:
tar -zxvf nfs-subdir-external-provisioner.tar.gz -C /opt/
使用helm部署 nfs-client插件:
[root@ylserver10686071 ~]# cd /opt/nfs-subdir-external-provisioner/ [root@ylserver10686071 nfs-subdir-external-provisioner]# helm install nfs-subdir-external-provisioner --namespace kube-system . --set nfs.server=10.68.60.193 --set nfs.path=/data/nfs/k8s/ NAME: nfs-subdir-external-provisioner LAST DEPLOYED: Fri Jul 30 20:36:05 2021 NAMESPACE: prod STATUS: deployed REVISION: 1 TEST SUITE: None [root@ylserver10686071 nfs-subdir-external-provisioner]#
查看已经创建的 StorageClass,StorageClass属于集群级别:
[root@ylserver10686071 nfs-subdir-external-provisioner]# kubectl get storageclass NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE nfs-client cluster.local/nfs-subdir-external-provisioner Delete Immediate true 48s [root@ylserver10686071 nfs-subdir-external-provisioner]#
创建PVC资源配置文件,使用nfs-client StorageClass:
[root@ylserver10686071 ~]# cat pvc002.yml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc002 namespace: default labels: name: pvc002 storetype: nfs capacity: 300Mi spec: storageClassName: nfs-client accessModes: - ReadWriteMany resources: requests: storage: 300Mi [root@ylserver10686071 ~]#
创建PVC资源,可以看到PV已经自动创建:
[root@ylserver10686071 ~]# kubectl apply -f pvc002.yml persistentvolumeclaim/pvc002 created [root@ylserver10686071 ~]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE pvc002 Bound pvc-13f05a23-0fce-429f-9803-db4ec3dd6465 300Mi RWX nfs-client 5m [root@ylserver10686071 ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-13f05a23-0fce-429f-9803-db4ec3dd6465 300Mi RWX Delete Bound default/pvc002 nfs-client 5m3s [root@ylserver10686071 ~]#
NFS服务端可以看到创建的PV对应存储目录:
[root@ylserver106860193 ~]# ll /data/nfs/k8s/ total 4 drwxrwxrwx 2 root root 6 Jul 31 03:17 default-pvc002-pvc-13f05a23-0fce-429f-9803-db4ec3dd6465 -rw-r--r-- 1 root root 7 Jul 30 03:32 index.html [root@ylserver106860193 ~]#
现在往PV对应的目录写入文件,然后删除PVC,看NFS端PV对应的存储目录是否存储:
[root@ylserver106860193 ~]# echo "StorageClass" > /data/nfs/k8s/default-pvc002-pvc-13f05a23-0fce-429f-9803-db4ec3dd6465/index.html [root@ylserver106860193 ~]#
开始删除PVC,PV也会自动删除
[root@ylserver10686071 ~]# kubectl delete pvc pvc002 persistentvolumeclaim "pvc002" deleted [root@ylserver10686071 ~]# kubectl get pvc No resources found in default namespace. [root@ylserver10686071 ~]# kubectl get pv No resources found [root@ylserver10686071 ~]#
查看NFS服务端目录,可以看到文件依然保留,目录在原有名称上添加了archived-:
[root@ylserver106860193 ~]# cat /data/nfs/k8s/archived-default-pvc002-pvc-13f05a23-0fce-429f-9803-db4ec3dd6465/index.html StorageClass [root@ylserver106860193 ~]#
其实跟StorageClass回收策略,涉及两个参数,文件 /opt/nfs-subdir-external-provisioner/values.yaml里可以修改,然后helm update 即可:
archiveOnDelete: true reclaimPolicy: Delete
- archiveOnDelete 当设置为 true 时,在删除PVC后,会对 PV 对应的存储目录进行备份
- reclaimPolicy 回收策略,上面有讲解过,Delete策略就是删除PVC时自动删除绑定的PV
StatefulSet StorageClass
当使用 StatefulSet 控制器创建Pod的时候,可以在 StatefulSet 配置文件里面直接声明 PV的创建,创建一个StatefulSet 资源配置文件:
[root@ylserver10686071 ~]# cat volumes002.yml apiVersion: apps/v1 kind: StatefulSet metadata: name: volumes002 namespace: prod spec: serviceName: volumes002-svc selector: matchLabels: k8s-app: volumes002 replicas: 3 template: metadata: labels: k8s-app: volumes002 spec: containers: - name: nginx image: nginx:1.21 volumeMounts: - mountPath: /usr/share/nginx/html/ name: html volumeClaimTemplates: ###这里声明PV资源 - metadata: ###这里声明具体PV信息,数组类型,可以声明多个 name: html annotations: volume.beta.kubernetes.io/storage-class: nfs-client spec: accessModes: - ReadWriteMany resources: requests: storage: 200Mi
创建 StatefulSet 资源,查看PV创建信息:
[root@ylserver10686071 ~]# kubectl apply -f volumes002.yml statefulset.apps/volumes002 created [root@ylserver10686071 ~]# kubectl get pvc -n prod NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE html-volumes002-0 Bound pvc-216d73b5-b4b6-4103-a163-f67c235b8cda 200Mi RWX nfs-client 38s html-volumes002-1 Bound pvc-17a767a7-282a-4fc4-8050-72ddc5829d86 200Mi RWX nfs-client 22s html-volumes002-2 Bound pvc-40409054-f6a8-46f8-9c0a-96979de34249 200Mi RWX nfs-client 5s [root@ylserver10686071 ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-17a767a7-282a-4fc4-8050-72ddc5829d86 200Mi RWX Delete Bound prod/html-volumes002-1 nfs-client 26s pvc-216d73b5-b4b6-4103-a163-f67c235b8cda 200Mi RWX Delete Bound prod/html-volumes002-0 nfs-client 42s pvc-40409054-f6a8-46f8-9c0a-96979de34249 200Mi RWX Delete Bound prod/html-volumes002-2 nfs-client 9s [root@ylserver10686071 ~]#
Local PV
PV的后端存储也支持本地宿主机目录,类似于hostPath,跟hostPath 同样存在一个问题,通常先创建PV,然后创建PVC,这时候如果两者匹配那么系统会自动进行绑定,哪怕是动态PV创建,也是先调度POD到任意一个节点,然后根据PVC来进行创建PV然后进行绑定最后挂载到POD中,可是本地持久化存储有一个问题就是这种PV必须要先准备好,而且不一定集群所有节点都有这种PV,如果POD随意调度肯定不行,如何保证POD一定会被调度到有PV的节点上呢?这时候就需要在PV中声明节点亲和,且POD被调度的时候还要考虑卷的分布情况。
编写PV资源配置文件:
[root@ylserver10686071 ~]# cat pv002.yml apiVersion: v1 kind: PersistentVolume metadata: name: pv002 labels: name: pv002 storetype: Local spec: storageClassName: local-storage accessModes: - ReadWriteMany - ReadWriteOnce - ReadOnlyMany capacity: storage: 5000Mi persistentVolumeReclaimPolicy: Retain local: ### local类型 path: /data/pv002 ###宿主机目录 nodeAffinity: ###节点亲和性设置 required: nodeSelectorTerms: - matchExpressions: - key: database operator: In values: - mysql
编写存储类配置文件:
[root@ylserver10686071 ~]# cat storageclass002.yml kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: local-storage provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer
这里的volumeBindingMode: WaitForFirstConsumer
很关键,意思就是延迟绑定,当有符合PVC要求的PV不立即绑定。因为POD使用PVC,而绑定之后,POD被调度到其他节点,显然其他节点很有可能没有那个PV所以POD就挂起了,另外就算该节点有合适的PV,而POD被设置成不能运行在该节点,这时候就没法了,延迟绑定的好处是,POD的调度要参考卷的分布。当开始调度POD的时候看看它要求的LPV在哪里,然后就调度到该节点,然后进行PVC的绑定,最后在挂载到POD中,这样就保证了POD所在的节点就一定是LPV所在的节点。所以让PVC延迟绑定,就是等到使用这个PVC的POD出现在调度器上之后(真正被调度之前),然后根据综合评估再来绑定这个PVC。
编写PVC配置文件:
[root@ylserver10686071 ~]# cat pvc002.yml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc002 namespace: prod labels: name: pvc002 storetype: local capacity: 5000Mi spec: storageClassName: local-storage accessModes: - ReadWriteOnce resources: requests: storage: 5000Mi
创建PV、StorageClass、PVC资源,查看PVC绑定情况:
[root@ylserver10686071 ~]# kubectl apply -f pv002.yml persistentvolume/pv002 created [root@ylserver10686071 ~]# kubectl apply -f storageclass002.yml storageclass.storage.k8s.io/local-storage created [root@ylserver10686071 ~]# kubectl apply -f pvc002.yml persistentvolumeclaim/pvc002 created [root@ylserver10686071 ~]# kubectl get pvc -n prod|grep pvc002 pvc002 Pending local-storage 17s
可以看到PVC处于Pending状态,这也就是延迟绑定,因为此时还没有POD。
创建 StatefulSet 资源配置文件:
[root@ylserver10686071 ~]# cat volumes003.yml apiVersion: apps/v1 kind: StatefulSet metadata: name: volumes003 namespace: prod spec: serviceName: volumes003-svc replicas: 1 selector: matchLabels: k8s-app: volumes003 template: metadata: labels: k8s-app: volumes003 spec: containers: - name: mysql env: - name: "MYSQL_DATABASE" value: "admin" - name: "MYSQL_USER" value: "admin" - name: "MYSQL_ROOT_PASSWORD" value: "123456" - name: "MYSQL_PASSWORD" value: "123456" image: mysql:5.7 imagePullPolicy: IfNotPresent ports: - containerPort: 3306 name: mysql protocol: TCP volumeMounts: - mountPath: /var/lib/mysql name: mysql-data volumes: - name: mysql-data persistentVolumeClaim: claimName: pvc002
先创建挂载目录(目录必须先手动创建),接着给Node打上标签,然后创建StatefulSet,查看Pod运行情况:
[root@ylserver10686073 ~]# mkdir /data/pv002 [root@ylserver10686071 ~]# kubectl label node ylserver10686073 database=mysql node/ylserver10686073 labeled [root@ylserver10686071 ~]# kubectl apply -f volumes003.yml statefulset.apps/volumes003 created [root@ylserver10686071 ~]# kubectl get pods -n prod -o wide|grep volumes003 volumes003-0 1/1 Running 0 23s 10.233.72.71 ylserver10686073 <none> <none> [root@ylserver10686071 ~]#
Pod运行的 Node 节点上查看挂载目录内容:
[root@ylserver10686073 ~]# ll /data/pv002/ total 188484 -rw-r-----. 1 polkitd input 56 Jul 31 17:31 auto.cnf -rw-------. 1 polkitd input 1676 Jul 31 17:31 ca-key.pem -rw-r--r--. 1 polkitd input 1112 Jul 31 17:31 ca.pem -rw-r--r--. 1 polkitd input 1112 Jul 31 17:31 client-cert.pem -rw-------. 1 polkitd input 1680 Jul 31 17:31 client-key.pem -rw-r-----. 1 polkitd input 436 Jul 31 17:31 ib_buffer_pool -rw-r-----. 1 polkitd input 79691776 Jul 31 17:31 ibdata1 -rw-r-----. 1 polkitd input 50331648 Jul 31 17:31 ib_logfile0 -rw-r-----. 1 polkitd input 50331648 Jul 31 17:30 ib_logfile1 -rw-r-----. 1 polkitd input 12582912 Jul 31 17:31 ibtmp1 drwxr-x---. 2 polkitd input 4096 Jul 31 17:31 mysql drwxr-x---. 2 polkitd input 8192 Jul 31 17:31 performance_schema -rw-------. 1 polkitd input 1676 Jul 31 17:31 private_key.pem -rw-r--r--. 1 polkitd input 452 Jul 31 17:31 public_key.pem -rw-r--r--. 1 polkitd input 1112 Jul 31 17:31 server-cert.pem -rw-------. 1 polkitd input 1680 Jul 31 17:31 server-key.pem drwxr-x---. 2 polkitd input 8192 Jul 31 17:31 sys [root@ylserver10686073 ~]#
这个POD被调度到Node ylserver10686073上,因为PV就在Node ylserver10686073上,这时候删除这个POD,然后在重建该POD,那么依然会被调度到Node ylserver10686073上。
总结一下:
- 根据 Container 一次性原则,Container销毁时,里面的数据也会销毁,所以需要保存的数据需要挂载到持久化存储中;
- Container 保存数据数据可以选择直接挂载宿主机目录,即 挂载卷类型为 hostPath,或者使用 PVC 卷进行挂载;
- PVC 是一层抽象接口,绑定的 PV 实体存储后端类型可以根据需求自定义,可以是本地宿主机目录, NFS,AWS EBS, GCE PD, Azure Disk, and Cinder volumes等等;
- PVC 绑定 PV 是根据 storage 大小、accessModes类型、以及相同的 storageClassName来绑定,其中 storage 大小、accessModes类型 必须是 PV的子集;
- StatefulSet 类型的资源可以在模板里面定义PVC资源,而不需要单独配置PVC文件;
- StorageClass 动态持久化存储可以由PVC资源自动生成PV资源,减少了维护成本