12.PV、PVC、StrageClass、本地持久存储
介绍StorageClass安装的一篇文章
https://huaweicloud.csdn.net/638db4d4dacf622b8df8cc0a.html#%E4%B8%80%EF%BC%9AKubeSphere%E6%A6%82%E8%BF%B0
一、PV
PresistentVolume持久卷:
是集群资源,不能指定namespace。
-
- 定义PV容量
- PV访问权限
- readWriteOnce:可读可写,只能被单个节点发发,支持被单个pod挂载,replicas为=1
- readOnlyMany:以只读方式被多个pod挂载,replicas可以>1
- readWriteMany:以读写方式被多个pod共享,replicas可以>1
- pv连接的存储后端地址
PV使用nfs:
1.mount nfs到主机,再mount到pod里。
PV卷阶段状态
Available:未被claim使用。
Bound:已绑定到claim。
Released:claim被删除,卷处于释放状态,未被集群回收。
Failed:卷自动回收失败。
二、PVC
PresistenVolumeClaim
消耗/使用pv资源
由用户进行存储的请求。类似于pod。声明请求特定的大小和访问模式。
pvc与pv是一一对应的。
PVC通过pv StorageClass-name绑定PV
PV与PVC的绑定原则
PV和PVC中的spec关键字段要匹配,比如存储(storage)大小。
PV和PVC中的storageClassName字段必须一致。
三、生命周期
PV是集群中的资源。PVC是对这些资源的请求。
Provisioning----->Binding----->Using----->Releasing----->Recycling
releasing:用户删除pvc回收存储资源,pv将变成 “released” 状态。保留着之前的数据,这些数据需要依策略来处理,否则这些PV无法被其他pvc使用。
Recycling:三种策略
Retain:允许人工处理保留的数据。
Recycle:将删除pv和外部关联的存储资源,需要插件支持。删除pvc时同时清除pv中的数据,pv将变成available状态。 在1.14版中已弃用,推荐使用动态存储供给策略:删除与该PV关联的PVC时,自动删除该PV中的所有数屈打成招
Delete:将执行清除操作,之后可以被新的pvc使用,需要插件支持。NFS不支持
注:目前只有NFS和HostPath类型卷支持Recycle,AWS EBS、GCE PD、Azure Disk和Cinder支持Delete。
kubectl delete pv pv-name ##Retain回收
四、例:
NFS
4.1准备nfs服务器
cd /data/volumes/ ##创建nfs服务器上的共享卷 mkdir v{1,2,3,4,5} echo "<h1>NFS stor 01</h1>" >v1/indes.html ....... echo "<h1>NFS stor 05</h1>" >v5/indes.html vim /etc/exports ##配置nfs共享内容 /data/volumes/v1 10.146.16.0/24(rw,no_root_squash) ...... /data/volumes/v5 10.146.16.0/24(rw,no_root_squash) exportfs -arv ##使nfs生效 showmount -e ##检查
4.2.在master上创建pv
vim pv-damo.yaml
apiVersion: v1 kind: PersistentVolume metadata: name: pv001 labels: name: pv001 spec:
persistentVolumeReclaimPolicy: Delete ##设置回收策略
nfs: path: /data/volumes/v1 server: nfs accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity: storage: 2Gi --- apiVersion: v1 kind: PersistentVolume metadata: name: pv002 labels: name: pv002 spec: nfs: path: /data/volumes/v2 server: nfs accessModes: ["ReadWriteOnce"] capacity: storage: 5Gi --- apiVersion: v1 kind: PersistentVolume metadata: name: pv003 labels: name: pv003 spec: nfs: path: /data/volumes/v3 server: nfs accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity: storage: 20Gi --- apiVersion: v1 kind: PersistentVolume metadata: name: pv004 labels: name: pv004 spec:
storageClassName: nfs ##PVC用storageClassName与PV绑定
nfs: path: /data/volumes/v4 server: nfs accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity: storage: 10Gi --- apiVersion: v1 kind: PersistentVolume metadata: name: pv005 labels: name: pv005 spec: nfs: path: /data/volumes/v5 server: nfs accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity: storage: 15Gi
kubectl apply -f pv-damo.yaml
kubectl get pv
4.3.创建PVC,绑定PV
创建一个pvc,需要6G存储,v1、v2、v3都不符合
#vim vol-pvc-demo.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc
namespace: default
spec:
storageClassName: nfs ##PVC用storageClassName与PV绑定
accessModes: ["ReadWriteMany"] ##它的模式必须与PV中定义的相匹配或是PV中定义的子集。 resources: ##定义资源要求PV满足这个PVC的要求才会被匹配到。 requests: storage: 6Gi #定义要求的空间大小 --- apiVersion: v1 kind: Pod metadata: name: vol-pvc namespace: default spec: volumes: - name: html persistentVolumeClaim: claimName: mypvc containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: - name: html mountPath: /usr/share/nginx/html/
kubectl apply -f vol-pvc-demo.yaml
kubectl get pvc
kubectl get pv
kubectl get pods -o wide



