K8s存储之Volume、PV、PVC、SC
Volume
Volume(存储卷)是Pod中能够被多个容器访问的共享目录。Kubernetes的Volume概念、用途和目的与Docker的Volume比较类似,但两者不能等价。首先,Kubernetes中的Volume被定义在Pod上,然后被一个Pod里的多个容器挂载到具体的文件目录下;其次,Kubernetes中的Volume与Pod的生命周期相同,但与容器的生命周期不相关,当容器终止或者重启时,Volume中的数据也不会丢失。最后,Kubernetes支持多种类型的Volume,例如GlusterFS、Ceph等先进的分布式文件系统。
emptyDir
emptyDir Volume是在Pod分配到node时创建的,正如卷的名字,它的初始内容为空,并且无需指定宿主机上对应的目录文件,因为这是kubernetes自动分配的一个目录,当Pod从node上移除时,emptyDir中的数据也会被永久删除。
拓扑图:
emptyDir的用途有:
- 临时空间,例如用于某些应用程序运行时所需的临时目录,且无需永久保留
- 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。
- 一个容器需要从另一个容器中获取数据库的目录(多容器共享目录)
Volume的使用也比较简单,在大多数情况下,我们先在Pod上声明一个Volume,然后在容器里引用该Volume并挂载(Mount)到容器里的某个目录上。
举例来说,为我们先创建一个pod,里面定义两个容器,一个nginx,一个busybox,然后指定nginx挂载路径/user/share/nginx/html/,指定busybox的挂载路径为/test。
[root@master ~]# cat volume_test.yaml apiVersion: v1 kind: Service metadata: name: service-nginx namespace: default spec: type: NodePort selector: app: nginx ports: - name: nginx port: 80 targetPort: 80 --- apiVersion: apps/v1 kind: Deployment metadata: name: mydeploy namespace: default spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: name: web labels: app: nginx spec: containers: - name: nginx image: nginx:1.21.4 ports: - name: nginx containerPort: 80 volumeMounts: - name: html mountPath: /user/share/nginx/html/ - name: busybox image: busybox command: - "/bin/sh" - "-c" - "sleep 6000" volumeMounts: - mountPath: /test/ name: html volumes: - name: html emptyDir: {}
创建pod并查看
[root@master ~]# kubectl apply -f volume_test.yaml service/service-nginx created deployment.apps/mydeploy created [root@master ~]# kubectl get pod NAME READY STATUS RESTARTS AGE mydeploy-786cbf6968-tndxp 2/2 Running 0 81s [root@master ~]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 38m service-nginx NodePort 10.100.6.107 <none> 80:32649/TCP 87s
进入pod查看busybox这个容器
[root@master ~]# kubectl exec mydeploy-786cbf6968-tndxp -c busybox -it -- sh / # ls bin dev etc home proc root sys test tmp usr var / # cd /test/ #进入挂载目录 /test # ls /test # date > index.html #创建一个index.html,并写入当前时间 /test # ls index.html /test # cat index.html Mon Aug 1 06:46:29 UTC 2022 /test #
再进入当前pod的nginx容器中
[root@master ~]# kubectl exec mydeploy-786cbf6968-tndxp -c nginx -it -- /bin/bash root@mydeploy-786cbf6968-tndxp:/# ls bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp user usr var root@mydeploy-786cbf6968-tndxp:/# cd /user/share/nginx/html/ root@mydeploy-786cbf6968-tndxp:/user/share/nginx/html# ls index.html root@mydeploy-786cbf6968-tndxp:/user/share/nginx/html# cat index.html Mon Aug 1 06:46:29 UTC 2022 root@mydeploy-786cbf6968-tndxp:/user/share/nginx/html#
此时我们发现当busybox这个容器中的挂载点文件和nginx容器中的挂载点文件一样,并且当busybox的文件发生改变时,nginx容器的文件也发生变化。说明两个容器公用一个volume。
hostPath
hostPath为在Pod上挂载宿主机上的文件或目录,它通常可以用于以下几方面:
- 容器应用程序生成的日志文件需要永久保存时,可以使用宿主机的告诉文件系统进行存储
- 需要访问宿主机上Docker引擎内部数据结构的容器应用时,可以通过定义hostPath为宿主机/var/lib/docker目录,使容器内部应用可以直接访问Docker的文件系统
在使用这种类型的volume时,需要注意以下几点:
- 在不同的node上具有相同配置的Pod时,可能会因为宿主机上的目录和文件不同而导致对volume上的目录和文件访问结果不一致
- 如果使用了资源配置,则kubernetes无法将hostPath在宿主机上使用的资源纳入管理
- 宿主机创建的文件或目录只能由 root 用户写入。你需要在特权容器中以 root 身份运行进程,或者修改主机上的文件权限以便容器能够写入hostPath 卷。
当我们配置hostPath时需要指定他的type,参数如下:
取值 | 行为 |
---|---|
空字符串(默认)用于向后兼容,这意味着在安装 hostPath 卷之前不会执行任何检查。 | |
DirectoryOrCreate |
如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为 0755,具有与 kubelet 相同的组和属主信息。 |
Directory |
在给定路径上必须存在的目录。 |
FileOrCreate |
如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件,权限设置为 0644,具有与 kubelet 相同的组和所有权。 |
File |
在给定路径上必须存在的文件。 |
Socket |
在给定路径上必须存在的 UNIX 套接字。 |
CharDevice |
在给定路径上必须存在的字符设备。 |
BlockDevice |
在给定路径上必须存在的块设备。 |
下面举例说明:
创建一个pod,里面部署nginx容器,并指定挂载方式时hostPath,类型为DirectoryOrCreate。
[root@master ~]# cat volume_test2.yaml apiVersion: v1 kind: Service metadata: name: service-nginx namespace: default spec: type: NodePort selector: app: nginx ports: - name: nginx port: 80 targetPort: 80 --- apiVersion: apps/v1 kind: Deployment metadata: name: mydeploy namespace: default spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: name: web labels: app: nginx spec: containers: - name: nginx image: nginx:1.21.4 ports: - name: nginx containerPort: 80 volumeMounts: - name: nginx-volume mountPath: /usr/share/nginx/html/ volumes: - name: nginx-volume hostPath: path: /test-volume # 宿主上目录位置 type: DirectoryOrCreate #类型可选
创建pod并查看pod、svc
[root@master ~]# kubectl get svc -owide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 17h <none> service-nginx NodePort 10.111.102.100 <none> 80:32457/TCP 14h app=nginx [root@master ~]# kubectl get pod -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES mydeploy-695f458b88-66s8n 1/1 Running 0 14h 10.101.11.54 node2 <none> <none> mydeploy-695f458b88-tnn59 1/1 Running 0 14h 10.101.149.28 node1 <none> <none>
此时我们看到pod被创建在node1和node2上,我们查看node1和node2的/目录下是否有test-volume创建
往test-volume目录下创建一个index.html文件,并添加内容。
[root@node1 ~]# echo node1 >/test-volume/index.html [root@node1 ~]# cat /test-volume/index.html node1 [root@node2 ~]# echo node2 >/test-volume/index.html [root@node2 ~]# cat /test-volume/index.html node2
最后验证一下,在master节点curl 主机IP:32457
[root@master ~]# curl 192.168.248.129:32457 node1 [root@master ~]# curl 192.168.248.129:32457 node2 [root@master ~]# curl 192.168.248.129:32457 node2 [root@master ~]# curl 192.168.248.129:32457 node1
此时发现master节点负载均衡到每个node节点,每个节点对应的时宿主机的文件。
NFS
nfs卷能将 NFS (网络文件系统) 挂载到你的 Pod 中。 不像 emptyDir那样会在删除 Pod 的同时也会被删除,nfs卷的内容在删除 Pod 时会被保存,卷只是被卸载。 这意味着nfs卷可以被预先填充数据,并且这些数据可以在 Pod 之间共享。
开启集群以外的另一台虚拟机,安装nfs-utils安装包
note:这里要注意的是需要在集群每个节点都安装nfs-utils安装包,并且nfs-server主机要关闭防火墙,不然挂载会失败!
[root@bogon ~]# yum install nfs-utils -y
创建一个/data/nfs的目录
[root@bogon ~]# mkdir -p /data/nfs
开启nfs服务并修改配置文件/etc/exports,将挂载点写入配置文件中
[root@bogon ~]# vim /etc/exports /data/nfs/ 192.168.228.0/24(insecure,rw,no_root_squash)
重启nfs服务
[root@bogon ~]# systemctl restart nfs
在/data/nfs/目录下创建一个index.html的文件,并写入数据
[root@bogon ~]# cd /data/nfs [root@bogon nfs]# echo test > index.html [root@bogon nfs]# cat index.html test
检查nfs是否能被检测到
[root@master ~]# showmount -e 192.168.248.131 Export list for 192.168.248.131: /date/nfs 192.168.248.0/24
创建一个yaml文件并写入nfs挂载
[root@master ~]# cat nfs_test.yaml apiVersion: v1 kind: Service metadata: labels: app: web name: nginx-svc namespace: default spec: ports: - name: http port: 80 # service暴露的端口 protocol: TCP targetPort: 80 #后端容器的端口 selector: #标签选择器与deployment一致 app: web type: NodePort --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: web name: deployment-nginx spec: replicas: 2 selector: matchLabels: app: web template: metadata: labels: app: web spec: containers: - image: nginx:1.21.4 name: nginx ports: - name: http containerPort: 80 #容器端口 volumeMounts: - mountPath: /usr/share/nginx/html name: nfs volumes: - name: nfs nfs: server: 192.168.248.131 #nfs服务器地址 path: /date/nfs/ #nfs服务器共享目录
执行yaml并验证
[root@master ~]# kubectl apply -f nfs_service.yaml service/nginx-svc created deployment.apps/deployment-nginx created [root@master ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES deployment-nginx-68cbc68d45-gnpdx 1/1 Running 0 44s 10.244.104.2 node2 <none> <none> deployment-nginx-68cbc68d45-tlqxv 1/1 Running 0 44s 10.244.166.131 node1 <none> <none> [root@master ~]# kubectl get svc -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3h24m <none> nginx-svc NodePort 10.108.207.154 <none> 80:32435/TCP 53s app=web
此时我们可以看到nfs服务器上/date/nfs/index.html被挂载到容器的内部,我们修改nfs服务器上/date/nfs/index.html
[root@localhost ~]# cd /date/nfs/ [root@localhost nfs]# ls index.html [root@localhost nfs]# ls index.html [root@localhost nfs]# echo 123 > index.html [root@localhost nfs]# cat index.html 123
再次刷新网页发现被同步
PV、PVC
之前提到的Volume是被定义在Pod上的,属于计算资源的一部分,而实际上,网络存储是相对独立于计算资源而存在的一种实体资源。比如在使用虚拟机的情况下,我们通常会先定义一个网络存储,然后从中划出一个“网盘”并挂接到虚拟机上。Persistent Volume(PV)和与之相关联的Persistent Volume Claim(PVC)也起到了类似的作用。
Persistent Volume(PV)
是由管理员设置的存储,他是集群的一部分,就像node也是集群的一部分一样,pv也是集群资源,是volume之类的卷插件,具有独立的pod之外的生命周期,当pv挂载到某个pod上时,pv不会因为pod删除而删除。
pv可以理解成为kubernetes集群中的某个网络存储对应的一块存储,它与Volume类似,但有以下区别:
- pv只能是网络存储,不属于任何Node,但可以在每个Node上访问
- pv并不是被定义在Pod上的,而是独立于Pod之外定义的
PV的关键配置参数
1、存储能力(Capacity)
描述存储设备具备的能力,目前仅支持对存储空间的设置(storage=xx)
2、存储卷模式(Volume Mode)
存储卷类型的设置(volumeMode=xxx),可选项包括Filesystem(文件系统)和Block(块设备),默认值为Filesystem。
3、访问模式(Access Modes)
对PV进行访问模式的设置,用于描述用户的应用对存储资源的访问权限。访问模式如下。
- ReadWriteOnce(RWO):读写权限,并且只能被单个Node挂载。
- ReadOnlyMany(ROX):只读权限,允许被多个Node挂载。
- ReadWriteMany(RWX):读写权限,允许被多个Node挂载。
某些PV可能支持多种访问模式,但PV在挂载时只能使用一种访问模式,多种访问模式不能同时生效,具体请百度。
4.存储类别(Class)
PV可以设定其存储的类别,通过storageClassName参数指定一个StorageClass资源对象的名称。具有特定类别的PV只能与请求了该类别的PVC进行绑定。未设定类别的PV则只能与不请求任何类别的PVC进行绑定。
5.回收策略(Reclaim Policy)
通过PV定义中的persistentVolumeReclaimPolicy字段进行设置,当pod生命周期结束后对PV中的数据处理,可选项如下:
- retain(保留):保留数据,需手动回收
- Recycle(擦除):简单清除文件的操作(rm -rf )
- delete(删除):与PV相连的后端存储完成Volume的删除操作(如AWS EBS、GCE PD、Azure Disk、OpenStack Cinder等设备的内部Volume清理)。
Persistent Volume Claim(PVC)
PVC作为用户对存储资源的需求申请,主要包括存储空间请求、访问模式、PV选择条件和存储类别等信息的设置。
PVC的关键配置参数
资源请求(Resources):描述对存储资源的请求,目前仅支持request.storage的设置,即存储空间大小。
访问模式(Access Modes):PVC也可以设置访问模式,用于描述用户应用对存储资源的访问权限。其三种访问模式的设置与PV的设置相同。
存储卷模式(Volume Modes):PVC也可以设置存储卷模式,用于描述希望使用的PV存储卷模式,包括文件系统和块设备。
PV选择条件(Selector):通过对Label Selector的设置,可使PVC对于系统中已存在的各种PV进行筛选。系统将根据标签选出合适的PV与该PVC进行绑定。选择条件可以使用matchLabels和matchExpressions进行设置,如果两个字段都设置了,则Selector的逻辑将是两组条件同时满足才能完成匹配。
存储类别(Class):PVC 在定义时可以设定需要的后端存储的类别(通过storageClassName字段指定),以减少对后端存储特性的详细信息的依赖。只有设置了该Class的PV才能被系统选出,并与该PVC进行绑定。
PVC也可以不设置Class需求。如果storageClassName字段的值被设置为空(storageClassName=""),则表示该PVC不要求特定的Class,系统将只选择未设定Class的PV与之匹配和绑定。
持久化演示
在nfs服务器上创建nfs的卷并重启
[root@bogon date]# cat /etc/exports /date/nfs/ 192.168.248.0/24(insecure,rw,no_root_squash) /date/nfs1/ 192.168.248.0/24(insecure,rw,no_root_squash) /date/nfs2/ 192.168.248.0/24(insecure,rw,no_root_squash) /date/nfs3/ 192.168.248.0/24(insecure,rw,no_root_squash) /date/nfs4/ 192.168.248.0/24(insecure,rw,no_root_squash) [root@bogon date]# systemctl restart nfs
在nfs服务器上创建对应的目录
[root@bogon date]# mkdir nfs{1..4} [root@bogon date]# ls nfs nfs1 nfs2 nfs3 nfs4
创建PV,创建5个pv对应上面的nfs挂载目录
[root@master ~]# cat pv.yaml apiVersion: v1 kind: PersistentVolume metadata: name: pv01 spec: capacity: #存储容量 storage: 10Gi #pv存储卷为10G accessModes: #访问模式: - ReadWriteMany #读写权限,允许被多个Node挂载。 - ReadWriteOnce #读写权限,并且只能被单个Node挂载 persistentVolumeReclaimPolicy: Retain #回收策略:保留 storageClassName: nfs #存储类别 nfs: #存储类型 path: /date/nfs/ #要挂在的nfs服务器的目录位置 server: 192.168.248.131 #nfs server地址,也可以是域名,前提是能被解析 --- apiVersion: v1 kind: PersistentVolume metadata: name: pv02 spec: capacity: storage: 20Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain storageClassName: nfs nfs: path: /date/nfs1/ server: 192.168.248.131 --- apiVersion: v1 kind: PersistentVolume metadata: name: pv03 spec: capacity: storage: 30Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain storageClassName: nfs nfs: path: /date/nfs2/ server: 192.168.248.131 --- apiVersion: v1 kind: PersistentVolume metadata: name: pv04 spec: capacity: storage: 40Gi accessModes: - ReadOnlyMany persistentVolumeReclaimPolicy: Retain storageClassName: nfs nfs: path: /date/nfs3/ server: 192.168.248.131 --- apiVersion: v1 kind: PersistentVolume metadata: name: pv05 spec: capacity: storage: 50Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: nfs nfs: path: /date/nfs4/ server: 192.168.248.131
执行yaml文件创建pv并查看
[root@master ~]# kubectl apply -f pv.yaml persistentvolume/pv01 unchanged persistentvolume/pv02 configured persistentvolume/pv03 configured persistentvolume/pv04 configured persistentvolume/pv05 configured [root@master ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv01 10Gi RWO,RWX Retain Available nfs 6m24s pv02 20Gi RWX Retain Available nfs 5m28s pv03 30Gi RWX Retain Available nfs 108s pv04 40Gi ROX Retain Available nfs 108s pv05 50Gi RWO Retain Available nfs 108s
解释:
ACCESS MODES: 访问模式
RWO:ReadWriteOnly 读写权限,并且只能被单个Node挂载。
RWX:ReadWriteMany 只读权限,允许被多个Node挂载。
ROX:ReadOnlyMany 读写权限,允许被多个Node挂载。
RECLAIM POLICY: 回收策略
Retain:保护pvc释放的pv及其上的数据,将不会被其他pvc绑定
recycle:保留pv但清空数据
delete:删除pvc释放的pv及后端存储volume
STATUS:
Available:空闲状态
Bound:已经绑定到某个pvc上
Released:对应的pvc已经被删除,但是资源没有被集群回收
Failed:pv自动回收失败
CLAIM:
被绑定到了那个pvc上面格式为:NAMESPACE/PVC_NAME
STORAGECLASS:对应存储类别storageClassName
创建pvc
[root@master ~]# cat pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mypvc spec: accessModes: - ReadOnlyMany resources: requests: storage: 10Gi storageClassName: nfs
查看pvc、pv
[root@master ~]# kubectl get pv,pvc -owide NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE persistentvolume/pv01 10Gi RWO,RWX Retain Available nfs 75s Filesystem persistentvolume/pv02 20Gi RWX Retain Available nfs 75s Filesystem persistentvolume/pv03 30Gi RWX Retain Available nfs 75s Filesystem persistentvolume/pv04 40Gi ROX Retain Bound default/mypvc nfs 75s Filesystem persistentvolume/pv05 50Gi RWO Retain Available nfs 75s Filesystem NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE persistentvolumeclaim/mypvc Bound pv04 40Gi ROX nfs 28s Filesystem
此时mypvc根据匹配已经绑定到pv04上面了,pv、pvc已经创建好,我们在创建一个pod将pvc关联到容器中
[root@master ~]# cat pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mypvc spec: accessModes: - ReadOnlyMany resources: requests: storage: 10Gi storageClassName: nfs [root@master ~]# vim pvc_pod.yaml [root@master ~]# cat pvc_pod.yaml apiVersion: v1 kind: Service metadata: name: nginx-deploy namespace: default spec: selector: app: mynginx type: NodePort ports: - name: nginx port: 80 targetPort: 80 nodePort: 30001 --- apiVersion: apps/v1 kind: Deployment metadata: name: mydeploy namespace: default spec: replicas: 2 selector: matchLabels: app: mynginx template: metadata: name: web labels: app: mynginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - mountPath: /usr/share/nginx/html name: html volumes: - name: html persistentVolumeClaim: claimName: mypvc
执行yaml
[root@master ~]# kubectl apply -f pvc_pod.yaml service/nginx-deploy created deployment.apps/mydeploy created
pv04对应的是nfs服务器中的/data/nfs3/目录,我们在目录下创建index.html并写入test-pvc
[root@bogon date]# cd nfs3/ [root@bogon nfs3]# echo test-pvc > index.html [root@bogon nfs3]# cat index.html test-pvc
验证
[root@master ~]# kubectl exec -it mydeploy-6fff8986f7-7qdrn -- /bin/bash root@mydeploy-6fff8986f7-7qdrn:/# df -h Filesystem Size Used Avail Use% Mounted on overlay 27G 3.2G 24G 12% / tmpfs 64M 0 64M 0% /dev tmpfs 910M 0 910M 0% /sys/fs/cgroup /dev/mapper/centos-root 27G 3.2G 24G 12% /etc/hosts shm 64M 0 64M 0% /dev/shm 192.168.248.131:/date/nfs3 8.0G 1.4G 6.6G 18% /usr/share/nginx/html tmpfs 910M 12K 910M 1% /run/secrets/kubernetes.io/serviceaccount tmpfs 910M 0 910M 0% /proc/acpi tmpfs 910M 0 910M 0% /proc/scsi tmpfs 910M 0 910M 0% /sys/firmware root@mydeploy-6fff8986f7-7qdrn:/# cd /usr/share/nginx/html root@mydeploy-6fff8986f7-7qdrn:/usr/share/nginx/html# ls index.html root@mydeploy-6fff8986f7-7qdrn:/usr/share/nginx/html# cat index.html test-pvc root@mydeploy-6fff8986f7-7qdrn:/usr/share/nginx/html#
当我们删除pod是看回收机制是不是生效。
[root@master ~]# kubectl delete -f pod_pvc.yaml service "nginx-deploy" deleted deployment.apps "mydeploy" deleted [root@master ~]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE mypvc Bound pv04 40Gi ROX nfs 35m [root@master ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv01 10Gi RWO,RWX Retain Available nfs 36m pv02 20Gi RWX Retain Available nfs 36m pv03 30Gi RWX Retain Available nfs 36m pv04 40Gi ROX Retain Bound default/mypvc nfs 36m pv05 50Gi RWO Retain Available nfs 36m
当pod删除时pvc和pv还是绑定状态,查看nfs挂载目录的文件还在
[root@localhost nfs3]# ls index.html [root@localhost nfs3]# cat index.html test-pvc [root@localhost nfs3]#
当pvc被删掉时,查看pv状态
[root@master ~]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE mypvc Bound pv04 40Gi ROX nfs 42m [root@master ~]# kubectl delete pvc mypvc persistentvolumeclaim "mypvc" deleted [root@master ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv01 10Gi RWO,RWX Retain Available nfs 43m pv02 20Gi RWX Retain Available nfs 43m pv03 30Gi RWX Retain Available nfs 43m pv04 40Gi ROX Retain Released default/mypvc nfs 43m pv05 50Gi RWO Retain Available nfs 43m
当pvc被删除后需要我们手动释放pv和pvc的绑定
[root@master ~]# kubectl edit pv pv04 # Please edit the object below. Lines beginning with a '#' will be ignored, # and an empty file will abort the edit. If an error occurs while saving this file will be # reopened with the relevant failures. # apiVersion: v1 kind: PersistentVolume metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"PersistentVolume","metadata":{"annotations":{},"name":"pv04"},"spec":{"accessModes":["ReadOnlyMany"],"capacity":{"storage":"40Gi"},"nfs":{"path":"/date/nfs3/","server":"192.168.248.131"},"persistentVolumeReclaimPolicy":"Retain","storageClassName":"nfs"}} pv.kubernetes.io/bound-by-controller: "yes" creationTimestamp: "2022-08-04T14:20:20Z" finalizers: - kubernetes.io/pv-protection name: pv04 resourceVersion: "20526" uid: 4e0d6db7-c0c3-41c5-9912-a26da20e72c5 spec: accessModes: - ReadOnlyMany capacity: storage: 40Gi claimRef: #需要将这块手动删掉 apiVersion: v1 kind: PersistentVolumeClaim name: mypvc namespace: default resourceVersion: "16788" uid: 558a73ae-21b4-496e-abb5-4224884392e3 nfs: path: /date/nfs3/ server: 192.168.248.131 persistentVolumeReclaimPolicy: Retain storageClassName: nfs volumeMode: Filesystem status: phase: Released
然后再查看pv,发现pv和pvc接触绑定
[root@master ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv01 10Gi RWO,RWX Retain Available nfs 47m
pv02 20Gi RWX Retain Available nfs 47m
pv03 30Gi RWX Retain Available nfs 47m
pv04 40Gi ROX Retain Available nfs 47m
pv05 50Gi RWO Retain Available nfs 47m
StorageClass(SC)动态存储
StorageClass作为对存储资源的抽象定义,对用户设置的PVC申请屏蔽后端存储的细节,一方面减少了用户对于存储资源细节的关注,另一方面减轻了管理员手工管理PV的工作,由系统自动完成PV的创建和绑定,实现了动态的资源供应。基于StorageClass的动态资源供应模式将逐步成为云平台的标准存储配置模式。
StorageClass的定义主要包括名称、后端存储的提供者(provisioner)和后端存储的相关参数配置。StorageClass一旦被创建出来,则将无法修改。如需更改,则只能删除原StorageClass的定义重建。
要使用StorageClass,需要安装对应的自动配置程序,比如我们后端使用的是NFS,那么我们就要使用nfs-client的自动配置程序,也叫Provisioner(供应者),这个程序使用我们已经配置好的nfs服务器,来自动创建持久卷,也就是自动帮我们创建pv,自动创建的pv以${namespace}-${pvcname}-${pvname}这样的命名格式存在我们的NFS服务器上。当pv被回收以后则以archieved-${namespace}-${pvcname}-${pvname}这样的命名方式存在NFS服务器上。
安装nfs-client
nfs-client官方文档:https://github.com/kubernetes-retired/external-storage/tree/master/nfs-client
首先创建一个nfs-client的deployment.yaml
[root@master ~]# cat deployment.yaml piVersion: apps/v1 kind: Deployment metadata: name: nfs-client-provisioner labels: app: nfs-client-provisioner #replace with namespace where provisioner is deployed namespace: default spec: replicas: 1 strategy: #更新策略 type: Recreate #重建更新 selector: matchLabels: app: nfs-client-provisioner template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner #SA名称 containers: - name: nfs-client-provisioner image: quay.io/external_storage/nfs-client-provisioner:latest volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: fuseim.pri/ifs - name: NFS_SERVER #NFS服务器地址 value: 192.168.248.131 - name: NFS_PATH #数据共享目录 value: /data/nfs volumes: - name: nfs-client-root nfs: server: 192.168.248.131 path: /data/nfs/
然后再创建一个名为nfs-client-provisioner的serviceAccount(SA)
[root@master ~]# kubectl create sa nfs-client-provisioner -n default
serviceaccount/nfs-client-provisioner created
创建一个clustrrole和clusterrolebinding为SA赋予权限
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
再创建一个storageclass的yaml
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: managed-nfs-storage provisioner: fuseim.pri/ifs # 必须与上面deployment的env下的PROVISIONER_NAME下的值一致 parameters: archiveOnDelete: "false"
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!