TOC

volumes

    Kubernetes上使用存储卷,大致分为两个步骤,首先我们需要在Pod上去定义存储卷,所以在Pod的spec当中使用volume把存储卷定义起来,而后我们需要在容器中去定义要使用的存储卷,但是这种存储卷的使用方式在spec.volumes当中去定义存储卷时,必须要明确,且清晰的给出访问存储系统的客户端配置信息,这对很多终端用户来讲,几乎是不可能完成的任务,尤其是遇到非常复杂的存储系统时更是如此,因此这种方式其实有背于Kubernetes提出的生产者消费者模型,所谓生产消费指的是提供存储能力的一方提供存储,那么消费者只需要向存储放说明它要使用多少存储就可以了,而无需关注存储系统的细节,很显然,在spec.volumes定义的使用方式是无法满足这种需求的,为此Kubernetes系统为了使得存储服务,也能够转为生产消费者模型机制,它为Kubernetes的volumes和volumeMounts以及和后端的存储设备之间增加了一个中间层,这个中间层我们就称之为PV;
PV(persistentVolumeClaim)
    正常情况下在一个Pod当中,应该在一个pause容器上直接使用spec.volumes去定义这个存储卷是什么,然后再去容器中去使用volumeMounts挂在到容器内部,而这个存储系统是直接关联到我们的pause容器上的;
    有了PV之后,就意味着在这个所谓的spec.volumes和存储系统之间增加了一个中间层,首先我们把存储系统所提供的的存储能力给它抽象成Kubernetes之上的一个标准类型的资源,这资源就是PV;
    但是需要注意的是,存储系统与PV不是一一对应的关系,存储系统上的每一个存储空间对应一个PV,就是说一个存储系统,比如我们的nfs,可以暴露出/data/v1、/data/v2两个存储空间,他们分别可以对应两个PV,两个PV之间是两个不同的PV资源,而不是直接把nfs存储系统对应一个PV,所以PV对应的是后端存储系统之上可被单个访问逻辑存储单元,所以我们需要使用存储系统上的资源的时候,我们就需要把存储系统之上切分出来的多个存储逻辑单元映射为一个又一个的PV;
使用PV以及PV几种状态
    正常情况下,PV在kubernetes之上是属于集群级别的资源(在kubernetes之上资源有两种级别第一个集群级别,第二个名称空间级别)默认不属于任何一个名称空间,但是Pod又属于名称空间,所以随后我们要想在名称空间中使用PV,还需要把PV注册到名称空间去,而且PV和名称空间也是一对一的,意思是它被A名称空间占据了,B名称空间就不能使用了;
    比如说有一个名称空间叫做myns,中有一个Pod视图使用PV1,这个时候它需要首先把PV1给占据,所谓占据就是在myns这个名称空间中创建一个PVC,所谓PVC就是请求占据PV,因此我们作为用户来讲,应该在名称空间创建一个PVC,PVC和PV之间并没有直接关联关系,但是PVC是请求占据PV的,因此如果你定义了一个PVC并请求占据一个PV,那PVC和PV之间就能建立关系了,这种占用模式我们称之为binding,如果一个PV没有被binding,说明它是空闲的,状态为available,一旦一个名称空间通过PVC占用了PV,这个名称空间中就可以有一个Pod去使用PVC了,然PVC使用PV,所以当我们删除Pod没有删除PVC的时候,这个PVC依然存在,所以当我们在同一个名称空间创建一个新的Pod还使用这个Pod,数据依然可以访问,那么如果我们把Pod删除了,PVC也删除了,那么此时我们的PV的状态处于reclim回收PV状态;
    PVC删除会影响PV,会对PV进行回收,因为PV里面是还有数据的,所以删除PVC针对PV的回收策略的方式有三种,delete删了PVC也删除PV,recycle(已经废弃)删除PVC就清空PV数据,retain删除PVC保留PV和PV里面的数据,此时我们的PV是不会被调度使用的,因为里面还有数据;

