概念

PersistentVolume(PV)

是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样,PV 也是集群中的资源。PV 是 Volume 之类的卷插件,但具有独立于使用 PV 的 Pod 的生命周期。此 API 对象包含存储实现的细节,即 NFS、iSCSl 或特定于云供应商的存储系统

PersistentVolumeClaim(PVC)

是用户存储的请求。它与Pod相似。Pod 消耗节点资源,PVC 消耗 PV 资源。Pod 可以请求特定级别的资源(CPU和内存)。声明可以请求特定的大小和访问模式(例如,可以以读/写一次或只读多次模式挂载)

静态 pv

集群管理员创建一些PV。它们带有可供群集用户使用的实际存储的细节。它们存在于KubernetesAPl中,可用于消费。

动态 pv

当管理员创建的静态 PV 都不匹配用户 的 persistentVolumeClaim 时,集群可能会尝试动态地为PVC 创建卷。此配置基于 storageclasses :PVC 必须请求[存储类],并且管理员必须创建并配置该类才能进行动态创建。声明该类为 “” 可以有效地禁用其动态配置。
要启用基于存储级别的动态存储配置,集群管理员需要启用 API server 上的 DefaultstorageClass [准入控制器]。例如,通过确保 Defaultstorageclass 位于 API server 组件的 --admission-control 标志,使用逗号分隔的有序值列表中,可以完成此操作

绑定

master 中的控制环路监视新的PVC,寻找匹配的PV(如果可能),并将它们绑定在一起。如果为新的 PVC 动态调配 PV,则该环路将始终将该 PV 绑定到 PVC。否则,用户总会得到他们所请求的存储,但是容量可能超出要求的数量。一旦 PV 和 PVC 绑定后, PersistentVolumeclaim 绑定是排他性的,不管它们是如何绑定的,PVC 跟PV 绑定是一对一的映射

持久化卷声明的保护

PVC 保护的目的是确保由 pod 正在使用的 PVC 不会从系统中移除,因为如果被移除的话可能会导致数据丢失(注意:当 pod 状态为 Pending 并且 Pod 已经分配给节点或者 Pod 为 Running 状态时, PVC 处于活动状态),当启用PVC保护alpha功能时,如果用户删除了一个pod 正在使用的PVC,则该 PVC 不会被立即删除。PVC的删除将被推迟,直到 PVC 不再被任何 pod 使用

持久化卷类型

PersistentVolume 类型以插件形式实现。Kubernetes 目前支持以下插件类型:

  • GCEPersistentDisk AWSElasticBlockStore AzureFile AzureDisk FC(Fibre Channel)
  • FlexVolume Flocker NFS iSCSI RBD(Ceph Block Device) CephFS
  • Cinder(Openstack block storage) Glusterfs VsphereVolume Quobyte Volumes
  • HostPath VMware Photon Portworx Volumes Scalelo Volumes StorageOS

持久卷演示代码

  1. apiVersion: v1
  2. kind: PersistentVolume
  3. metadata:
  4. name: pv0003
  5. spec:
  6. capacity:
  7. storage: 5Gi # 声明卷大小
  8. volumeMode: Filesystem
  9. accessModes:
  10. - ReadWriteOnce # 只有一个人读写
  11. persistentVolumeReclaimPolicy: Recycle # 回收策略
  12. storageClassName: slow # 存储类的名称
  13. mountOptions:
  14. - hard
  15. - nfsvers=4.1
  16. nfs: # nfs服务
  17. path: /tmp
  18. server: 172.17.0.2

PV访问模式

PersistentVolume 可以以资源提供者支持的任何方式挂载到主机上。如下表所示,供应商具有不同的功能,每个PV的访问模式都将被设置为该卷支持的特定模式。例如,NFS 可以支持多个读/写客户端,但特定的 NFSPV 可能以只读方式导出到服务器上。每个 PV都有一套自己的用来描述特定功能的访问模式

  • ReadWriteOnce —— 该卷可以被单个节点以读/写模式挂载
  • ReadOnlyMany —— 该卷可以被多个节点以只读模式挂载
  • ReadWriteMany —— 该卷可以被多个节点以读/写模式挂载