在work上:挂载在work node上的目录

/var/lib/kubelet/pods/<Pod 的 ID>/volumes/kubernetes.io~<Volume 类型 >/<Volume 名字 >
五、不通过PV、PVC使用存储
5.1.emptyDir
pod删除它也删除。
apiVersion: apps/v1 kind: Deployment metadata: name: httpd-demo labels: app: httpd-demo spec: replicas: 3 selector: matchLabels: app: httpd-demo template: metadata: labels: app: httpd-demo spec: containers: - name: httpd image: httpd ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/http/html/ volumes: - name: html emptyDir: {}
5.2.hostPath
把宿主机的目录与pod建立关系
kubectl explain Deployment.spec.template.spec.volumes
apiVersion: apps/v1 kind: Deployment metadata: name: httpd-demo labels: app: httpd-demo spec: replicas: 3 selector: matchLabels: app: httpd-demo template: metadata: labels: app: httpd-demo spec: containers: - name: httpd image: httpd ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/http/html/ volumes: - name: html path: /data/volumes type: DirectoryOrCreate
5.3.NFS
apiVersion: v1 kind: Pod metadata: name: pvcpod namespace: default spec: volumes: - name: html nfs: path: /data/volumes server: 10.146.16.248 containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: - name: html mountPath: /usr/share/nginx/html/
5.4.GFS/ceph略
六、StorageClass (动态创建PV,pod挂载存储)
大规模集群里,大量的PVC、PV,通过StorageClass定义,管理员可以将存储资源定义为某种类型的资源(快速存储、慢速存储),用户根据storageClass描述就可以申请到PV了。StorageClass会依据需求创建出PV。
管理不限属性的资源(如性能), 集群管理员提供各种pv的不同方式,而不仅仅是大小和访问模式。
能够自动的去创建pv。
工作原理:比如要使用NFS,需要一个nfs-client的自动配置程序---Provisioner(制备器),它使用已经配置好的nfs服务器,来自动创建持久卷--PV。
1.自动创建的PV以${namespace}-${pvcName}-${pvName}格式创建在NFS服务器上的共享数据目录中。
2.当PV被回收后以archieved-${namespace}-${pvcName}-${pvName}命名格式存在NFS服务器上。