binding:绑定状态,也就是说该pv已经绑定到了一个名称空间;
availble:可用状态,也就是说改pv可以供名称空间申请绑定;
reclaim:回收状态,表示pvc已删除,处于回收状态,回收有三种逻辑;
    recycle:删除pvc之后,清空对应pv里面的数据;
    delete(废弃):删除pvc同时删除pv;
    retain:删除pvc,pv和数据都保留;
使用PVC多路读写
    我们还可以让多个Pod同时访问一个PVC,如果这个PV后面的存储系统是NFS,因为NFS是支持多路读写的,所以在这个层面来说底层是支持多路读写的,那么我们在定义PV的时候还可以再进行一次限制,可以指定三种访问方式,单路读写、多路读写、多路只读,而一个PVC访问PV时,PVC的访问能力就不能超出PV的访问能力,PV也不能超出底层存储系统的访问能力,所以在定义PVC的时候也需要指定和PV一样的三种访问方式,
PV生命周期
    PV供给有两种方式,第一我们称之为静态提供逻辑,也就是说由管理员手动创建的,第二动态供给,所谓动态供给指的是,有一个存储系统,这个存储系统有很多可以使用的逻辑存储单元,但是它没有直接定义为PV,只有当用户需要在某一个名称空间中创建PVC的时候,它可以根据用户请求的需要来动态创建PV,比如说创建PVC的时候指定stroage定义了一个1Gi的存储空间,那么这个时候就可以根据用户的请求按需找出底层存储空间最合适的一个存储逻辑单元,给它动态创建成PV,并且让PV和PVC二者绑定起来,这就叫动态供给,而这种动态供给要求存储系统要实现存在多个逻辑存储单元,这个多个存储单元在必要时能满足PVC的请求,自动的创建成为PV;
    还有一种机制,能实现这个存储系统上所需要的逻辑存储单元,也不存在,只有存储空间,没有划分逻辑存储单元(就像windows的磁盘没格式化一样),当用户创建PVC的时候,根据用户的请求,动态的调用存储系统的管理接口,去创建一个刚好满足PVC需求的逻辑存储单元,再把这个存储单元创建成为Kunbernetes集群上的PV,然后再与PVC绑定,但这个得有一个基本的前提条件就是对应的存储系统需要支持restfull接口的API,才可以,比如我们的ceph就支持,NFS不支持;
    所以我们整个PV的生命周期,第一先供给,第二供给完成之后就可以绑定了,第三绑定完成之后就可以使用了,第四用完了就可以回收了;

    我们的pvc创建能够为什么创建时,能触发还能动态供给pv,这个功能还需要依赖于一个存储类,storgaeClass,也就是说,我们需要事先在这个kubernetes之上,将这个外部的存储系统,比如ceph,在kubernetes之上先定义一个另外类型的存储资源,我们称之为存储类storgaeClass,当创建一个pvc时,pvc不是向存储系统请求,而是向storgaeClass请求,而storgaeClass已经配置了如何去连接这个外部的存储系统的管理接口,它里面配置好了各种各样的连接参数,并且知道怎么连接到底层的存储系统管理接口,在必要的时候调用管理接口创建一个逻辑存储单元,并自动的在当前storgaeClass内部创建一个PV,所以pv是属于storgaeClass的,一个pvc去请求一个pv时,如果通过storgaeClass来实现,那么pvc也属于storgaeClass,所以PV和PVC就可以分为两类了,属于某个storgaeClass和不属于某个storgaeClass。还需要注意的是,PVC只能向同一个storgaeClass中的PV请求绑定,就是PVC属于storgaeClass1,那它之内向storgaeClass1内的PV请求绑定,不能跨存储类,如果一个PVC不属于任何storgaeClass那么它所绑定的PV也一定不属于任何storgaeClass的;
