ConfigMap 和 Secret 中的 Volume

【k8s】 ConfigMap/Secret 管理应用配置(五) 提到了 Volume 存储卷的概念。它使用字段 volumes 和 volumeMounts 将配置信息挂载到 Pod 中供进程使用。

本篇笔记会讲述 Volume 的高级用法,看看 Kubernetes 管理存储资源的 API 对象 PersistentVolume、PersistentVolumeClaim、StorageClass,然后使用本地磁盘来创建实际可用的存储卷。

一、PersistentVolume

Pod 里的容器是由镜像产生的,而镜像文件本身是只读的,进程要读写磁盘只能用一个临时的存储空间,一旦 Pod 销毁,临时存储也就会立即回收释放,数据也就丢失了。为了保证即使 Pod 销毁后重建数据依然存在,Kubernetes 就顺着 Volume 的概念,延伸出了 PersistentVolume 对象,它专门用来表示持久存储设备,但隐藏了存储的底层实现,我们只需要知道它能安全可靠地保管数据就可以了(由于 PersistentVolume 这个词很长,一般都把它简称为 PV)。

作为存储的抽象,PV 实际上就是一些存储设备、文件系统,比如 Ceph、GlusterFS、NFS,甚至是本地磁盘,管理它们已经超出了 Kubernetes 的能力范围,所以,一般会由系统管理员单独维护,然后再在 Kubernetes 里创建对应的 PV

要注意的是,PV 属于集群的系统资源,是和 Node 平级的一种对象,Pod 对它没有管理权,只有使用权。

1.PersistentVolumeClaim 和 StorageClass

PV 无法直接挂载到 Pod 里面使用,因为不同的存储设备的差异巨大:速度快慢、共享/独占读写、容量大小…这么多种存储设备,只用一个 PV 对象来管理还是有点太勉强了,不符合“单一职责”的原则,让 Pod 直接去选择 PV 也很不灵活。

于是 Kubernetes 就又增加了两个新对象,PersistentVolumeClaimStorageClass,用的还是中间层的思想,把存储卷的分配管理过程再次细化。

PersistentVolumeClaim 简称 PVC。它是用来向 Kubernetes 申请存储资源的 API 对象,用来给 Pod 使用,相当于 Pod 的存储代理,代表 Pod 向系统申请 PV。一旦资源申请成功,Kubernetes 就会把 PV 和 PVC 关联在一起,这个动作叫做绑定(bind)

但是,系统里的存储资源非常多,如果要 PVC 去直接遍历查找合适的 PV 也很麻烦,所以就要用到 StorageClass

StorageClass 抽象了特定类型的存储系统(比如Ceph、NFS),在 PVC PV 之间充当协调人的角色,帮助 PVC 找到合适的 PV。也就是说它可以简化 Pod 挂载虚拟盘的过程,让 Pod 看不到 PV 的实现细节。

在这里插入图片描述

二、使用 YAML 描述 PersistentVolume

Kubernetes 里有很多种类型的 PV,最基础的是本机存储 HostPath。它和 Docker 中使用 docker run -v 使用的参数 -v 非常相似。

因为 Pod 会在集群的任意节点上运行,所以首先,我们要作为系统管理员在每个节点上创建一个目录,它将会作为本地存储卷挂载到 Pod 里:在 /tmp 目录下建立名字为 host-10mb-pv 的文件夹,表示一个容量为 10 MB 的存储设备。

目前只能用 kubectl api-resources kubectl explain 查看 PV 的字段说明,手动编写 PV 的 YAML 描述文件。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: host-10m-pv

spec:
  storageClassName: host-manual
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 10Mi
  hostPath:
    path: /tmp/host-10mib-pv/