6.1.StorageClass资源
每个StorageClass都包含provisioner、parameters和reclaimPolicy字段,这些字段在StorageClass动态分配PersistenVolume时会使用到。
StorageClass对象的命名很重要,user使用这个命名来请求生成一个特定的类。当创建StorageClass对象进,管理员设置StorageClass对象的命名和其他参数,一旦创建了对象就不能再对其更新。
通过StorageClass的名称来标识不同种类的存储,比如SSD、block-device这种名称,使用者通过StorageClass的名字来实现动态创建PV指定类弄存储的过程。
可以为没有申请绑定到特定StorageClass的PVC指定一个默认的存储类。
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: standard provisioner: kubernetes.io/aws-ebs parameters: type: gp2 reclaimPolicy: Retain allowVolumeExpansion: true mountOptions: - debug volumeBindingMode: Immediate ##立即绑定
6.2.Provisioner---制备器
Provisioner决定使用哪个卷插件制备PV。
卷插件 内置制备器 配置例子
AWSElasticBlockStore ✓ AWS EBS
AzureFile ✓ Azure File
AzureDisk ✓ Azure Disk
CephFS - -
Cinder ✓ OpenStack Cinder
FC - -
Glusterfs ✓ Glusterfs
iSCSI - -
NFS - -
RBD ✓ Ceph RBD
Local - Local
内置制备器(其名称前缀为”kubernetes.io“并打包在kubernetes中)。如NFS没有内部provisioner,可以用第三方的外部provisioner。
6.3.回收策略
reclaimPolicy字段中指定回收策略,可以是Delete或者Retain。没有指定默认为Delete;
通过StorageClass手动创建并管理的PersistentVolume会使用这些回收策略。
6.4.允许卷扩展
PersistenVolume可以配置为可扩展。allowVolumeExpansion: true
只能扩不能收。Azure File、Azure Disk、glusterfs、rbc、Cinder支持。
6.5.卷绑定模式
volumeBindingMode字段控制了卷绑定和动态制备是时应该的动作。
默认:immediate模式表示一旦创建了PersistentVolumeClaim也就完成了卷绑定和动态制备。
可以通过WaitForFirstConsumer模式来解决此问题。它将延迟persistenVolume的绑定和制备,直到使用该PVC的Pod被创建。PV会根据Pod调度约束指定的拓扑来选择或制备。
6.6.例
StorageClass + NFS
6.6.1.准备NFS Server
略
6.6.2.创建Service Account,用于管理NFS Provisioner在K8S集群中运行的权限;NFS Provisioner需要单独下截,并以DP方式部署pod。
RBAC授权
# rbac.yaml:#唯一需要修改的地方只有namespace,根据实际情况定义 apiVersion: v1 kind: ServiceAccount # 创建一个账户,主要用来管理NFS provisioner在k8s集群中运行的权限 metadata: name: nfs-client-provisioner namespace: default --- kind: ClusterRole # 创建集群角色 apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nfs-client-provisioner-runner # 角色名 rules: # 角色权限 - apiGroups: [""] resources: ["persistentvolumes"] # 操作的资源 verbs: ["get", "list", "watch", "create", "delete"] # 对该资源的操作权限 - apiGroups: [""] resources: ["persistentvolumeclaims"] verbs: ["get", "list", "watch", "update"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["create", "update", "patch"] --- kind: ClusterRoleBinding # 集群角色绑定 apiVersion: rbac.authorization.k8s.io/v1 metadata: name: run-nfs-client-provisioner subjects: # 角色绑定对象 - kind: ServiceAccount name: nfs-client-provisioner namespace: default roleRef: kind: ClusterRole # 哪个角色 name: nfs-client-provisioner-runner apiGroup: rbac.authorization.k8s.io --- kind: Role # 创建角色 apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner # 角色名 namespace: default # Role需要指定名称空间,ClusterRole 不需要 rules: # 角色权限 - apiGroups: [""] resources: ["endpoints"] verbs: ["get", "list", "watch", "create", "update", "patch"] --- kind: RoleBinding # 角色绑定 apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner subjects: # 角色绑定对象 - kind: ServiceAccount name: nfs-client-provisioner namespace: default roleRef: # 绑定哪个角色 kind: Role name: leader-locking-nfs-client-provisioner apiGroup: rbac.authorization.k8s.io
6.6.3.创建StorageClass,指定Provisioner。负责建立PVC并调用NFS Provisioner进行预定的工作,并让PV与PVC建立关联。注意StorageClass provisioner需要与6.6.4.NFS provisioner中的PROVISIONER_NAME相同
# 创建NFS资源的StorageClass apiVersion: storage.k8s.io/v1 kind: StorageClass # 创建StorageClass metadata: name: managed-nfs-storage ##通过这个名字来定义不同类的存储 provisioner: qgg-nfs-storage #这里的名称要和provisioner配置文件中的环境变量PROVISIONER_NAME保持一致 parameters: archiveOnDelete: "false"
附:如果有内置的provisioner就不需要手动创建6.6.4步的provisioner
kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: slow ##通过这个名字来定义不同类的存储。 provisioner: kubernetes.io/aws-ebs #可以只写aws parameters: type: io1 iopsPerGB: "10" fsType: ext4
6.6.4.创建NFS Provisioner DP,它有两个功能:1.在NFS共享目录下创建挂载点(volume);2.建立PV并将PV与NFS的挂载点建立关联。# 创建NFS provisioner
apiVersion: apps/v1 kind: Deployment # 部署nfs-client-provisioner metadata: name: nfs-client-provisioner labels: app: nfs-client-provisioner namespace: default #与RBAC文件中的namespace保持一致 spec: replicas: 1 selector: matchLabels: app: nfs-client-provisioner strategy: type: Recreate selector: matchLabels: app: nfs-client-provisioner template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner # 指定serviceAccount! containers: - name: nfs-client-provisioner image: quay.io/external_storage/nfs-client-provisioner:latest #镜像地址
###image: registry.cn-beijing.aliyuncs.com/docker-dhbm/nfs-subdir-external-provisioner ##k8s 1.28image用这个,用上面的会报错,pvc会一直处于pending状态。 volumeMounts: # 挂载数据卷到容器指定目录 - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME # 配置provisioner的Name value: qgg-nfs-storage # 确保该名称与 StorageClass 资源中的provisioner名称保持一致 - name: NFS_SERVER #绑定的nfs服务器 value: 10.146.16.248 #NFS服务器IP - name: NFS_PATH #绑定的nfs服务器目录 value: /data/scvolumes # NFS共享目录
volumes: ##申明nfs数据卷
- name: nfs-client-root nfs: server: 10.146.16.248 ##NFS服务器IP path: /data/scvolumes ##NFS共享目录
6.6.5.创建pod测试
先创建一个PVC
# 申明一个PVC,指定StorageClass kind: PersistentVolumeClaim apiVersion: v1 metadata: name: test-claim annotations: # 通过annotations注解,和storage-class进行关联,为什么不使用storageClassName,因为版本比较低 # 这里指定的名字就是上面创建的StorageClass的名字,让它帮我们创建PV volume.beta.kubernetes.io/storage-class: "managed-nfs-storage" ##用哪一类存储。 spec: accessModes: - ReadWriteMany resources: requests: storage: 10Mi

