1. 基本概念

在 Kubernetes(K8S)中,PV(PersistentVolume)PVC(PersistentVolumeClaim) 是用于持久化存储的核心概念,它们之间的关系可以理解为“资源提供者”和“资源请求者”。

两者的关系:

组件

角色

描述

PV

提供者

是由管理员预先创建或动态创建的持久存储资源,类似于云硬盘、NFS、iSCSI 等

PVC

请求者

是用户(开发者)对存储资源的申请,声明需要多大、访问模式等

Binding

绑定

当 PVC 与符合条件的 PV 匹配成功后,会进行绑定(Binding),然后 Pod 就可以挂载使用了

类比理解:

  • PV是"房屋出租",由管理员提供

  • PVC是租房需求,由用户发出

  • 系统根据条件匹配合适的房子(PV)给租户(PVC),一旦绑定,PVC 就“住进去”了。

2. 实践操作

  1. 创建pv

--- 1. 准备nfs的存储路径
mkdir -p /data/nfs/pv/pv001
--- 2. 创建PV
apiVersion: v1
kind: PersistentVolume
metadata:
  name: linux-pv
  labels:
    commpany: pexetech
spec:
  accessModes:
  - ReadWriteMany
   #   声明PV的访问模式,常用的有"ReadWriteOnce","ReadOnlyMany"和"ReadWriteMany":
   #   ReadWriteOnce:(简称:"RWO")
   #      只允许单个worker节点读写存储卷,但是该节点的多个Pod是可以同时访问该存储卷的。
   #   ReadOnlyMany:(简称:"ROX")
   #      允许多个worker节点进行只读存储卷。
   #   ReadWriteMany:(简称:"RWX")
   #      允许多个worker节点进行读写存储卷。
   #   ReadWriteOncePod:(简称:"RWOP")
   #       该卷可以通过单个Pod以读写方式装入。
   #       如果您想确保整个集群中只有一个pod可以读取或写入PVC,请使用ReadWriteOncePod访问模式。
  nfs:
   server: 192.168.0.78
   path: /data/nfs/pv/pv001
   #   指定存储卷的回收策略,常用的有"Retain"和"Delete"
   #    Retain:
   #       "保留回收"策略允许手动回收资源。
   #       删除PersistentVolumeClaim时,PersistentVolume仍然存在,并且该卷被视为"已释放"。
   #       在管理员手动回收资源之前,使用该策略其他Pod将无法直接使用。
   #    Delete:
   #       对于支持删除回收策略的卷插件,k8s将删除pv及其对应的数据卷数据。
   #    Recycle:
   #       对于"回收利用"策略官方已弃用。相反,推荐的方法是使用动态资源调配。
  persistentVolumeReclaimPolicy: Retain
  ## 声明存储卷的容量
  capacity: 
    storage: 2Gi
  1. 查看PV信息:

Name:            linux-pv   ## PV的名称
StorageClass:               ## sc的名称
Status:          Available  ## PV的状态
Claim:                      ## PV被哪个PVC使用
Reclaim Policy:  Retain     ## PV的回收策略
Access Modes:    RWX        ## PV的访问模式
Capacity:        2Gi        ## PV的容量
  1. 创建PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: linux-pvc
  labels:
    commpany: pexetech
spec:
  ## 声明资源的访问模式
  accessModes:
  - ReadWriteMany
  ## 声明资源的使用量
  resources:
    requests:
      storage: 2Gi
  ## 绑定上面的pv
  volumeName: linux-pv
  1. 创建资源清单

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-pvc
spec:
  replicas: 2
  selector:
    matchExpressions:
    - key: apps
      operator: Exists
  template:
    metadata:
      labels:
        apps: nginx
    spec:
      volumes:
      - name: data
        # 声明是一个PVC类型
        persistentVolumeClaim:
          # 引用哪个PVC
          claimName: linux-pvc
      containers:
      - name: web
        image: '192.168.0.77:32237/uat/nginx:1.22'
        volumeMounts:
        - name: data
          mountPath: /usr/share/nginx/html
  1. 创建service 资源清单

apiVersion: v1
kind: Service
metadata:
  name: pvc-nginx 
spec:
  type: NodePort
  selector:
    apps: nginx
  ports:
  - port: 80
    targetPort: 80
    nodePort: 30083
  1. PV的回收策略

当PV的回收策略是Retain,PV和PVC是无法直接被删除的,需要我们用补丁的当时回收

# 手动删除 PVC(如果还存在)
kubectl delete pvc my-pvc

# 然后重置 PV 的绑定信息(解除绑定)
kubectl patch pv my-pv -p '{"spec":{"claimRef": null}}'

# 最后删除 PV
kubectl delete pv my-pv
  1. PVC处于Terminating 状态卡住

kubectl get pvc my-pvc -o json | jq .metadata.finalizers
## 如果结果类似:
["kubernetes.io/pvc-protection"]

## 可以强制移除
kubectl patch pvc my-pvc -p '{"metadata":{"finalizers": []}}' --type=merge
kubectl delete pvc my-pvc

3. StorageClass动态存储类实践

说明:

  1. k8s组件原生并不支持NFS动态存储

https://kubernetes.io/docs/concepts/storage/storage-classes/

  1. NFS不提供内部配置器实现动态存储,但可以使用外部配置器

--- 1. 拉去开源配置器
apt install -y git 


--- 2. 修改配置文件
cd k8s-external-storage/nfs-client/deploy
vim deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  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
      containers:
        - name: nfs-client-provisioner
          ## 这里镜像是 nfs-subdir-external-provisioner:latest   
          image: 192.168.0.77:32237/uat/nfs-subdir-external-provisioner:latest 
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs
            - name: NFS_SERVER
              value: 192.168.0.78 
            - name: NFS_PATH
              value: /data/nfs/sc
      volumes:
        - name: nfs-client-root
          nfs:
            ## 配置nfs服务端的ip地址和路径    
            server: 192.168.0.78 
            path: /data/nfs/sc

--- 3. 修改动态存储类的配置文件
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
## 这里的fuseim.pri/ifs 要和上面的env 中的PROVISIONER_NAME 的值相同哦
provisioner: fuseim.pri/ifs 
parameters:
  archiveOnDelete: "true"

--- 4. nfs 服务器创建sc共享路径
mkdir -p /data/nfs/sc

--- 5. 创建动态存储类
kubectl apply -f class.yaml

--- 6. 创建授权角色
kubectl apply -f rbac.yaml

--- 7. 部署nfs动态存储配置器
kubectl apply -f deployment.yaml

--- 8. 测试动态存储类pvc

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim-001
spec:
  storageClassName: managed-nfs-storage
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 20Mi

--- 9. 测试pod
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-pvc
spec:
  replicas: 2
  selector:
    matchExpressions:
    - key: apps
      operator: Exists
  template:
    metadata:
      labels:
        apps: nginx
    spec:
      volumes:
      - name: data
        # 声明是一个PVC类型
        persistentVolumeClaim:
          # 引用哪个PVC
          claimName: test-claim-001 
      containers:
      - name: web
        image: '192.168.0.77:32237/uat/nginx:1.22'
        volumeMounts:
        - name: data
          mountPath: /usr/share/nginx/html