Kubernetes学习之PV、PVC

一、认识PV、PVC
  PersistentVolume(PV)是指集群管理员配置提供的某存储系统上的一段存储空间,它是对底层共享存储的抽象,将共享存储作为一种可由用户申请使用的资源,实现了"存储消费"机制。通过存储插件,PV支持使用多种网络存储或云端存储等多种后端存储系统,例如,前面使用到的NFS、还有其他的如RBD、Cinder等。PV是集群级别的资源,不属于任何的名称空间,用户对PV资源的使用需要通过PersistentVolumeClaim(PVC)提出的使用申请(或称为声明)来完成绑定,PVC是PV资源对象的消费者,它向PV申请特定大小的空间及访问模式(如读写或只读),从而创建出PVC存储卷,而后再由Pod资源通过PersistentVolumeClaim存储卷关联使用。
Kubernetes学习之PV、PVC_第1张图片
  尽管PVC使得用户可以以抽象的方式访问存储资源,但是很多时候还是会涉及到PV的不少属性,例如,用于不同场景时设置的性能参数等。为此,集群管理员不得不通过多种方式提供多种不同的PV以满足用户不同的使用需求,两者衔接上的偏差必然会导致用户的需求无法全部及时有效的得到满足。Kubernetes自1.4版本起引入了一个新的资源对象StorageClass,可用于将存储资源定义为具有显着特性的类别(Class)而不是具体的PV,例如"fast"、“slow"或"glod”、“silver”、"bronze"等等。用户通过PVC直接向意向的类别发出申请,匹配由管理员事先创建的PV,或者由其按需为用户动态创建PV,这样做甚至免去了需要事先创建PV的过程。

二、Kubernetes的存储系统

Kubernetes学习之PV、PVC_第2张图片
Kubernetes学习之PV、PVC_第3张图片
Kubernetes学习之PV、PVC_第4张图片

Kubernetes学习之PV、PVC_第5张图片
Kubernetes学习之PV、PVC_第6张图片
  Kubernetes挂载Volume的过程
  1)用户创建一个好汉PVC的Pod(使用动态存储卷);
  2)PV Controller发现这个PVC处于待绑定状态,调用Volume-Pliugin(in-tree或out-of-tree)创建存储卷;并创建PV对象,并将创建的PV与PVC绑定;
  3)Scheduler根据Pod配置、节点状态、PV配置等信息,把Pod调度到Worker节点Node上;
  4)AD Controller发现Pod处于待挂载状态,调用Volume Plugin(in-tree或out-of-tree)实现设备挂载到目标节点(/dev/sdb);
  5)在Worker节点上,Kubelet(Volume Manager)等待设备挂载完成,通过Volume Plugin将设备挂载至指定目录:/var/lib/kubelet/pods/f9433060-ba17-4ab5-96b3-4aacd1dc0dd6/volumes/
  6)Kubelet在被告知挂载目录准备好后,启动Pod中的containers,用Docker -v方式(bind)将已经挂载到本地的卷映射到容器中;
Kubernetes学习之PV、PVC_第7张图片

三、创建PV
  PersistentVolume Spec主要支持以下几个通用字段,用于定义PV的容量、访问模式和回收策略。
  Capacity:当前PV的容量;目前,Capacity仅支持空间设定,将来应该还可以指定IOPS和throughput。
  访问模式:尽管在PV层看起来并无差别,但是存储设备支持及启用的功能特性却可能不尽相同。例如NFS存储支持多客户端同时挂载及读写操作,但是也可能是在共享时仅启用了只读模式,其他存储系统也存在类似的可配置特性。因此,PV底层的设备或许存在其特有的访问模式下,用户使用时必须在其特定范围内设定其功能,具体各PV的支持访问模式如下图:
Kubernetes学习之PV、PVC_第8张图片
  ReadWriteOnce:仅可被单个节点读写挂载;命令行中可简写为RWO。
  ReadOnlyMany:可被多个节点同时只读挂载;命令行中可简写为ROX。
  ReadWriteMany:可被多个节点同时读写挂载;命令行中可简写为RWX。
  persistentVolumeReclaimPolicy:PV空间被释放时的处理机制;可用类型仅为Retain(默认)、Recycle或Delete,具体说明如下:
    Retain:保持不动,由管理员随后手动回收。
    Recycle:空间回收,即删除存储卷目录下的所有文件(包括子目录和隐藏文件),目前只支持NFS和hostPath支持此操作。
    Delete:删除存储卷,仅部分支持云端存储系统支持,如AWS EBS、GCE PD、Azure Disk和Cinder。
  volumeMode:卷模型,用于指定此卷可被用作文件系统还是裸格式的块设备;默认为Filesystem。
  storageClassName:当前PV所属的StorageClass的名称;默认为空值,即不属于任何的StorageClass。
  mountOptions:挂载选项组成的列表,如ro、soft和hard等等。