kubectl get pv

在1.20版本以后需要修改/etc/kubernetes/manifests/kube-apiserver.yaml文件,否则会出现以下错误:
#kubectl describe pvc test-claim查看
waiting for a volume to be created, either by external.....

添加一行:
- --feature-gates=RemoveSelfLink=false

# 创建测试pod,查看是否可以正常挂载 kind: Pod apiVersion: v1 metadata: name: test-pod spec: containers: - name: test-pod image: busybox:1.24 command: - "/bin/sh" args: - "-c" - "touch /mnt/SUCCESS && exit 0 || exit 1" #创建一个SUCCESS文件后退出 volumeMounts: - name: nfs-pvc # 挂载数据卷 mountPath: "/mnt" restartPolicy: "Never" volumes: - name: nfs-pvc persistentVolumeClaim: # 数据卷挂载的是pvc claimName: test-claim #与PVC名称保持一致
在NFS服务器上可以看到SUCCESS这个文件

以上实验删除pod,pv不会被删除。删除PVC,PV也被删除,NFS上的文件也会被删除。
7、本地持久化存储
数据存在POD运行的宿主机上。
不支持动态创建。
宿主机有hostPath和emptyDir两种方式,但它们不适用于本地持久存储。要保证pod被调到具有本地持久化存储的节点上。使用这种方式的持久化主要是为了解决对超高IO性能的磁盘的要求,用本地SSD,通过网络会削弱性能。
使用这种方式要解决POD的调度问题,保证POD一定会调度到拥有这种PV的node上。定义PV是要声明节点亲和。
7.1.定义PV
apiVersion: v1 kind: PersistentVolume metadata: name: example-pv spec: capacity: storage: 5Gi volumeMode: Filesystem accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Delete storageClassName: local-storage local: # local类型 path: /data/vol1 # 节点上的具体路径 nodeAffinity: # 这里就设置了节点亲和 required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - node01 # 这里我们使用node01节点,该节点有/data/vol1路径
7.2.定义StorageClass
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的调度要参考卷的分布。当开始调度POD的时候看看它要求的PV在哪里,然后就调度到该节点,然后进行PVC的绑定,最后在挂载到POD中,这样就保证了POD所在的节点就一定是PV所在的节点。所以让PVC延迟绑定,就是等到使用这个PVC的POD出现在调度器上之后(真正被调度之前),然后根据综合评估再来绑定这个PVC。
7.3.定义PVC
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: local-claim spec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi storageClassName: local-storage
7.4.定义POD
apiVersion: apps/v1 kind: Deployment metadata: name: tomcat-deploy spec: replicas: 1 selector: matchLabels: appname: myapp template: metadata: name: myapp labels: appname: myapp spec: containers: - name: myapp image: tomcat:8.5.38-jre8 ports: - name: http containerPort: 8080 protocol: TCP volumeMounts: - name: tomcatedata mountPath : "/data" volumes: - name: tomcatedata persistentVolumeClaim: claimName: local-claim


浙公网安备 33010602011771号