k8s pv与pvc

发布时间 2023-10-19 11:03:00作者: 南风丶轻语

k8s pv与pvc

概念

PV

我们想要持久化k8s pod中的数据,就需要用到存储,找一个地方,存放数据。不然一旦pod被删除,则数据就丢失了。

在k8s中,pv就是存储数据的地方,可以理解为pv就是存储后端。

pv可以由多种存储系统提供,如NFS,GFS,本地,CIFS,云存储集群等

PVC

用户想要使用PV,就需要申请,说明要多大的空间,以及其他属性(例如读写属性:只读,只写,读写。速度属性:快、中、慢)。用户把这些需要的信息通过PVC进行申明,然后由k8s选择合适的PV,然后绑定在一起。这样就可以在pod中挂载PVC,然后使用PV,把数据存起来。

A:为什么用户不直接申请PV,直接使用PV

Q:①降低用户使用门槛

​ 假设直接使用PV,则用户需要知道PV是怎么产生的,有哪些属性。

​ 要使用PV时,就需要把属性传递给PV,PV才能通过存储系统来生成需要的空间。

​ 这就要求用户需要了解那些存储后端。然后才能合理使用,不然就无法生成需要的空间。

​ 用户只需要关心自己需要多大的空间以及一些自己想要的属性。仅此而已!

​ ②管理员方便管理

​ 管理员可以把存储后端给更专业的存储后端人员处理。然后混合使用不同的存储后端。这样存储就多样化了。能应对用户不同的存储需求。

PV参数

举个例子,然后说明定义PV的参数

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv1
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: 172.17.134.126
    path: "/data/k8s"

capacity

capacity 表示存储能力

capacity.storage 表示空间大小, 例如5Gi

accessModes

accessModes 表示访问模式,用于描述用户应用对存储资源的访问权限,有以下几个选项

缩写 说明
ReadWriteOnce RWO 读写权限,但是只能被单个节点挂载
ReadOnlyMany ROX 只读权限,可以被多个节点挂载
ReadWriteMany RWX 读写权限,可以被多个节点挂载

persistentVolumeReclaimPolicy

指定回收策略,有以下几个选项

说明
Retain K8S什么也不做,等待用户手动去处理PV里的数据,处理完后,再手动删除PV。
Delete K8S会自动删除该PV及里面的数据
Recycle(已废弃) K8S会将PV里的数据删除,然后把PV的状态变成Available,又可以被新的PVC绑定使用

生命周期

PV的生命周期有以下几个选项

说明
Available 表示可用状态,还未被任何 PVC 绑定
Bound 表示 PV 已经被 PVC 绑定
Released PVC 被删除,但是资源还未被集群重新声明,数据还存在
Failed 表示该 PV 的自动回收失败

PVC参数

举个例子,然后说明定义PVC的参数

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc1
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: sc-name
  resources:
    requests:
      storage: 5Gi

accessModes

和PV一样

resources.requests.storage

表示用户想要申请的PV的大小

storageClassName

指定storageClass的名称,后续会根据这个名称,找到匹配的pv

说明

创建PVC后,k8s会根据resources.requests.storage和accessModes、storageClassName属性,与所有PV进行配对,选出一个合适的PV,来与PVC进行绑定。

如果没有匹配的PV,则会绑定失败

静态创建PV

静态创建PV,就是管理员首先创建出一些PV,然后用户根据PVC进行申请,使用PV。

使用nfs作为后端存储,测试pv和pvc

虚机信息

IP 功能
172.17.134.134 k8s master节点
172.17.139.162 k8s worker节点
172.17.140.87 k8s worker节点
172.17.134.126 nfs服务器

k8s信息

版本:1.22.0

image-20231018140707091

部署NFS服务

在172.17.134.126执行以下命令,部署NFS服务

关闭防火墙

systemctl stop firewalld.service && systemctl disable firewalld.service && systemctl status firewalld.service

image-20231018141055899

下载nfs和rpc服务

yum -y install nfs-utils rpcbind

创建数据目录

mkdir -p /data/k8s/
chmod 755 /data/k8s/

暴露数据目录

编辑/etc/exports文件,输入以下内容

/data/k8s *(rw,sync,no_root_squash)

image-20231018141448887

nfs权限说明

  • ro 只读
  • rw 可读写
  • sync 同步写数据,保证数据不丢失
  • async 异步写数据,在写入持久化存储之前进行请求响应,如果服务器重启可能会导致文件丢失或者损坏
  • root_squash 将root用户(uid/gid 0)的请求映射为匿名用户(anonymous uid/gid)
  • no_root_squash 禁用root_squash规则
  • all_squash 将所有用户都映射为匿名用户
  • no_all_squash 禁用all_squash规则,默认选项
  • anonuid 指定要映射为匿名用户的uid,例如:anonuid=150
  • anongid 指定要映射为匿名用户的gid,例如:anongid=100

