zoukankan      html  css  js  c++  java
  • 再探共享存储


    文章 介绍了 pv,pvc 和 storageClass 以及其中的关系。这里将进一步深入探讨共享存储。

    1. 默认 storageClass

    创建 pvc 时不指定 storageClassName, 那么 kubernetes 将使用默认 storageClass 创建 pv。注意这里的不指定,是没有 storageClassName 字段,而不是 storageClassName 设为空。

    通过如下命令设置默认 storageClass:

    [root@chunqiu pv (Master)]# kubectl patch storageclasses.storage.k8s.io ocs-storagecluster-ceph-rbd -p 
    '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
    
    [root@chunqiu pv (Master)]# kubectl get storageclasses.storage.k8s.io
    NAME                    PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
    csi-cephfs              cephfs.csi.ceph.com            Delete          Immediate              true                   142d
    csi-cephrbd (default)   rbd.csi.ceph.com               Delete          Immediate              true                   142d
    

    storageClass 是集群级别资源,创建不指定 storageClassName 的 pvc 如下:

    [root@chunqiu pv (Master)]# cat pvcWithoutStorageClass.yaml
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: chunqiu-pvc-no-storageclass
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi
    
    [root@chunqiu pv (Master)]# kubectl apply -f pvcWithoutStorageClass.yaml -n chunqiu
    [root@chunqiu pv (Master)]# kubectl get pvc -n chunqiu
    NAME                                STATUS        VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    chunqiu-no-storageclass             Bound         pvc-d4207818-1d6a-4953-bc3f-d1dda5358239   1Gi        RWO            csi-cephrbd    5s
    

    可见,创建的 pvc 使用了默认 storageClass cephrbd。

    2. pv 资源回收

    查看前一节创建的默认共享存储 pvc-d4207818-1d6a-4953-bc3f-d1dda5358239:

    [root@chunqiu pv (Master)]# kubectl get pv pvc-d4207818-1d6a-4953-bc3f-d1dda5358239
    NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                             STORAGECLASS   REASON   AGE
    pvc-d4207818-1d6a-4953-bc3f-d1dda5358239   1Gi        RWO            Delete           Bound    chunqiu/chunqiu-no-storageclass   csi-cephrbd             47s
    

    需要重点介绍的是 pv 的 reclaim policy,它定义了回收 pv 的方式:

    • Delete: 删除 pvc 时,绑定到 pvc 上的 pv 会被删除;
    • Recycle:删除 pvc 时,pv 中存储的资源将被清理掉,此时状态为 Available 以供下一个 pvc 使用;
    • Retain: 删除 pvc 时,Retain 模式下的 pv 将会保留,其状态将置为 Released。

    问题在于 Released 状态下的 pv 并不能被下一个 pvc 使用,这是 Kubernetes 对资源的一种保护,防止不明用户使用 volume 的资源。那么,如果是同一个用户需要访问前一个 Released 的 pv 该怎么做呢?

    可以通过命令将 pv 的状态从 Released 更改为 Available,此时 pv 就可以同下一个 pvc 绑定在一起了,而且 pv 中存储的资源也并未被清楚。完整示例如下:

    # 更新 pv reclaim policy
    [root@chunqiu pv (Master)]# kubectl patch pv pvc-d4207818-1d6a-4953-bc3f-d1dda5358239 -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
    persistentvolume/pvc-d4207818-1d6a-4953-bc3f-d1dda5358239 patched
    
    [root@chunqiu pv (Master)]# kubectl get pv pvc-d4207818-1d6a-4953-bc3f-d1dda5358239
    NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                             STORAGECLASS   REASON   AGE
    pvc-d4207818-1d6a-4953-bc3f-d1dda5358239   1Gi        RWO            Retain           Bound    chunqiu/chunqiu-no-storageclass   csi-cephrbd             11m
    
    # 删除 pvc 查看 pv 状态
    [root@chunqiu pv (Master)]# kubectl delete pvc chunqiu-no-storageclass -n chunqiu
    persistentvolumeclaim "chunqiu-no-storageclass" deleted
    
    [root@chunqiu pv (Master)]# kubectl get pv pvc-d4207818-1d6a-4953-bc3f-d1dda5358239
    NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM                             STORAGECLASS   REASON   AGE
    pvc-d4207818-1d6a-4953-bc3f-d1dda5358239   1Gi        RWO            Retain           Released   chunqiu/chunqiu-no-storageclass   csi-cephrbd             13m
    

    删除 pvc 后,pv 状态更新为 Released,且 CLAIM 中绑定的 pvc 信息还在,即使 pvc 已经不在了!
    在这样状态下 pv 是不能再被下一个 pvc 绑定的,需要将其状态置为 Available 才行:

    [root@chunqiu pv (Master)]# kubectl edit pv pvc-d4207818-1d6a-4953-bc3f-d1dda5358239
    apiVersion: v1
    kind: PersistentVolume
    ...
    spec:
      accessModes:
      - ReadWriteOnce
      capacity:
        storage: 1Gi
      claimRef:
        apiVersion: v1
        kind: PersistentVolumeClaim
        name: chunqiu-no-storageclass
        namespace: chunqiu
        resourceVersion: "98551723"
        uid: d4207818-1d6a-4953-bc3f-d1dda5358239
    

    使用 edit 命令查看 pv manifest 信息,可以看到 claimRef 下定义了绑定的 pvc 信息,将 pvc 信息删掉即可将 pv 从 Released 更新为 Available。如果下一个绑定的 pvc 和上一个是同名同 namespace,也可以只将 uid 删除即可。查看两种情况下的 pv 表现:

    # edit 删除 uid,注意这里的删除,实际做的是将 uid 置成 null
    [root@chunqiu pv (Master)]# kubectl edit pv pvc-d4207818-1d6a-4953-bc3f-d1dda5358239
    claimRef:
        apiVersion: v1
        kind: PersistentVolumeClaim
        name: chunqiu-no-storageclass
        namespace: chunqiu
        resourceVersion: "98551723"
        uid: null
    
    # 查看状态已更新,且 ClAIM 信息任保留
    [root@chunqiu pv (Master)]# kubectl get pv pvc-d4207818-1d6a-4953-bc3f-d1dda5358239
    NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                             STORAGECLASS   REASON   AGE
    pvc-d4207818-1d6a-4953-bc3f-d1dda5358239   1Gi        RWO            Retain           Available   chunqiu/chunqiu-no-storageclass   csi-cephrbd             20m
    
    # edit 删除 claimRef,同样的实际操作是将 claimRef 置为 null
    [root@chunqiu pv (Master)]# kubectl edit pv pvc-d4207818-1d6a-4953-bc3f-d1dda5358239
    claimRef: null
    
    [root@chunqiu pv (Master)]# kubectl get pv pvc-d4207818-1d6a-4953-bc3f-d1dda5358239
    NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
    pvc-d4207818-1d6a-4953-bc3f-d1dda5358239   1Gi        RWO            Retain           Available           csi-cephrbd             23m
    

    再次创建 pvc:

    [root@chunqiu pv (Master)]# kubectl apply -f pvcWithoutStorageClass.yaml -n chunqiu
    persistentvolumeclaim/chunqiu-no-storageclass created
    
    [root@chunqiu pv (Master)]# kubectl get pvc -n chunqiu
    NAME                             STATUS        VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    chunqiu-no-storageclass             Bound         pvc-d4207818-1d6a-4953-bc3f-d1dda5358239   1Gi        RWO            csi-cephrbd    11s
    

    可以看到 pvc 重新绑定到 pv pvc-d4207818-1d6a-4953-bc3f-d1dda5358239 上!

    这里有一个小细节是 pvc 中使用的是默认 storageClass,storageClass 在创 pv 时,会查找集群中是否有满足条件的 pv,如果有则绑定到满足条件的 pv,而不是动态创建 pv!

    3. “升级”场景下的 pv

    前面说到“pvc 中使用的是默认 storageClass,storageClass 在创 pv 时,会查找集群中是否有满足条件的 pv,如果有则绑定到满足条件的 pv,而不是动态创建 pv”,这种查找机制会有什么问题吗?
    有的。

    设想这样一种情况,pod 和 pvc 关联,pvc 绑定到 pv 上。此时,需要做“升级”,升级方式是先将 pod 和 pvc 删除,然后更新 pod 中 container image 为最新版本,重新创建 pod 完成“升级”。示例如下:

    # 创建 pod
    [root@chunqiu pv (Master)]# cat pod-pvc.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: chunqiu
      labels:
        name: chunqiu
    spec:
      containers:
      - name: chunqiu
        image: chunqiu:18.4.0
        ports:
        - containerPort: 6379
      volumes:
      - name: update
        persistentVolumeClaim:
          claimName: chunqiu-no-storageclass
    
    [root@chunqiu pv (Master)]# kubectl apply -f pod-pvc.yaml -n chunqiu
    pod/chunqiu created
    [root@chunqiu pv (Master)]# kubectl get pods -n chunqiu
    NAME        READY   STATUS    RESTARTS   AGE
    chunqiu   1/1     Running   0          4s
    
    [root@chunqiu pv (Master)]# kubectl describe pvc chunqiu-no-storageclass -n chunqiu
    Name:          chunqiu-no-storageclass
    Namespace:     chunqiu
    StorageClass:  csi-cephrbd
    Status:        Bound
    Volume:        pvc-d4207818-1d6a-4953-bc3f-d1dda5358239
    Labels:        <none>
    Annotations:   pv.kubernetes.io/bind-completed: yes
                   pv.kubernetes.io/bound-by-controller: yes
    Finalizers:    [kubernetes.io/pvc-protection]
    Capacity:      1Gi
    Access Modes:  RWO
    VolumeMode:    Filesystem
    Mounted By:    chunqiu
    Events:        <none>
    

    可以看出,pvc 是以 pod 为单位 mount 的,如果 pod 内 container 需要访问 pv,需使用 volumeMounts 指定 pvc。

    删除 pod 和 pvc,更新 pod 内 container image:

    [root@chunqiu pv (Master)]# kubectl delete pods chunqiu -n chunqiu
    pod "chunqiu" deleted
    [root@chunqiu pv (Master)]# kubectl delete pvc chunqiu-no-storageclass -n chunqiu
    persistentvolumeclaim "chunqiu-no-storageclass" deleted
    
    # 更新 pv 状态
    [root@chunqiu pv (Master)]# kubectl get pv pvc-d4207818-1d6a-4953-bc3f-d1dda5358239 -n chunqiu
    NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM                       STORAGECLASS   REASON   AGE
    pvc-d4207818-1d6a-4953-bc3f-d1dda5358239   1Gi        RWO            Retain           Released   chunqiu/chunqiu-no-storageclass   csi-cephrbd             74m
    [root@chunqiu pv (Master)]# kubectl edit pv pvc-d4207818-1d6a-4953-bc3f-d1dda5358239
    persistentvolume/pvc-d4207818-1d6a-4953-bc3f-d1dda5358239 edited
    [root@chunqiu pv (Master)]# kubectl get pv pvc-d4207818-1d6a-4953-bc3f-d1dda5358239
    NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
    pvc-d4207818-1d6a-4953-bc3f-d1dda5358239   1Gi        RWO            Retain           Available           csi-cephrbd             75m
    
    # 更新 pod 内 container image(略)
    # 重新创建 pvc
    [root@chunqiu pv (Master)]# kubectl apply -f pvcWithoutStorageClass.yaml -n chunqiu
    persistentvolumeclaim/chunqiu-no-storageclass created
    [root@chunqiu pv (Master)]# kubectl get pvc -n chunqiu
    NAME                                STATUS   VOLUME                    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    chunqiu-no-storageclass             Bound    chunqiu-pv-volume         1Gi        RWO            csi-cephrbd    5s
    

    这里问题出现了,重新创建的 pvc 没有和 pv pvc-d4207818-1d6a-4953-bc3f-d1dda5358239 绑定,而是和集群中的另一个 Available pv chunqiu-pv-volume 绑定在一起。这对于“升级”来说是不可接受的,因为数据还存在原来的 pv pvc-d4207818-1d6a-4953-bc3f-d1dda5358239 上呢!

    这是在实际做“升级”及类似操作需要注意的地方,pvc 可能会绑定到集群中的其它符合条件的 pv 上,而不是前一个已经释放的 pv!

    4. storageClassName 为空 pvc

    前面说了 pvc 可以不加 storageClassName,那么使用的就是 Kubernetes 的默认 storageClassName。如果 storageClassName 置为"" 会出现什么情况呢?

    首先查看两个 pv 信息:

    [root@chunqiu pv (Master)]# kubectl describe pv chunqiu-pv-volume
    Name:            chunqiu-pv-volume
    Labels:          type=local
    Annotations:     pv.kubernetes.io/bound-by-controller: yes
    Finalizers:      [kubernetes.io/pv-protection]
    StorageClass:    csi-cephrbd
    ...
    
    [root@chunqiu pv (Master)]# kubectl describe pv chunqiu-pv-volume-empty
    Name:            chunqiu-pv-volume-empty
    Labels:          type=local
    Annotations:     pv.kubernetes.io/bound-by-controller: yes
    Finalizers:      [kubernetes.io/pv-protection]
    StorageClass:
    ...
    

    两个 pv 主要的不同是 storageClass,一个指定,一个未指定。当建 pvc 时,如果 storageClassName 置为空,那么 pvc 将使用已经创建的 storageClass 同样为空的 pvc,如果没有,则 pvc 创建失败。示例如下:

    [root@chunqiu pv (Master)]# kubectl get pv chunqiu-pv-volume
    NAME             CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
    chunqiu-pv-volume   1Gi        RWO            Retain           Available           csi-cephrbd             21m
    [root@chunqiu pv (Master)]# kubectl get pv chunqiu-pv-volume-empty
    NAME                   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
    chunqiu-pv-volume-empty   1Gi        RWO            Retain           Available                                   3h14m
    
    # 创建 storageClass 为空的 pvc
    [root@chunqiu pv (Master)]# cat pvcWithoutStorageClassEmpty.yaml
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: chunqiu-storageclass-empty
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi
      storageClassName: ""
    
    [root@chunqiu pv (Master)]# kubectl apply -f pvcWithoutStorageClassEmpty.yaml -n chunqiu
    persistentvolumeclaim/chunqiu-storageclass-empty created
    [root@chunqiu pv (Master)]# kubectl get pvc -n chunqiu
    NAME                      STATUS   VOLUME                 CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    chunqiu-storageclass-empty   Bound    chunqiu-pv-volume-empty   1Gi        RWO                           4s
    

    可以看到,绑定到先前创建的同样为 storageClass 为空的 pv chunqiu-pv-volume-empty 上。相反地,删除 storageClass 为空的 pv,查看 pvc 能否绑定:

    [root@chunqiu pv (Master)]# kubectl delete pvc chunqiu-storageclass-empty -n chunqiu
    persistentvolumeclaim "chunqiu-storageclass-empty" deleted
    [root@chunqiu pv (Master)]# kubectl delete pv chunqiu-pv-volume-empty
    persistentvolume "chunqiu-pv-volume-empty" deleted
    
    [root@chunqiu pv (Master)]# kubectl apply -f pvcWithoutStorageClassEmpty.yaml -n chunqiu
    persistentvolumeclaim/chunqiu-storageclass-empty created
    [root@chunqiu pv (Master)]# kubectl get pvc -n chunqiu
    NAME                      STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    chunqiu-storageclass-empty   Pending    
                                                     4s
    [root@chunqiu pv (Master)]# kubectl describe pvc chunqiu-storageclass-empty -n chunqiu
    Name:          chunqiu-storageclass-empty
    ...
      Type    Reason         Age                From                         Message
      ----    ------         ----               ----                         -------
      Normal  FailedBinding  13s (x2 over 13s)  persistentvolume-controller  no persistent volumes available for this claim and no storage class is set
    

    5. “deployment” 和 pvc

    这里结合 pvc 讨论 deployment 的创建和升级场景。

    deployment 下有多个 pods,多个 pods 可以绑定到一个 pvc 上,多个 pvc 也可以绑定到一个 pod 上。那么在滚动升级时由于 deployment 的 pod 会交替升级,那么中间和 pvc 的绑定,解绑就要考虑到,不过升级的最终结果是一样的,原来几个 pods 绑定的 pvc,升级之后也是一样的。

    有一种情况是使用重建的方式更新 pods,如果重建前后 pvc 有变动那么很有可能更新会失败。譬如,重建前 pod 绑定在一个 pvc 上,重建后 pod 需绑定到两个 pvc,且多出来的 pvc 并没有创建。这样的场景下重建更新是会失败的。

    芝兰生于空谷,不以无人而不芳。
  • 相关阅读:
    jQuery标准的AJAX模板
    maven库
    在 Windows7 上按照 MySQL5.7
    如何保证代码的有效性
    项目负责人的职责
    string integer == equals 转
    走近AbstractQueuedSynchronizer
    STAR
    tesseract-ocr
    Spring @Qualifier l转
  • 原文地址:https://www.cnblogs.com/xingzheanan/p/15230251.html
Copyright © 2011-2022 走看看