01 引言
声明:本文为《Kubernetes权威指南:从Docker到Kubernetes实践全接触(第5版)》的读书笔记
在上一篇博客《k8s教程(Volume篇)-PV详解》,我们了解了持久卷的工作原理,本文继续深入学习PVC。
02 PVC详解
PVC
作为用户对存储资源的需求申请,主要涉及存储空间请求、访问模式、 PV选择条件和存储类别等信息的设置。
2.1 参数配置
下例声明的PVC具有如下属性:申请8GiB存储空间,访问模式为ReadWriteOnce,PV选择条件为包含release=stable标签并且包含条件为environment In[dev]的标签,存储类别为“slow”(要求在系统中已存在名为slow的StorageClass):
apiVersion: v1 kind: PersistentVolumeclaim metadata: name: myclaim spec: accessModes: - ReadWriteOnce volumeMode: Filesystem resources: requests: storage: 8Gi storageClassName: slow selector: matchLabels: release: "stable" matchExpressions: - {key: environment, operator: In, values: [dev]}
对PVC的关键配置参数说明如下:
2.1.1 资源请求(Resources)
资源请求(Resources):描述对存储资源的请求,通过 resources.requests.storage字段设置需要的存储空间大小。
2.1.2 访问模式 (Access Modes)
访问模式 (Access Modes):PVC也可以设置访问模式,用于描述用户应用对存储资源的访问权限。其三种访问模式的设置与PV的设置相同。
2.1.3 存储卷模式(Volume Modes)
存储卷模式(Volume Modes):PVC也可以设置存储卷模式,用于描述希望使用的PV存储卷模式,包括文件系统(Filesystem)和块设备 (Block) 。
PVC设置的存储卷模式应该与PV存储卷模式相同,以实现绑定,如果不同,则可能出现不同的绑定结果。在各种组合模式下是否可以绑定的结果如下图所示:
PV的存储卷模式 | PVC的存储卷模式 | 是否可以绑定 |
未设定 | 未设定 | 可以绑定 |
未设定 | Block | 无法绑定 |
未设定 | FileSystem | 可以绑定 |
Block | 未设定 | 无法绑定 |
Block | Block | 可以绑定 |
Block | FileSystem | 无法绑定 |
FileSystem | FileSystem | 可以绑定 |
FileSystem | Block | 无法绑定 |
FileSystem | 未设定 | 可以绑定 |
2.1.4 PV选择条件 (Selector)
PV选择条件 (Selector):通过Label Selector
的设置,可使PVC
对于系统中己存在的各种PV
进行筛选。系统将根据标签选出合适的PV
与该PVC
进行绑定。
对选择条件可以使用matchLabels
和matchExpressions
进行设置,如果两个字段都已设置,则Selector
的逻辑将是两组条件同时满足才能完成匹配。
2.1.5 存储类别(Class)
存储类别(Class):PVC在定义时可以设定需要的后端存储的类别(通过storageClassName字段指定),以减少对后端存储特性的详细信息的依赖。只有设置了该Class
的PV
才能被系统选出,并与该PVC
进行绑定。
PVC
也可以不设置Class
需求,如果storageClassName
字段的值被设置为空 (storageClassName=""
),则表示该PVC
不要求特定的Class
,系统将只选择未设定Class
的PV
与之匹配和绑定。PVC
也可以完全不设置storageClassName
字段, 此时将根据系统是否启用了名为DefaultStorageClass
的admission controller
进行相应的操作。
启用DefaultStorageClass:要求集群管理员己定义默认的StorageClass。
- 如果在系统中不存在默认的StorageClass,则等效于不启用DefaultStorageClass的情况;
- 如果存在默认的StorageClass,则系统将自动为PVC创建一个PV (使用默认StorageClass的后端存储),并将它们进行绑定;
- 集群管理员设置默认 StorageClass 时,会在 StorageClass 的定义中加上一个 annotation“storageclass.kubernetes.io/is-default-class=true”;
- 如果管理员将多个StorageClass都定义为default,则由于不唯一,系统将无法创建PVC。
未启用DefaultStorageClass:等效于PVC设置storageClassName的值为空(storageClassName=“),即只能选择未设定Class的PV与之匹配和绑定。
- 当Selector和Class都进行了设置时,系统将选择两个条件同时满足的PV与之匹配。
另外,如果PVC设置了Selector,则系统无法使用动态供给模式为其分配PV。
03 Pod使用PVC
在PVC
创建成功之后,Pod
就可以以存储卷(Volume
)的方式使用PVC
的存储资源了。
PVC受限于命名空间,Pod在使用PVC时必须与PVC处于同一个命名空间。
Kubernetes为Pod挂载PVC的过程如下:系统在Pod所在的命名空间中找到其配置的PVC,然后找到PVC绑定的后端PV,将PV存储挂载到Pod所在Node的目录下,最后将Node的目录挂载到Pod的容器内。
3.1 举例
3.1.1 举例:默认模式 (Filesystem)
在Pod中使用PVC时,需要在YAML配置中设置PVC类型的Volume,然后在容器中通过volumeMounts.mountPath设置容器内的挂载目录,示例如下:
apiversion: v1 kind: Pod metadata: name: mypod spec: containers: - name: myfrontend image: nginx volumeMounts: - mountPath: "/var/www/html" name: mypd volumes: - name: mypd persistentVolumeClaim: claimName: myclaim
3.1.2 举例:存储卷模式为块设备(Block)
如果存储卷模式为块设备(Block),则PVC的配置与默认模式 (Filesystem)略有不同,下面对如何使用裸块设备 (Raw Block Device) 进行说明。
假设使用裸块设备的PV已创建,例如:
apiVersion: V1 kind: PersistentVolume metadata: name: block-pv spec: capacity: storage: 10Gi accessModes: - ReadwriteOnce volumeMode: Block persistentVolumeReclaimPolicy: Retain fc: targetWwNs: ["50060e801049cfa1"] lun: 0 readOnly: false
PVC的YAML配置示例如下:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: block-pvc spec: accessModes: - ReadWriteOnce volumeMode: Block resources: requests: storage: 10Gi
使用裸块设备PVC的Pod定义如下:
与文件系统模式PVC的用法不同,容器不使用volumeMounts设置挂载目录,而是通过volumeDevices字段设置块设备的路径devicePath
apiVersion: v1 kind: Pod metadata: name: pod-with-block-volume spec: containers: - name: fc-container image: fedora:26 conmand: ["/bin/sh", "-c"] args: ["tail -f /dev/nul1"] volumeDevices: - name: data devicePath: /dev/xvda volumes: - name: data persistentVolumeClaim: claimName: block-pvc
在某些应用场景中,同一个Volume可能会被多个Pod或者一个Pod中的多个容器共享,此时可能存在各应用程序需要使用不同子目录的需求。这可以通过Pod 的volumeMounts定义的subPath字段进行设置。通过对subPath的设置,在容器中将以subPath设置的目录而不是在Volume中提供的默认根目录作为根目录使用。
下面的两个容器共享同一个PVC(及后端PV),但是各自在Volume中可以访问的根目录由subPath进行区分,mysql容器使用Volume中的mysql子目录作为根目录,php容器使用Volume中的html子目录作为根目录:
apiVersion: v1 kind: Pod metadata: name: mysql spec: containers: - name: mysql image: mysql env: name: MY_SQL_ROOT_PASSWORD value: "rootpasswd" volumeMounts: - mountPath: /var/lib/mysql name: site-data subPath: mysql - name: php image: php:7.0-apache volumeMounts: - mountPath: /var/www/html name: site-data suoPath: html volumes: - name: site-data persistentVolumeClain: claimName: site-data-pvc
注意,subPath
中的路径名称不能以“/
”开头,需要用相对路径的形式。
在一些应用场景中,如果希望通过环境变量来设置
subPath
路径,例如使用Pod
名称作为子目录的名称,则可以通过subPathExpr
字段提供支持。subPathExpr
字段用于将Downward API
的环境变量设置为存储卷的子目录。需要注意的是,subPathExpr
字段和subPath
字段是互斥的,不能同时使用。
下面的例子通过Downward API
将Pod
名称设置为环境变量POD_NAME
,然后在挂载存储卷时设置subPathExpr=$ (POD_NAME)
子目录:
apiversion: v1 kind: Pod metadata: name: pod1 spec: containers: - name: container1 env: - name: POD_NAME valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.name image: busybox command: ["sh","-c", "while [true];do do echo 'Hello';sleep 10; done | tee -a /logs/hello .txt" ] volumeMounts: - name: workdir1 mountPath: /logs subPathExpr: $ (POD NAME) restartPolicy: Never volumes: - name: workdir1 hostPath: path: /var/log/pods
04 文末
本文主要讲解了PVC,以及Pod使用PVC,希望能帮助到大家,谢谢大家的阅读,本文完!