在命令行中,访问模式缩写为:

  • RWO - ReadWriteOnce
  • ROX - ReadOnlyMany
  • RWX - ReadWriteMany

    一个卷一次只能使用一种访问模式挂载,即使它支持很多访问模式。例如,ccEpersistentpisk可以由单个节点作为Readwriteonce模式挂载,或由多个节点以ReadonlyMany 模式挂载,但不能同时挂载

后端插件

Volume插件 ReadWriteOnce ReadOnlyMany ReadWriteMany
AWSElasticBlockStoreAWSElasticBlockStore - -
AzureFile
AzureDisk - -
CephFS
Cinder - -
FC -
FlexVolume -
Flocker - -
GCEPersistentDisk -
Glusterfs
HostPath - -
iSCSl -
PhotonPersistenDisk - -
Quobyte
NFS
RBD -
VsphereVolume - -(当pod并列时有效)
PortworxVolume -
ScalelO -
StorageOS - -

回收策略

  • Retain(保留)—— 手动回收
  • Recycle(回收)—— 基本擦除( rm-rf/thevolume/*
  • Delete(删除)—— 关联的存储资产(例如AWSEBS、GCEPD、Azure Disk和Openstack Cinder卷)将被删除

当前,只有NFS和HostPath 支持Recycle回收策略。AWSEBS、GCEPD、Azure Disk和Cinder 卷支持删除策略(有些策略可能会在最新版更改导致不可用或废弃)

状态

卷可以处于以下的某种状态:

  • Available(可用)——— 块空闲资源还没有被任何声明绑定
  • Bound(已绑定)—— 卷已经被声明绑定
  • Released(已释放)—— 声明被删除,但是资源还未被集群重新声明
  • Failed(失败)—— 该卷的自动回收失败

命令行会显示绑定到PV的PVC的名称

持久化演示说明-NFS

I、安装NFS服务器

在另外一台机器上安装,在k8s中调用

  1. yum install -y nfs-common nfs-utils rpcbind
  2. mkdir /nfsdata
  3. chmod 666 /nfsdata
  4. chown nfsnobody /nfsdata
  5. cat /etc/exports
  6. /nfsdata *(rw,no_root_squash,no_all_squash,sync)
  7. systemctl start rpcbind
  8. systemctl start nfs
  9. # centos8 使用, 只安装 nfs-utils rpcbind
  10. systemctl start nfs-server
  11. 所有节点安装客户端
  12. yum install -y nfs-utils rpcbind

说明: /etc/exports是nfs默认的配置文件
说明:各项权限的说明:
rw:可读写
ro: 只读
no_root_squash:对root用户不压制,如果客户端以root用户写入,在服务端都映射为服务端的root用户
root_squash: nfs服务:默认情况使用的是相反参数root_squash,
如果客户端是用户root操作,会被压制成nobody用户
all_squash: 不管客户端的使用nfs的用户是谁,都会压制成nobody用户
insecure: 允许从客户端过来的非授权访问
sync: 数据同步写入到内存和硬盘
async: 数据先写入内存,不直接写入到硬盘
anonuid: 指定uid的值,此uid必须存在于/etc/passwd中
anongid: 指定gid的值

Ⅱ、部署PV

  1. apiVersion: v1
  2. kind: PersistentVolume
  3. metadata:
  4. name: nfspv1
  5. spec:
  6. capacity:
  7. storage: 1Gi
  8. accessModes:
  9. - ReadWriteOnce
  10. persistentVolumeReclaimPolicy: Recycle
  11. storageClassName: nfs
  12. nfs:
  13. path: /data/nfs
  14. server: 192.168.66.100

Ⅲ、创建服务并使用PVC

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: nginx
  5. labels:
  6. app: nginx
  7. spec:
  8. ports:
  9. - port: 80
  10. name: web
  11. clusterIP: None
  12. selector:
  13. app: nginx
  14. ---
  15. apiVersion: apps/v1
  16. kind: StatefulSet
  17. metadata:
  18. name: web
  19. spec:
  20. selector:
  21. matchLabels:
  22. app: nginx
  23. serviceName: "nginx" ## 与上面 clusterIP: None 的无头服务对应
  24. replicas: 3
  25. template:
  26. metadata:
  27. labels:
  28. app: nginx
  29. spec:
  30. containers:
  31. - name: nginx
  32. image: k8s.gcr.io/nginx-slim:0.8
  33. ports:
  34. - containerPort: 80
  35. name: web
  36. volumeMounts:
  37. - name: www
  38. mountPath: /usr/share/nginx/html
  39. volumeClaimTemplates: # 卷请求
  40. - metadata:
  41. name: www # 卷挂载名称
  42. spec:
  43. accessModes: ["ReadWriteOnce"] # 访问模式
  44. storageClassName: "nfs" #访问的类
  45. resources:
  46. requests:
  47. storage: 1Gi # 卷大小要求

关于StatefulSet

  • 匹配Pod name(网络标识)的模式为:$(statefulset名称) -$(序号),比如上面的示例:web-0,web-1,web-2
  • statefulSet 为每个Pod 副本创建了一个DNs域名,这个域名的格式为:$(podname).(headless server name),也就意味着服务间是通过 Pod 域名来通信而非 PodIP,因为当 Pod 所在 Node 发生故障时,Pod 会被飘移到其它 Node 上,Pod IP会发生变化,但是 Pod 域名不会有变化
  • StatefulSet 使用 Headless 服务来控制 Pod 的域名,这个域名的 FQD N为:$(ervice name).$(namespace).svc.cluster.local,其中,”cluster.local” 指的是集群的域名
  • 根据 volumeClaim Templates,为每个Pod 创建一个pvc,pvc 的命名规则匹配模式: (volumeClaimTemplates.name)-(pod_name),比如上面的 volumeMounts.name=www,Pod name=web-[0-2],因此创建出来的PVC是www-web-0、www-web-1、www-web-2
  • 删除Pod 不会删除其 pvc,手动删除 pvc 将自动释放 pv

Statefulset的启停顺序:

  • 有序部署:部署 Statefulset 时,如果有多个Pod副本,它们会被顺序地创建(从0到N-1)并且,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态。
  • 有序删除:当Pod被删除时,它们被终止的顺序是从N-1到0。
  • 有序扩展:当对Pod执行扩展操作时,与部署一样,它前面的Pod必须都处于Running和Ready状态。

StatefulSet使用场景:

  • 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现。
  • 稳定的网络标识符,即Pod 重新调度后其PodName 和HostName不变。
  • 有序部署,有序扩展,基于init containers来实现。
  • 有序收缩。

手动释放PV资源的时候需要先删除对应节点上数据
回收时,查看pv状态

  1. [root@k8s-master01 pv]# kubectl edit pv nfspv3
  2. # Please edit the object below. Lines beginning with a '#' will be ignored,
  3. # and an empty file will abort the edit. If an error occurs while saving this file will be
  4. # reopened with the relevant failures.
  5. #
  6. apiVersion: v1
  7. kind: PersistentVolume
  8. metadata:
  9. annotations:
  10. pv.kubernetes.io/bound-by-controller: "yes"
  11. creationTimestamp: "2020-07-29T23:19:09Z"
  12. finalizers:
  13. - kubernetes.io/pv-protection
  14. name: nfspv3
  15. resourceVersion: "439667"
  16. selfLink: /api/v1/persistentvolumes/nfspv3
  17. uid: 77abb565-6af7-4381-bf29-614bf14cec87
  18. spec:
  19. accessModes:
  20. - ReadWriteOnce
  21. capacity:
  22. storage: 5Gi
  23. claimRef:
  24. apiVersion: v1
  25. kind: PersistentVolumeClaim
  26. name: www-web-1
  27. namespace: default
  28. resourceVersion: "333053"
  29. uid: ccab922d-1d0f-434a-a2f5-52856bc15eaa
  30. nfs:
  31. path: /nfsdata2
  32. server: 192.168.66.100
  33. persistentVolumeReclaimPolicy: Retain
  34. storageClassName: nfs
  35. volumeMode: Filesystem
  36. status:
  37. phase: Released

删除 claimRef 字段:

  1. [root@k8s-master01 pv]# kubectl get pv
  2. NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
  3. nfspv1 10Gi RWO Retain Available nfs 20h
  4. nfspv2 5Gi ROX Retain Available nfs 20h
  5. nfspv3 5Gi RWO Retain Available nfs 12h
  6. nfspv4 5Gi RWO Retain Available nfs 12h

则该 pv 被手动回收

对应关系
image.png
每个PV对应一个存储卷
statefulset 会根据 PVC模板在每个pod创建时创建对应pvc
每个pvc对应一个pv