一、PV、PVC API 资源对象需求背景

  • 我们之前提到过在Pod中定义数据卷Volume的时候,使用的是 ConfigMap 或者 Secret 资源对象在相应的目录下进行挂载。这2种资源对象在相应的位置上以文件的形式存在,而且能够容纳的数据量有限。本地磁盘、NFS之类的持久化存储资源在集群中也需要有对应的 API 资源对象,因此在Kubernetes中就有了PersistentVolume的概念(简称PV)。
  • 我们当前可以使用的持久化存储设备是五花八门的,如本地磁盘、NFS、Ceph等,它们的容量、读写速率等也差别很大。假设我们在Pod 中去直接定义使用这些持久化设备,一方面会造成较大的资源浪费,另一方面也会显得相当麻烦。因为我们在使用某一类持久化设备时,我们只关心这些存储设备的类型、我们需要的容量大小。于是Kubernetes新增了 PersistentVolumeClaim 资源对象(简称PVC),用于明确我们在使用存储设备时的清单明细。
  • 因为PV 和 PVC 之间又不是一一对应的关系,Kubernetes 中又提出了使用 StorageClass 资源对象,用于 PV 与 PVC 资源对象之间的解耦;

二、使用 Yaml 定义 PV、PVC API 资源对象

2.1 在 Yaml 中定义 PV

我们在yaml 中定义 PV,可以简单的理解为是在编写这个PV 的规格说明书。其实定义一个好一个存储卷很简单,明确这个存储卷的容量、挂载路径、访问权限即可,我们在定义PV时也是这样。一个 PV 资源对象在Yaml 中定义的示例如下:

apiVersion: v1		#  资源对象的版本
kind: PersistentVolume		#  资源对象的版本
metadata:
  name: test-pv		#  该资源对象的名称

spec:
  storageClassName: test-storageClass
  accessModes:
  - ReadOnlyMany
  capacity:
    storage: 200Mi
  hostPath:
    path: /tmp/test-pv/

关键字段含义:

storageClassName: 与该PV进行对接的StorageClass 的名称;
accessModes: 定义对该存储设备的访问权限。有3个取值:

  • ReadWriteOnce: 该存储资源可读可写,但是只能被Pod挂载一次,被挂载过之后将不再会参与分配;
  • ReadOnlyMany: 该存储资源只读不可写,可以被任意节点上的Pod挂载多次;
  • ReadWriteMany: 该存储资源可读可写,可以被任意节点上的Pod挂载多次;

capacity.storage: 所代表的存储设备的容量
hostPath.path: 该存储卷的挂载路径

2.2 在 Yaml 中定义 PVC

PVC 资源对象的Yaml内容其实就是我们在使用存储卷的时候的需求清单,示例如下:

apiVersion: v1		# 资源对象版本
kind: PersistentVolumeClaim		# 资源对象类型
metadata:
  name: test-pvc	# 资源对象名称

spec:
  storageClassName: test-storageClass
  accessModes:
    - ReadOnlyMany
  resources:
    requests:
      storage: 100Mi

storageClassName: 跟PV对接时使用的StorageClass的名称;
accessModes:规定对该存储卷的访问权限;
resources.requests: 服务需要的存储卷的大小;

三、PV、PVC API 资源对象的使用

Kubernetes内置算法模块,会根据 PVC 需求和匹配的 storageClass,来分配最为合适的PV,从而最大限度的利用好利群内的存储资源。

3.1 创建PV、PVC 资源对象

使用以下命令创建PV、PVC 资源对象,并查看创建效果:

kubectl apply -f pv.yaml
# 查看创建 PV 资源对象的状态
kubectl get pv
kubectl apply -f pvc.yaml
# 查看创建 PVC 资源对象的状态
kubectl get pvc

3.2 PVC 资源对象的使用

下面使用 Yaml 文件定义了一个Pod,演示了如何在定义Pod 的时候使用我们之前已经定义好的PVC:

apiVersion: v1
kind: Pod
metadata:
  name: testPvc-pod

spec:
  volumes:
  - name: test-vol
    persistentVolumeClaim:
      claimName: test-pvc

  containers:
    - name: test-program
      image: nginx:alpine
      ports:
      - containerPort: 80
      volumeMounts:
      - name: test-vol
        mountPath: /data/test

上面的情况是在Pod 的本地磁盘上创建PV,但是在 Deployment 等资源对象创建的 Pod 会在集群的各个节点上漂移,导致Pod 上对应的服务的数据丢失。所以,我们在使用存储服务的时候一般是例如 NFS 之类的来使用磁盘存储服务,无论Pod 漂移到集群上的哪个节点,都能访问到相应的磁盘服务。

3.3 使用 PV 解决Pod在集群上的漂移

3.3.1 使用 NFS 定义 PV

因为Pod在集群上的漂移问题,首先得解决方案就是通过 NFS 服务来解决。我们定义一个NFS类型的PV,其Yaml 文件内容如下:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: test-nfs-pv

spec:
  storageClassName: nfs
  accessModes:		## 设置该 PV 的权限
    - ReadWriteMany
  capacity:		## 设置该 PV 容量大小
    storage: 2Gi

  nfs:
    path: /tmp/nfs/1g-pv		#设置在NFS 服务器上存储分配地址
    server: 192.168.10.208		# NFS 服务器地址

要保证集群中有NFS 服务,且NFS 服务的server地址、path设置正确,集群中的每个节点都安装了 NFS 服务的客户端。
但是对于一个大型的系统来说,手动的分配设置存储、编写PV,效率还是过于低下。Kubernetes 提供了使用 provisioner.

3.3.2 使用 Provisioner 管理存储

使用 Provisioner 的方式管理存储、创建PV 的方式实现了自动化,告别了手动管理。我们只需要通过 storageClass 关联要使用的 provisioner,再在我们的 PVC 内关联上相应的 storageClass,通过 kubectl apply 命令创建对应的资源对象。然后我们在创建 PVC 时,provisioner 就会根据我们的 PVC 创建相应的 PV。
示例 storageClass 如下:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: test-nfs-client

# 指定要使用的 provisioner
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner 
parameters: # 提供 provisioner 在运行期间需要的参数
  archiveOnDelete: "false"

示例的 PVC 如下:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-nfs2-pvc

spec:
  storageClassName: test-nfs-client
  accessModes:
    - ReadWriteMany

  resources:
    requests:
      storage: 500Mi

然后,我们就不必再手动创建PV,只需要根据我们的资源需求写出 PVC ,在StorageClass 中指定 provisioner,provisioner 就会帮助我们创建对应的 PV。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