• k8s之PV、PVC和StorageClass


    PV

    什么是PV?

    PV 描述的,则是一个具体的 Volume 的属性,比如 Volume 的类型、挂载目录、远程存储服务器地址等。

    创建PV

    使用yaml来定义PV

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: nfs-1g-pv
    
    spec:
      storageClassName: nfs
      accessModes:
        - ReadWriteMany
      capacity:
        storage: 1Gi
    
      nfs:
        path: /root/zwf/share
        server: 10.64.2.153
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    参数说明:

    • storageClassName的值为nfs,使用了NFS网络文件系统作为存储卷,
    • accessModes的值为ReadWriteMany,支持多个节点同时读写该共享目录
    • storage的值为1Gi,分配了1G的存储空间

    使用yaml定义的描述文件来创建PV对象

    [root@k8s-worker1 zwf]# kubectl apply -f pv.yaml -n zwf
    persistentvolume/nfs-1g-pv created
    [root@k8s-worker1 zwf]# kubectl get pv -n zwf
    NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                           STORAGECLASS   REASON   AGE
    nfs-1g-pv   1Gi        RWX            Retain           Available                                   nfs                     12s
    
    • 1
    • 2
    • 3
    • 4
    • 5

    PVC

    什么是PVC?

    提供给应用开发获取存储资源的对象,开发将pod与PVC进行绑定可以达到持久化的存储状态,而PVC会与相对应的PV相绑定,提供具体的存储空间。

    PV和PVC有什么区别?

    实际上类似于“接口”和“实现”的思想。开发者只要知道并会使用“接口”,即:PVC;而运维人员则负责给“接口”绑定具体的实现,即:PV。

    创建PVC

    有了pv之后,创建申请存储的PVC对象,yaml定义如下,定义的内容和PV基本相同,但是不包含NFS的存储细节。

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: nfs-static-pvc
    
    spec:
      storageClassName: nfs
      accessModes:
        - ReadWriteMany
    
      resources:
        requests:
          storage: 1Gi
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    创建pvc对象,并且可以看到VOLUME的值是上面创建的pv对象,这样两者就进行绑定了。

    [root@k8s-worker1 zwf]# kubectl apply -f pvc.yaml -n zwf
    persistentvolumeclaim/nfs-static-pvc created
    [root@k8s-worker1 zwf]# 
    [root@k8s-worker1 zwf]# kubectl get pvc -n zwf
    NAME             STATUS   VOLUME      CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    nfs-static-pvc   Bound    nfs-1g-pv   1Gi        RWX            nfs            9s
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    我们再pvc文件中并没有填写pv的任何信息,它是如何知道该绑定那个pv对象的呢?这是因为pvc会根据自身需要的容量去找到对应的pv进行匹配绑定。

    在Pod中申请PVC

    Pod的yaml定义如下,使用volumes定义了存储卷使用上面创建的pvc对象nfs-static-pvc,在containers中使用vlumeMounts在pod中挂载了/tmp目录在该存储卷中。

    apiVersion: v1
    kind: Pod
    metadata:
      name: nfs-static-pod
    
    spec:
      volumes:
      - name: nfs-pvc-vol
        persistentVolumeClaim:
          claimName: nfs-static-pvc
    
      containers:
        - name: nfs-pvc-test
          image: nginx:alpine
          ports:
          - containerPort: 80
    
          volumeMounts:
            - name: nfs-pvc-vol
              mountPath: /tmp
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    创建pod后,我们进入pod中在/tmp写入数据

    [root@k8s-worker1 zwf]# kubectl apply -f pod_pvc.yaml -n zwf
    pod/nfs-static-pod created
    
    [root@k8s-worker1 zwf]# kubectl exec -it nfs-static-pod -n zwf -- /bin/sh
    / # cd /tmp
    /tmp # echo 222 > 2.txt
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在nfs服务器中的/root/zwf/share中,我们也可以看到上面写的数据

    [root@k8s-worker2 share]# pwd
    /root/zwf/share
    [root@k8s-worker2 share]# ls
    2.txt
    [root@k8s-worker2 share]# cat 2.txt
    222
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Pod、PVC、PV 和 NFS 存储的关系可以用下图来形象地表示:

    StorageClass

    上面的PV是需要管理员手动创建的,每一次的开发都需要根据需求逐个创建PV,并且还需要精确创建空间大小,导致工作量巨大。所以我们需要在开发中可以动态的创建PV。

    StoreageClass可以用来绑定Provisioner对象,而这个Provisioner就是一个能够自动管理存储、创建 PV 的应用,代替了原来系统管理员的手工劳动。

    通过StorageClass配置NFS Provisioner

    k8s中每一类的存储设备都有相应的Provisioner,这里我们使用的是NFS Provisioner(https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner)

    在 GitHub 的 deploy 目录里是部署它所需的 YAML 文件,一共有三个,分别是 rbac.yamlclass.yaml deployment.yaml

    1. 首先将rbac.yaml的namespace改成kube-system
    2. 在修改deployment.yaml的namespace也改为kube-system,再修改其中的volumes 和 env 里的 IP 地址和共享目录名,与NFS服务器保持一致.
    spec:
      template:
        spec:
          serviceAccountName: nfs-client-provisioner
          containers:
          ...
              env:
                - name: PROVISIONER_NAME
                  value: k8s-sigs.io/nfs-subdir-external-provisioner
                - name: NFS_SERVER
                  value: 192.168.10.208        #改IP地址
                - name: NFS_PATH
                  value: /tmp/nfs              #改共享目录名
          volumes:
            - name: nfs-client-root
              nfs:
                server: 192.168.10.208         #改IP地址
                Path: /tmp/nfs                 #改共享目录名
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    再将k8s.gcr.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2改成chronolaw/nfs-subdir-external-provisioner:v4.0.2

    1. 最后创建NFS Provisioner
    kubectl apply -f rbac.yaml
    kubectl apply -f class.yaml
    kubectl apply -f deployment.yaml
    
    • 1
    • 2
    • 3

    查看kube-system的pod可以看到nfs的provisioner。

    [root@k8s-worker1 zwf]# kubectl get pods -n kube-system
    NAME                                      READY   STATUS    RESTARTS      AGE
    nfs-client-provisioner-57789d96b7-42q67   1/1     Running   0             22h
    
    • 1
    • 2
    • 3

    使用NFS动态存储卷

    创建StrogeClass对象,onDelete: "remain"代表着即使Pod被删除,也会保留分配的存储,之后再手动删除。

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: nfs-client
    
    provisioner: k8s-sigs.io/nfs-subdir-external-provisioner 
    parameters:
      onDelete: "remain"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    创建StrageClass对象,并可以看到PROVISIONER已经绑定了我们上面创建的nfs-provisioner了。

    [root@k8s-worker1 zwf]# kubectl apply -f pvc_dyn.yaml -n zwf
    storageclass.storage.k8s.io/nfs-client-retained created
    
    [root@k8s-worker1 zwf]# kubectl get sc -n zwf
    NAME                  PROVISIONER                                   RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
    nfs-client   k8s-sigs.io/nfs-subdir-external-provisioner   Delete          Immediate           false                  21h
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    定义PVC,配置storageClassName:nfs-client与上面的StrageClass对象相绑定。

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: nfs-dyn-10m-pvc
    
    spec:
      storageClassName: nfs-client
      accessModes:
        - ReadWriteMany
    
      resources:
        requests:
          storage: 10Mi
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    创建PVC,然后你会发现STATUS的状态为Bound,已经自动的创建了PV,并且已经相互绑定。

    [root@k8s-worker1 zwf]# kubectl get pvc -n zwf
    NAME              STATUS    VOLUME      CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    nfs-dyn-10m-pvc   Pending                                         nfs-client     25s
    
    [root@k8s-worker1 zwf]# kubectl get pvc -n zwf
    NAME              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    nfs-dyn-10m-pvc   Bound    pvc-292cfed3-bec8-4425-aeac-697e3740c76c   10Mi       RWX            nfs-client     9s
    
    [root@k8s-worker1 zwf]# kubectl get pv -n zwf
    NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                           STORAGECLASS   REASON   AGE
    pvc-292cfed3-bec8-4425-aeac-697e3740c76c   10Mi       RWX            Delete           Bound    zwf/nfs-dyn-10m-pvc             nfs-client              47s
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    去NFS文件服务器的共享目录中查看,可以看到多出来了一个目录,目录名称为命名空间-pvc名称-pvc名称

    [root@k8s-worker2 share]# pwd
    /root/zwf/share
    [root@k8s-worker2 share]# ls
    zwf-nfs-dyn-10m-pvc-pvc-292cfed3-bec8-4425-aeac-697e3740c76c
    
    • 1
    • 2
    • 3
    • 4

    定义Pod,挂载上面创建的PVC到容器的/tmp目录中

    apiVersion: v1
    kind: Pod
    metadata:
      name: nfs-dyn-pod
    
    spec:
      volumes:
      - name: nfs-dyn-10m-vol
        persistentVolumeClaim:
          claimName: nfs-dyn-10m-pvc
    
      containers:
        - name: nfs-dyn-test
          image: nginx:alpine
    
          volumeMounts:
            - name: nfs-dyn-10m-vol
              mountPath: /tmp
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    创建Pod成功

    [root@k8s-worker1 zwf]# kubectl apply -f pod_strageclass.yaml -n zwf
    pod/nfs-dyn-pod created
    [root@k8s-worker1 zwf]# kubectl get pods -n zwf
    NAME          READY   STATUS    RESTARTS   AGE
    nfs-dyn-pod   1/1     Running   0          10s
    
    • 1
    • 2
    • 3
    • 4
    • 5

    进入到挂载了pvc的pod,然后在/tmp目录下写一个文件

    kubectl exec -it nfs-dyn-pod -n zwf -- /bin/sh
    / # cd /tmp
    /tmp # echo 111 > 3.txt
    
    • 1
    • 2
    • 3

    再到NFS服务器上的共享目录对应的pv目录下,能看到之前写的文件。

    [root@k8s-worker2 zwf-nfs-dyn-10m-pvc-pvc-292cfed3-bec8-4425-aeac-697e3740c76c]# pwd
    /root/zwf/share/zwf-nfs-dyn-10m-pvc-pvc-292cfed3-bec8-4425-aeac-697e3740c76c
    
    [root@k8s-worker2 zwf-nfs-dyn-10m-pvc-pvc-292cfed3-bec8-4425-aeac-697e3740c76c]# cat 3.txt 
    111
    
    • 1
    • 2
    • 3
    • 4
    • 5

    关系图如下:

    欢迎关注,互相学习,共同进步~

    我的个人博客

    我的微信公众号:编程黑洞

  • 相关阅读:
    周记之重新开始
    2-多媒体数据压缩国际标准
    关于时空数据的培训 GAN:实用指南(第 01/3 部分)
    RK3399平台开发系列讲解(内核调试篇)2.50、嵌入式产品启动速度优化
    Python二分查找详解
    tokenizers normalizers模块
    微信小程序SEO指南
    SIM800C连接OneNet平台HTTP协议上传GPS数据
    工厂方法模式 创建型模式之四
    下载神器-IDM使用教程及下载
  • 原文地址:https://blog.csdn.net/qq_22918243/article/details/126671073