启动rpc服务

systemctl start rpcbind && systemctl enable rpcbind && systemctl status rpcbind

启动nfs服务

systemctl start nfs && systemctl enable nfs && systemctl status nfs

验证服务是否可用

  • 本地验证

rpcinfo -p|grep nfs

image-20231018141905986

cat /var/lib/nfs/etab

image-20231018141942416

  • 客户端挂载验证

在172.17.140.87执行以下命令,验证是否可以使用nfs服务

 showmount -e 172.17.134.126

image-20231018142107982

mkdir -p /home/nfs_from_126/data
mount -t nfs 172.17.134.126:/data/k8s /home/nfs_from_126/data
cd /home/nfs_from_126/data
echo i am 172.17.139.162 host file >> 162.txt

在nfs服务器中查看,是否有该文件,有则OK,否则nfs服务搭建失败,需要排查,重新搭建

image-20231018142927021

定义pv

nfs-pv1.yml

创建5Gi大小,访问属性是ReadWriteOnce的PV

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv1
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: 172.17.134.126
    path: "/data/k8s"

nfs-pv2.yml

创建1Gi大小,访问属性是ReadWriteOnce的PV

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv2
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: 172.17.134.126
    path: "/data/k8s"

nfs-pv3.yml

创建5Gi大小,访问属性是ReadWriteMany的PV

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv3
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: 172.17.134.126
    path: "/data/k8s"

nfs-pv4.yml

创建1Gi大小,访问属性是ReadWriteMany的PV

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv4
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: 172.17.134.126
    path: "/data/k8s"

应用pv

kubectl apply -f nfs-pv1.yml
kubectl apply -f nfs-pv2.yml
kubectl apply -f nfs-pv3.yml
kubectl apply -f nfs-pv4.yml

查看pv

kubectl get pv -o wide

image-20231018145938970

定义PVC

nfs-pvc1.yml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc1
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

应用PVC

 kubectl apply -f nfs-pvc1.yml

查看PVC

kubectl get pvc -o wide

image-20231018155031766

查看pv与pvc的关系

 kubectl get pv -o wide

image-20231018155147768

可以看到,PVC:nfs-pvc1与PV:nfs-pv1绑定在一起了

注意事项

假设,我要申请的PVC的大小超过了5Gi,则PVC与PV会绑定失败,会一直等待绑定

提示信息 no persistent volumes available for this claim and no storage class is set

image-20231018160306814

使用PVC

  • 定义pod

nfs-pvc1.yml

apiVersion: v1
kind: Pod
metadata:
  name: nfs-pod1
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    imagePullPolicy: IfNotPresent
    command: ["/bin/bash","-c","echo begin;sleep 3600;echo end"]
    volumeMounts:
      - mountPath: "/home/nfs-pod1" #挂载的路径
        name:  nfs-pod1 #要与①相同
  volumes:
    - name: nfs-pod1 #要与①相同
      persistentVolumeClaim:
        claimName: nfs-pvc1 # 使用kubectl get pvc 获取到的 pvc
  • 应用pod
 kubectl apply -f nfs-pod1.yml

在pod中创建文件,在nfs上就能看到

image-20231018162600253

nfs中查看

image-20231018162628654

删除PVC

kubectl delete pvc nfs-pvc1

删除PV

kubectl delete pv nfs-pv1
kubectl delete pv nfs-pv2
kubectl delete pv nfs-pv3
kubectl delete pv nfs-pv4

动态创建PV

静态创建有个弊端,就是必须管理员先手动创建PV,然后用户创建PVC,然后才能申请PV使用。

作为管理员,面对多样的场景,也不能做很多PV来用,也做不了那么多。做了的PV也会存在浪费的情况,例如PV是50Gi,但用户申请PVC未5Gi,此时没有其他可用的PV,则该PVC与PV绑定了,就浪费了45Gi。

因此,需要k8s根据用户提交的PVC,自动创建PV且绑定。这就引入了动态创建PV

说明

先删除之前的所有PVC和PV,然后再测试

image-20231018171919041

原理

【待填充】

创建RBAC

rbac.yml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner #与②相同
  namespace: default        #根据实际环境设定namespace,下面类同

---
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 #与②相同
    # replace with namespace where provisioner is deployed
    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 #与③相同
    # replace with namespace where provisioner is deployed
  namespace: default
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 #与②相同
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner #与③相同
  apiGroup: rbac.authorization.k8s.io

创建nfs-client-provisioner