storageClassName 是对存储类型的抽象 StorageClass 的名字。这个 PV 是手动管理的,名字可以任意起。
accessModes 定义了存储设备的访问模式。简单来说就是虚拟盘的读写权限,和 Linux 的文件访问模式差不多,目前 Kubernetes 里有 4 种:

  • ReadWriteOnce:存储卷可读可写,但只能被一个节点上的 Pod 挂载
  • ReadOnlyMany:存储卷只读不可写,可以被任意节点上的 Pod 多次挂载
  • ReadWriteMany:存储卷可读可写,也可以被任意节点上的 Pod 多次挂载
  • ReadWriteOncePod:卷可以被单个 Pod 以读写方式挂载。 如果你想确保整个集群中只有一个 Pod 可以读取或写入该 PVC, 请使用 ReadWriteOncePod 访问模式。这只支持 CSI 卷以及需要 Kubernetes 1.22 以上版本

前三种 3 种访问模式限制的对象是节点而不是 Pod,因为存储是系统级别的概念,不属于 Pod 里的进程。显然,本地目录只能是在本机使用,所以这个 PV 使用了 ReadWriteOnce。

在命令行接口(CLI)中,访问模式也使用以下缩写形式:

RWO - ReadWriteOnce
ROX - ReadOnlyMany
RWX - ReadWriteMany
RWOP - ReadWriteOncePod

capacity 表示存储设备的容量,这里我设置为 10MB。Kubernetes 里定义存储容量使用的是国际标准,要写成 Ki/Mi/Gi

hostPath 指定了存储卷的本地路径,也就是我们在节点上创建的目录。

用这些字段把 PV 的类型、访问模式、容量、存储位置都描述清楚,一个存储设备就创建好了。

三、使用 YAML 描述 PersistentVolumeClaim

有了 PV,就表示集群里有了这么一个持久化存储可以供 Pod 使用,我们需要再定义 PVC 对象,向 Kubernetes 申请存储。

下面这份 YAML 就是一个 PVC,要求使用一个 5MB 的存储设备,访问模式是 ReadWriteOnce

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: host-5mib-pvc

spec:
  storageClassName: host-manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Mi

PVC 的内容与 PV 很像,但它不表示实际的存储,而是一个申请或者声明spec 里的字段描述的是对存储的期望状态。所以 PVC 里的storageClassName accessModes 和 PV 是一样的,但不会有字段 capacity,而是要用 resources.requests.storage 表示希望要有多大的容量。

这样,Kubernetes 就会根据 PVC 里的描述,去找能够匹配 StorageClass 和符合容量的 PV,然后把 PV 和 PVC绑定在一起,实现存储的分配。

四、在 Kubernetes 中使用 PersistentVolume

创建 PV 对象,然后查看它的状态

$ kubectl apply -f host-path-pv.yaml 
persistentvolume/host-10m-pv created

$ kubectl get pv -o wide 
NAME          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE   VOLUMEMODE
host-10m-pv   10Mi       RWO            Retain           Available           host-manual             8s    Filesystem

可以看到,这个 PV 的容量是 10 MiB,访问模式是 RWO(ReadWriteOnce)StorageClass 是自定义的 host-manual,状态是可用(Available),可以随时分配给 Pod 使用。

创建PVC申请存储资源

$ kubectl apply -f host-path-pvc.yaml 
persistentvolumeclaim/host-5mib-pvc created
$ kubectl get pvc -o wide 
NAME            STATUS   VOLUME        CAPACITY   ACCESS MODES   STORAGECLASS   AGE   VOLUMEMODE
host-5mib-pvc   Bound    host-10m-pv   10Mi       RWO            host-manual    5s    Filesystem
$ kubectl get pv -o wide 
NAME          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                   STORAGECLASS   REASON   AGE   VOLUMEMODE
host-10m-pv   10Mi       RWO            Retain           Bound    default/host-5mib-pvc   host-manual             14m   Filesystem

一旦 PVC 对象创建成功,Kubernetes 就会立即通过 StorageClass resources 等条件在集群里查找符合要求的 PV,如果找到合适的存储对象就会把它俩绑定(bind)在一起,绑定后的状态就是 Bound。