1)创建PV

]# cat my-pv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata: 
  name: pv-nfs-001
  labels:
    release: stable
spec:
  capacity: 
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: slow
  nfs:
    path: "/data/"
    server: 172.16.2.250

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-002
  labels:
    release: stable
spec:
  capacity:
    storage: 10Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: slow
  nfs:
    path: "/data/"
    server: 172.16.2.250


]# kubectl apply -f my-pv.yaml  
persistentvolume/pv-nfs-001 created
persistentvolume/pv-nfs-002 created

2)查看PV资源对象

]# kubectl get pv -o wide 
NAME         CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE   VOLUMEMODE
pv-nfs-001   5Gi        RWX            Recycle          Available           slow                    73s   Filesystem
pv-nfs-002   10Gi       RWX            Recycle          Available           slow                    73s   Filesystem

]# kubectl describe pv pv-nfs-001 
Name:            pv-nfs-001
Labels:          release=stable
Annotations:     Finalizers:  [kubernetes.io/pv-protection]
StorageClass:    slow
Status:          Available
Claim:           
Reclaim Policy:  Recycle
Access Modes:    RWX
VolumeMode:      Filesystem
Capacity:        5Gi
Node Affinity:   <none>
Message:         
Source:
    Type:      NFS (an NFS mount that lasts the lifetime of a pod)
    Server:    172.16.2.25
    Path:      /data/
    ReadOnly:  false
Events:        <none>

.
  通过查看PV的详细信息可以看见,当前PV的状态为Available,即为"可用状态",表示目前尚未被PVC所关联绑定;创建完成的PV资源可能处于下列四种状态中的某一种,它们代表着PV资源生命周期中的各个阶段:
  Available:可用状态,尚未被PVC所绑定。
  Bound:已经被绑定至某个PVC。
  Released:绑定的PVC已经被删除了,但是资源尚未被集群回收。
  Failed:因自动回收资源失败而处于的故障状态。

四、创建PVC
  PersistentVolumeClaim是存储卷类型的资源,它通过申请占用某个PersistentVolume而创建,它与PV是一对一的关系,用户无须关心底层的实现细节。申请时,用户只需要指定目标空间的大小、访问模式、PV标签选择器和StorageClass等相关信息即可。PVC的Spec字段的可嵌套字段具体如下:
  accessMode:当前PVC的访问模式,其可用模式与PV相同。
  resource:当前PVC存储卷要占用的资源量最小值;目前,PVC的资源限定仅指的是其空间大小。
  selector:绑定时对PV应用的标签选择器(matchLabels)或者是匹配条件表达式(matchEx-pressions),用于挑选要绑定的PV;如果同时指定了两种挑选机制,则需要同时满足两种选择机制的PV才能被选择出来。
  storageClassName:所依赖的存储类名称。
  volumeMode:卷模型,用于指定此卷可被用作文件系统还是裸格式的块设备;默认为"Filesystem"。
  volumeName:用于直接指定要绑定的PV的卷名。

1)创建PVC

]# cat my-pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-nfs-001
  labels:
    release: "stable"
spec:
  accessModes:
    - ReadWriteMany
  volumeMode: Filesystem
  resources:
    requests:
      storage: 5Gi
  storageClassName: slow
  selector:
    matchLabels:
      release: "stable"

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-nfs-002
  labels:
    release: "stable"
spec:
  accessModes:
    - ReadWriteMany
  volumeMode: Filesystem
  resources:
    requests:
      storage: 10Gi
  storageClassName: slow
  selector:
    matchLabels:
      release: "stable"

]# kubectl apply -f my-pvc.yaml 
persistentvolumeclaim/pvc-nfs-001 created
persistentvolumeclaim/pvc-nfs-002 created

2)查看PVC资源对象详细信息

]# kubectl get pvc -o wide 
NAME          STATUS   VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS   AGE   VOLUMEMODE
pvc-nfs-001   Bound    pv-nfs-001   5Gi        RWX            slow           6s    Filesystem
pvc-nfs-002   Bound    pv-nfs-002   10Gi       RWX            slow           6s    Filesystem

]# kubectl get pv -o wide 
NAME         CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                 STORAGECLASS   REASON   AGE   VOLUMEMODE
pv-nfs-001   5Gi        RWX            Recycle          Bound    default/pvc-nfs-001   slow                    21m   Filesystem
pv-nfs-002   10Gi       RWX            Recycle          Bound    default/pvc-nfs-002   slow                    21m   Filesystem

# kubectl describe pvc pvc-nfs-001
Name:          pvc-nfs-001
Namespace:     default
StorageClass:  slow
Status:        Bound
Volume:        pv-nfs-001
Labels:        release=stable
Annotations:   pv.kubernetes.io/bind-completed: yes
               pv.kubernetes.io/bound-by-controller: yes
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:      5Gi
Access Modes:  RWX
VolumeMode:    Filesystem
Mounted By:    <none>
Events:        <none>