nfs-client-provisioner.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default  #与RBAC文件中的namespace保持一致
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nfs-client-provisioner
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      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: master-nfs-storage  #provisioner名称,请确保该名称与StorageClass的provisioner名称保持一致
            - name: NFS_SERVER
              value: 172.17.134.126   #NFS Server IP地址
            - name: NFS_PATH
              value: /data/k8s    #NFS挂载卷
      volumes:
        - name: nfs-client-root
          nfs:
            server: 172.17.134.126  #NFS Server IP地址
            path: /data/k8s     #NFS 挂载卷

创建StorageClass

storageclass.yml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: master-nfs-storage
provisioner: master-nfs-storage #这里的名称要和的provisioner配置文件中的环境变量PROVISIONER_NAME保持一致
parameters:
  archiveOnDelete: "false"
reclaimPolicy: Retain

应用配置

kubectl apply -f rbac.yml
kubectl apply -f nfs-client-provisioner.yml
kubectl apply -f storageclass.yml

image-20231018192547591

查看配置

kubectl get deployments
kubectl get pod
kubectl get sc

image-20231019101455653

测试

创建pvc,使用pod挂载pvc,测试是否可以自动创建pv

创建PVC

nfs-dy-pvc1.yml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-dy-pvc1
spec:
  accessModes:
    - ReadWriteOnce #表示该volume只能被单个节点以读写的方式映射
  resources:
    requests:
      storage: 5Gi
  storageClassName: master-nfs-storage  #指定storageclass 与StorageClass中的provisioner一致
kubectl apply -f nfs-dy-pvc1.yml

查看PVC和PV

kubectl get pvc
kubectl get pv
kubectl describe pv pvc-78ce936e-a001-4881-a030-ae9465f8e252

image-20231019101646927

可以看到,已经自动创建了PV,且和PVC绑定了

nfs创建的路径是 /data/k8s/default-nfs-dy-pvc1-pvc-78ce936e-a001-4881-a030-ae9465f8e252

创建pod

nfs-dy-pod1.yml

apiVersion: v1
kind: Pod
metadata:
  name: nfs-dy-pod1
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    imagePullPolicy: IfNotPresent
    command: ["/bin/bash","-c","echo begin;sleep 3600;echo end"]
    volumeMounts:
      - mountPath: "/home/nfs-dy-pod1" #挂载的路径
        name:  volume1 #要与①相同
  volumes:
    - name: volume1 #要与①相同
      persistentVolumeClaim:
        claimName: nfs-dy-pvc1 # 使用kubectl get pvc 获取到的 pvc
kubectl apply -f nfs-dy-pod1.yml

查看Pod

kubectl get pod
kubectl logs nfs-dy-pod1

image-20231019102240138

在pod中测试

kubectl exec -it nfs-dy-pod1 -- bash
cd /home/nfs-dy-pod1/
echo nfs-dy-pod1-1 > nfs-dy-pod1-1.txt
echo nfs-dy-pod1-2 > nfs-dy-pod1-2.txt
echo nfs-dy-pod1-3 > nfs-dy-pod1-3.txt

image-20231019102443933

在nfs上查看

路径 /data/k8s/default-nfs-dy-pvc1-pvc-78ce936e-a001-4881-a030-ae9465f8e252

image-20231019102621460

删除pod

kubectl delete pod nfs-dy-pod1

删除PVC

kubectl delete pvc nfs-dy-pvc1

删除PV

kubectl get pv
kubectl delete pv pvc-78ce936e-a001-4881-a030-ae9465f8e252

image-20231019103957336

删除PV后,nfs的数据依旧存在

image-20231019104040114

备注

保护的PVC和PV

如果用户删除被某 Pod 使用的 PVC 对象,该 PVC 申领不会被立即移除。 PVC 对象的移除会被推迟,直至其不再被任何 Pod 使用。 此外,如果管理员删除已绑定到某 PVC 申领的 PV 卷,该 PV 卷也不会被立即移除。 PV 对象的移除也要推迟到该 PV 不再绑定到 PVC。

你可以看到当 PVC 的状态为 Terminating 且其 Finalizers 列表中包含 kubernetes.io/pvc-protection 时,PVC 对象是处于被保护状态的。

链接

【精选】k8s搭建nfs创建pv、pvc_创建基于nfs的pv pvc_zhoujianhui008的博客-CSDN博客

K8S动态PV供给-CSDN博客

k8s 使用StorageClass+NFS动态创建pv - yg0070 - 博客园 (cnblogs.com)

K3S/K8S 中动态创建 PVC 时 SelfLink 问题解决 - 知乎 (zhihu.com)

持久卷 | Kubernetes