PVC 对象申请的是 5MB,但现在系统里只有一个 10MB 的 PV,没有更合适的对象,所以 Kubernetes 也只能把这个 PV 分配出去。

如果把 PVC 的申请容量改大一些,超过现有可用 PV 的容量,PVC 就会一直处于 Pending 状态,这意味着 Kubernetes 没有在系统中找到合适的存储,无法分配资源,只有等满足要求的 PV 出现才能完成绑定。

五、为 Pod 挂载 PersistentVolume

有了持久化存储就可以为 Pod 挂载存储卷。先要在 spec.volumes 定义存储卷,然后在 containers.volumeMounts 挂载进容器。因为我们用的是 PVC,所以要在 volumes 里用字段 persistentVolumeClaim 指定 PVC 的名字。

下面就是 Pod 的 YAML 描述文件,把存储卷挂载到了 Nginx 容器的 /tmp 目录:

apiVersion: v1
kind: Pod
metadata:
  name: host-pvc-pod

spec:
  volumes:
  - name: host-pvc-vol
    persistentVolumeClaim:
      claimName: host-5mib-pvc

  containers:
    - name: ngx-pvc-pod
      image: nginx:alpine
      ports:
      - containerPort: 80
      volumeMounts:
      - name: host-pvc-vol
        mountPath: /tmp

现在启动这个 Pod:

$ kubectl apply -f ngx-pvc-pod.yaml 
pod/host-pvc-pod created

$ kubectl get pods -o wide 
NAME                        READY   STATUS    RESTARTS        AGE    IP           NODE      NOMINATED NODE   READINESS GATES
host-pvc-pod                1/1     Running   0               21s    10.10.1.70   k8s-worker01   <none>           <none>

我们在 Pod 中创建一个文件,然后取宿主机上看看文件是否被创建:

$ kubectl exec -it host-pvc-pod -- sh
/ # cd /tmp/
/tmp # echo yeah!  > file.text

登录宿主机:

[root@k8s-work01 ~]#  ls /tmp/host-10mib-pv/
file.text
[root@k8s-work01 ~]#  cat /tmp/host-10mib-pv/file.text 
yeah!

确实在 worker 节点的本地目录有一个 file.text 文件。因为 Pod 产生的数据已经通过 PV 存在了磁盘上,所以如果 Pod 删除后再重新创建,挂载存储卷时会依然使用这个目录,数据保持不变,也就实现了持久化存储。不过还有一点小问题,因为这个 PV 是 HostPath 类型,只在本节点存储,如果 Pod 重建时被调度到了其他节点上,那么即使加载了本地目录,也不会是之前的存储位置,持久化功能也就失效了。

HostPath 类型的 PV 一般用来做测试,或者是用于 DaemonSet 这样与节点关系比较密切的应用。下篇笔记就要学习网络共享存储了。

下图表示了Pod 和 PVC/PV 的关系画成了图(省略了字段 accessModes),你可以从图里看出它们是如何联系起来的:
在这里插入图片描述

资料
Kubernetes 持久卷官方文档
Introducing Single Pod Access Mode for PersistentVolumes

总结

  1. PersistentVolume 简称为 PV,是 Kubernetes 对存储设备的抽象,由系统管理员维护,需要描述清楚存储设备的类型、访问模式、容量等信息。
  2. PersistentVolumeClaim 简称为 PVC,代表 Pod 向系统申请存储资源,它声明对存储的要求,Kubernetes 会查找最合适的 PV 然后绑定。
  3. StorageClass 抽象特定类型的存储系统,归类分组 PV 对象,用来简化 PV/PVC 的绑定过程。
  4. HostPath 是最简单的一种 PV,数据存储在节点本地,速度快但不能跟随 Pod 迁移。
Logo

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

更多推荐