.
  可以看到当前PV、PVC的状态都已经处于"Bound"状态,说明PV与PVC已经建立了绑定关系。创建好PVC资源之后,即可在Pod资源中通过persistenVolumeClain存储卷引用它,而后挂载于容器中进行数据持久化。需要注意的是,PV是集群级别的资源,而PVC则隶属于名称空间,因此,PVC在绑定目标PV时不受名称空间的限制,但是Pod引用PVC时,则只能是属于同一名称空间中的资源。

五、在Pod中使用PVC
  在Pod资源中调用PVC资源,只需要在定义volumes时使用persistentVolumeClaims字段嵌套指定两个字段即可,具体如下:
  claimName:要调用的PVC存储卷的名称,PVC卷要与Pod在同一个名称空间下。
  readOnly:是否将存储卷强制挂载为只读模式,默认为false。

1)编写创建Pod的yaml文件

]# cat my-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: vol-nfs-pod01
  labels:
    app: myapp
    release: "stable"
spec:
  containers:
  - name: redis
    image: redis:4-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 6379
      name: redisport
    volumeMounts:
    - mountPath: /data-redis
      name: redis-nfs-vol
  volumes:
  - name: redis-nfs-vol
    persistentVolumeClaim: 
      claimName: pvc-nfs-001

---
apiVersion: v1
kind: Pod
metadata:
  name: vol-nfs-pod02
  labels:
    app: myapp
    release: "stable"
spec:
  containers:
  - name: redis
    image: redis:4-alpine
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 6379
      name: redisport
    volumeMounts:
    - mountPath: /data-redis
      name: redis-nfs-vol
  volumes:
  - name: redis-nfs-vol
    persistentVolumeClaim:
      claimName: pvc-nfs-002

]# kubectl apply  -f my-pod.yaml 
pod/vol-nfs-pod01 created
pod/vol-nfs-pod02 created

2)查看Pod资源的详细信息

]# kubectl get pods -o wide 
NAME            READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
vol-nfs-pod01   1/1     Running   0          82s   10.244.1.109   node1   <none>           <none>
vol-nfs-pod02   1/1     Running   0          82s   10.244.1.110   node1   <none>           <none>

]# kubectl describe pods vol-nfs-pod01
Name:         vol-nfs-pod01
Namespace:    default
Priority:     0
Node:         node1/172.16.2.101
Start Time:   Sun, 30 Aug 2020 17:34:17 +0800
Labels:       app=myapp
              release=stable
Annotations:  Status:  Running
IP:           10.244.1.109
IPs:
  IP:  10.244.1.109
Containers:
  redis:
    Container ID:   docker://7ed7da0a023622f21f31c254ebfb1b3321ad9f4414f9cd294609894921cbb602
    Image:          redis:4-alpine
    Image ID:       docker-pullable://redis@sha256:aaf7c123077a5e45ab2328b5ef7e201b5720616efac498d55e65a7afbb96ae20
    Port:           6379/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sun, 30 Aug 2020 17:34:19 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /data-redis from redis-nfs-vol (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-47pch (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  redis-nfs-vol:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  pvc-nfs-001
    ReadOnly:   false
  default-token-47pch:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-47pch
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age        From               Message
  ----    ------     ----       ----               -------
  Normal  Scheduled  <unknown>  default-scheduler  Successfully assigned default/vol-nfs-pod01 to node1
  Normal  Pulled     <invalid>  kubelet, node1     Container image "redis:4-alpine" already present on machine
  Normal  Created    <invalid>  kubelet, node1     Created container redis
  Normal  Started    <invalid>  kubelet, node1     Started container redis

3)查看Pod资源的存储空间

]# kubectl exec -it vol-nfs-pod01  --  df -h  | grep /data-redis
172.16.2.250:/data       50.0G     14.7G     35.3G  29% /data-redis

4)报错及解决办法:

如果在创建Pod时该Pod状态一直处于"CreateContainer",且查看详细信息报如下错误:

Mounting arguments: --description=Kubernetes transient mount for /var/lib/kubelet/pods/51bb0c63-053d-4fd6-aa61-e5f552cd0915/volumes/kubernetes.io~nfs/pv-nfs-001 --scope -- mount -t nfs -o hand,nfsvers=4.1 172.16.2.25:/data/ /var/lib/kubelet/pods/51bb0c63-053d-4fd6-aa61-e5f552cd0915/volumes/kubernetes.io~nfs/pv-nfs-001
Output: Running as unit run-112794.scope.
mount.nfs: an incorrect mount option was specified
  Warning  FailedMount  <invalid>  kubelet, node1  MountVolume.SetUp failed for volume "pv-nfs-001" : mount failed: exit status 32
Mounting command: systemd-run

请在Pod被调度的节点上安装NFS相关的软件包:

yum install nfs-utils -y

你可能感兴趣的:(Kubernetes学习)