pv简单使用
# 在各个节点上安装nfs
[root@node1 ~]# yum install -y nfs-utils
[root@node2 ~]# yum install -y nfs-utils
[root@node3 ~]# yum install -y nfs-utils
# 创建数据目录
[root@node1 ~]# mkdir -pv /data/volumes{1..5}
# 配置nfs共享
[root@node1 ~]# cat /etc/exports
/data/volumes1  172.16.0.0/16(rw,sync,no_root_squash)
/data/volumes2  172.16.0.0/16(rw,sync,no_root_squash)
/data/volumes3  172.16.0.0/16(rw,sync,no_root_squash)
/data/volumes4  172.16.0.0/16(rw,sync,no_root_squash)
/data/volumes5  172.16.0.0/16(rw,sync,no_root_squash)
[root@node1 ~]# exportfs -rav
[root@node1 ~]# systemctl start nfs
# 定义pv
[root@node1 ~]# cat pv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-v1
spec:
  capacity:
    storage: 5Gi
  persistentVolumeReclaimPolicy: Delete # pvc删除策略
  accessModes:
  - ReadWriteOnce
  - ReadOnlyMany
  - ReadWriteMany
  nfs:
    path: /data/volumes1
    server: 172.16.1.2
[root@node1 ~]# kubectl get pv          
NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv-nfs-v1   5Gi        RWO,ROX,RWX    Delete           Available                                   27s # Available状态
# 定义pvc
[root@node1 ~]# cat pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-nfs-v1
  namespace: pv
spec:
  accessModes: # 访问模式是读写还是只读
  - ReadWriteOnce
  volumeMode: Filesystem  # 是文件系统还是块设备
  resources:
    requests:
      storage: 1024Mi
[root@node1 ~]# kubectl get pv
NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM           STORAGECLASS   REASON   AGE
pv-nfs-v1   5Gi        RWO,ROX,RWX    Delete           Bound    pv/pvc-nfs-v1                           8m23s # Bound状态
# 创建pod使用pvc
[root@node1 ~]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: vol-test
  namespace: pv
spec:
  hostNetwork: true
  restartPolicy: Always
  containers:
  - name: vol-pod
    image: busybox:latest
    command:
    - /bin/httpd
    - -f
    - -h
    - /data
    volumeMounts:
    - name: code
      mountPath: /data
  volumes:
  - name: code
    persistentVolumeClaim:  # 使用persistentVolumeClaim方式
      claimName: pvc-nfs-v1 # 指定pvc的名称
# 查看分配的节点
[root@node1 ~]# kubectl get pods -n pv -o wide    
NAME       READY   STATUS    RESTARTS   AGE   IP           NODE            NOMINATED NODE   READINESS GATES
vol-test   1/1     Running   0          80s   172.16.1.3   node2.cce.com   <none>           <none>
# 测试
[root@node1 ~]# echo 1 > /data/volumes1/index.html
[root@node1 ~]# curl 172.16.1.3                   
1
[root@node1 ~]# echo 1 >> /data/volumes1/index.html 
[root@node1 ~]# curl 172.16.1.3                    
1
1

存储类

    有的时候我们可能有这样的场景,有nfs存储一套,有ceph存储一套,还有云端存储两套,可能云存储的两套其中一套是aws的,也可能是micosoft的,那这四组存储系统在kubernetes上可能需要进行分类,因为有的慢,有的快,有的存取能力强,有的存取能力差,所以我们不同的Pod中的应用应该根据它的实际需要分配给它一个最佳的存储设备,比如只是一个测试使用的Pod应用,我们给它一个nfs这种比较慢的也没什么问题,但是一个要求IO非常强大,最好从ceph中分配,如果期望能够在互联网上访问,那么我们可以使用云存储去分;
    一般来讲,我们可以根据这个存储设备的综合性能指标,来给它分类,这就叫做存储类,把分类出来的存储设备归类到对应的存储设备当中,所以我们就称之为其为存储类;
    有了存储类之后,我们在某个名称空间当中再去使用某个pvc时,这个pvc也需要向某个存储类来申请,所以这个时候pvc就属于某个存储类,而在这个存储类当中有pv,因为pv是真正把存储设备的存储空间映射至kubernetes标准资源,而pv属于存储类的话,pvc就必须要在同一个存储类,所以pvc向某一个存储类请求一定是在同一个类下有某一个pv要满足需要;
    存储类的pv,和上面还是一样的两种方式第一静态手动创建、动态供给,一旦有了存储类,我们就可以使用底层存储系统的供给功能了,但是动态供给支持与否是取决于存储系统的,存储类也是标准的kubernetes资源;

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注