一、部署nfs服务端
1、需在 k8s-master 节点上搭建了一个 NFS 服务器,目录为 /nfsdata:
yum install -y nfs-utils rpcbind vim /etc/exports /nfsdata *(rw,no_root_squash,no_all_squash,sync)
2、保存配置文件后,执行如下操作:
在服务端创建对应的目录和赋予权限:
mkdir /nfsdata chmod 777 /nfsdata
3、启动rpcbind和nfs服务:
systemctl start rpcbind && systemctl enable rpcbind systemctl start nfs && systemctl enable nfs
4、每个node安装nfs工具
yum install -y nfs-utils
5、每个node查询NFS服务器
showmount -e nfs-ip
二、 NFS PersistentVolume
1、创建PV
(1)下面创建一个PV mypv1,配置文件nfs-pv1.yml如下:
[root@ren7 yaml]# cat nfs-pv1.yml apiVersion: v1 kind: PersistentVolume metadata: name: mypv1 spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle storageClassName: nfs nfs: path: /nfsdata/pv1 #需要创建pv1目录,否则pod起不来 server: 192.168.11.7
① capacity
指定 PV 的容量为 1G。
② accessModes
指定访问模式为 ReadWriteOnce
,支持的访问模式有:
ReadWriteOnce – PV 能以 read-write 模式 mount 到单个节点。
ReadOnlyMany – PV 能以 read-only 模式 mount 到多个节点。
ReadWriteMany – PV 能以 read-write 模式 mount 到多个节点。
persistentVolumeReclaimPolicy
指定当 PV 的回收策略为 Recycle
,支持的策略有:rm -rf /thevolume/*
。 ④ storageClassName
指定 PV 的 class 为 nfs
。相当于为 PV 设置了一个分类,PVC 可以指定 class 申请相应 class 的 PV。
⑤ 指定 PV 在 NFS 服务器上对应的目录。
注意要做storage-provider段要提前建好文件夹
[root@ren7 nfsdata]# pwd /nfsdata [root@ren7 nfsdata]# mkdir pv1 [root@ren7 nfsdata]# ls pv1
(2)创建 mypv1:
[root@ren7 yaml]# kubectl apply -f nfs-pv1.yml persistentvolume/mypv1 created [root@ren7 yaml]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mypv1 1Gi RWO Recycle Available nfs 9s
STATUS 为 Available,表示 mypv1 就绪,可以被 PVC 申请。
2、创建PVC
(1)接下来创建 PVC mypvc1
,配置文件 nfs-pvc1.yml
如下:
注意:
1)storageClassName需要与上面定义的pv保持一致!
2)各个节点都需要下载nfs-utils
[root@ren7 yaml]# cat nfs-pvc1.yml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mypvc1 spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: nfs
PVC 就很简单了,只需要指定 PV 的容量,访问模式和 class。
(2)创建 mypvc1:
[root@ren7 yaml]# kubectl apply -f nfs-pvc1.yml persistentvolumeclaim/mypvc1 created [root@ren7 yaml]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE mypvc1 Bound mypv1 1Gi RWO nfs 10s [root@ren7 yaml]# [root@ren7 yaml]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mypv1 1Gi RWO Recycle Bound default/mypvc1 nfs 161m
从 kubectl get pvc 和 kubectl get pv 的输出可以看到 mypvc1 已经 Bound 到 mypv1,申请成功。
3、pod使用PVC
(1)接下来就可以在 Pod 中使用存储了,Pod 配置文件 pod1.yml 如下:
[root@ren7 yaml]# cat pod1.yml apiVersion: v1 kind: Pod metadata: name: mypod1 spec: containers: - name: mypod1 image: reg.yunwei.com/learn/busybox:latest args: - /bin/sh - -c - sleep 30000 volumeMounts: - mountPath: "/mydata" name: mydata volumes: - name: mydata persistentVolumeClaim: claimName: mypvc1
与使用普通 Volume 的格式类似,在 volumes 中通过 persistentVolumeClaim 指定使用 mypvc1 申请的 Volume。
(2)创建 mypod1:
[root@ren7 yaml]# kubectl apply -f pod1.yml pod/mypod1 created [root@ren7 yaml]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES mypod1 1/1 Running 0 12s 172.20.72.157 192.168.11.5 <none> <none>
(3)验证 pv 是否可用:
[root@ren7 yaml]# kubectl exec mypod1 touch /mydata/hello [root@ren7 yaml]# cd /nfsdata/ [root@ren7 nfsdata]# ls pv1 [root@ren7 nfsdata]# ls pv1/ hello
可见,在 Pod 中创建的文件 /mydata/hello 确实已经保存到了 NFS 服务器目录 /nfsdata/pv1 中。
如果不再需要使用 pv,可用删除PVC 回收 pv。
三、回收 PV:
1、当 PV 不再需要时,可通过删除 PVC 回收。
[root@ren7 yaml]# kubectl delete -f nfs-pvc1.yml persistentvolumeclaim "mypvc1" deleted [root@ren7 yaml]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES mypod1 1/1 Running 0 3h46m 172.20.72.157 192.168.11.5 <none> <none>
当 PVC mypvc1 被删除后,我们发现 Kubernetes 启动了一个新 Pod这个 Pod 的作用就是清除 PV mypv1 的数据。这个时候我们再看 NFS 服务器目录 /nfsdata/pv1 中已经没有数据了。
[root@ren7 nfsdata]# ls pv1 [root@ren7 nfsdata]# ls pv1/ [root@ren7 nfsdata]# [root@ren7 nfsdata]#
2、当数据清除完毕,mypv1 的状态重新变为 Available,此时则可以被新的 PVC 申请。
[root@ren7 yaml]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv1 1Gi RWO Recycle Available nfs 3h52m
3、因为 PV 的回收策略设置为 Recycle,所以数据会被清除,但这可能不是我们想要的结果。如果我们希望保留数据,可以将策略设置为 Retain。
apiVersion: v1 kind: PersistentVolume metadata: name: mypv1 spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: nfs nfs: path: /nfsdata/pv1 server: 192.168.11.7
4、通过kubectl apply 更新PV:
[root@ren7 yaml]# kubectl apply -f nfs-pv1.yml persistentvolume/mypv1 configured [root@ren7 yaml]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mypv1 1Gi RWO Retain Available nfs 14s
5、回收策略已经变为 Retain,通过下面步骤验证其效果:
[root@ren7 yaml]# kubectl apply -f nfs-pvc1.yml persistentvolumeclaim/mypvc1 created [root@ren7 yaml]# [root@ren7 yaml]# kubectl get pod No resources found. [root@ren7 yaml]# kubectl apply -f pod1.yml pod/mypod1 created [root@ren7 yaml]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES mypod1 1/1 Running 0 10s 172.20.72.159 192.168.11.5 <none> <none> [root@ren7 yaml]# kubectl exec mypod1 touch /mydata/nihao [root@ren7 yaml]# kubectl delete pod mypod1 pod "mypod1" deleted [root@ren7 yaml]# kubectl delete pvc mypvc1 persistentvolumeclaim "mypvc1" deleted [root@ren7 yaml]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mypv1 1Gi RWO Retain Released default/mypvc1 nfs 6m51s
[root@ren7 yaml]# kubectl get pvc
No resources found.
[root@ren7 yaml]# kubectl get pod
No resources found.
① 重新创建 mypvc1。
② 在 mypv1 中创建文件 nihao。
③ mypv1 状态变为 Released。
④ Kubernetes 并没有启动 Pod recycler-for-mypv1。
⑤ PV 中的数据被完整保留。
(6)我们再看 NFS 服务器目录 /nfsdata/pv1 中数据还保留。
[root@ren7 nfsdata]# ls pv1 [root@ren7 nfsdata]# ls pv1/ nihao
(7)虽然 mypv1 中的数据得到了保留,但其 PV 状态会一直处于 Released,不能被其他 PVC 申请。
[root@ren7 yaml]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv1 1Gi RWO Retain Released default/mypvc1 nfs 10m
(8)为了重新使用存储资源,可以删除并重新创建 mypv1。删除操作只是删除了 PV 对象,存储空间中的数据并不会被删除。
新建的 mypv1 状态为 Available,已经可以被 PVC 申请。
[root@ren7 yaml]# kubectl delete pv mypv1 persistentvolume "mypv1" deleted [root@ren7 yaml]# kubectl apply -f nfs-pv1.yml persistentvolume/mypv1 created [root@ren7 yaml]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mypv1 1Gi RWO Retain Available nfs 6s
PV 还支持 Delete 的回收策略,会删除 PV 在 Storage Provider 上对应存储空间。NFS 的 PV 不支持 Delete,支持 Delete 的 Provider 有 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。
四、PV的动态供给
1、pv的供给方式
前面的例子中,我们提前创建了 PV,然后通过 PVC 申请 PV 并在 Pod 中使用,这种方式叫做静态供给(Static Provision)。
与之对应的是动态供给(Dynamical Provision),即如果没有满足 PVC 条件的 PV,会动态创建 PV。相比静态供给,动态供给有明显的优势:不需要提前创建 PV,减少了管理员的工作量,效率高。
动态供给是通过 StorageClass 实现的,StorageClass 定义了如何创建 PV
2、pv动态供给举例
StorageClass standard:
StorageClass slow:
这两个 StorageClass 都会动态创建 AWS EBS,不同在于 standard 创建的是 gp2 类型的 EBS,而 slow 创建的是 io1 类型的 EBS。不同类型的 EBS 支持的参数可参考 AWS 官方文档。
StorageClass 支持 Delete 和 Retain 两种 reclaimPolicy,默认是 Delete。
与之前一样,PVC 在申请 PV 时,只需要指定 StorageClass 和容量以及访问模式,比如:
除了 AWS EBS,Kubernetes 支持其他多种动态供给 PV 的 Provisioner,完整列表请参考 https://kubernetes.io/docs/concepts/storage/storage-classes/#provisioner
五、pv、pvc无法删除问题
一般的删除步骤为:先删除pod再删除pvc最后删除pv。
但是遇到pv始终处于“Terminating”状态,而且delete不掉。
解决办法:
直接删除k8s中的记录:
kubectl patch pv xxx -p '{"metadata":{"finalizers":null}}'
参考信息:
This happens when persistent volume is protected. You should be able to cross verify this: Command: kubectl describe pvc PVC_NAME | grep Finalizers Output: Finalizers: [kubernetes.io/pvc-protection] You can fix this by setting finalizers to null using kubectl patch: kubectl patch pvc PVC_NAME -p '{"metadata":{"finalizers": []}}' --type=merge