kubernetes存储管理按照发展的历程,涉及到有Volume,PV(Persistent Volume)和PVC(PersistentVolumeClaims),和StorageClass,Volume是最早提出的存储卷,主要解决容器和数据存储的依赖关系,抽象底层驱动以支持不同的存储类型;使用Volume需要了解底层存储细节,因此提出了PV,Persistent Volume是由k8s管理员定义的存储单元,应用端使用PersistentVolumeClaims声明去调用PV存储,进一步抽象了底层存储;随着PV数量的增加,管理员需要不停的定义PV的数量,衍生了通过StorageClass动态生成PV,StorageClass通过PVC中声明存储的容量,会调用底层的提供商生成PV。本文介绍Volume的使用,下篇文章介绍PV,PVC和StorageClass。
- Volume 存储卷,独立于容器,后端和不同的存储驱动对接
- PV Persistent Volume持久化存储卷,和node类似,是一种集群资源,由管理员定义,对接不同的存储
- PVC PersistentVolumeClaims持久化存储声明,和pod类似,作为PV的使用者
- StorageClass 动态存储类型,分为静态和动态两种类型,通过在PVC中定义存储类型,自动创建所需PV
存储概述
kubernetes容器中的数据是临时的,即当重启重启或crash后容器的数据将会丢失,此外容器之间有共享存储的需求,所以kubernetes中提供了volume存储的抽象,volume后端能够支持多种不同的plugin驱动,通过.spec.volumes中定义一个存储,然后在容器中.spec.containers.volumeMounts调用,最终在容器内部以目录的形式呈现。
kubernetes内置能支持多种不同的驱动类型,大体上可以分为四种类型:
- 公/私有云驱动接口,如awsElasticBlockStore实现与aws EBS集成
- 开源存储驱动接口,如ceph rbd,实现与ceph rb块存储对接
- 本地临时存储,如hostPath
- kubernetes对象API驱动接口,实现其他对象调用,如configmap,每种存储支持不同的驱动
本地临时存储
本地临时存储包括hostPath、emptyDir等。
emptyDir临时存储
emptyDir是一种临时存储,pod创建的时候会在node节点上为容器申请一个临时的目录,跟随容器的生命周期,如容器删除,emptyDir定义的临时存储空间也会随之删除,容器发生意外crash则不受影响,同时如果容器发生了迁移,其上的数据也会丢失,emptyDir一般用于测试,或者缓存场景。注意:一个容器崩溃了不会导致数据的丢失,因为容器的崩溃并不移除pod.
emptyDir 的一些用途:
- 缓存空间,例如基于磁盘的归并排序。
- 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。
- 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。
1 | apiVersion: v1 |
进入pod,查看文件
1 | [root@master ~]# k apply -f 1.yaml |
那创建的文件是放在哪里呢?先使用 k get pods -o wide 查看pods所在的node,然后登陆这台node,查看:
1 | [root@node2 ~]# docker inspect k8s_test-container_test-pd_default_88417898-cfed-44a8-8522-715d29f7e009_0 |
可以看到是bind到机器上面的。当删除完这个pod时,这个文件也是会自动删除的。
hostPath主机存储
hostPath 卷能将node宿主机节点文件系统上的文件或目录挂载到您的 Pod 中。例如,hostPath 的一些用法有:
- 运行一个需要访问 Docker 引擎内部机制的容器;请使用
hostPath挂载/var/lib/docker路径。 - 在容器中运行 cAdvisor 时,以
hostPath方式挂载/sys。 - 允许 Pod 指定给定的
hostPath在运行 Pod 之前是否应该存在,是否应该创建以及应该以什么方式存在。
除了必需的 path 属性之外,用户可以选择性地为 hostPath 卷指定 type。支持的 type 值如下:
| 取值 | 行为 |
|---|---|
| 空字符串(默认)用于向后兼容,这意味着在安装 hostPath 卷之前不会执行任何检查。 | |
DirectoryOrCreate |
如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为 0755,具有与 Kubelet 相同的组和所有权。 |
Directory |
在给定路径上必须存在的目录。 |
FileOrCreate |
如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件,权限设置为 0644,具有与 Kubelet 相同的组和所有权。 |
File |
在给定路径上必须存在的文件。 |
Socket |
在给定路径上必须存在的 UNIX 套接字。 |
CharDevice |
在给定路径上必须存在的字符设备。 |
BlockDevice |
在给定路径上必须存在的块设备。 |
当使用这种类型的卷时要小心,因为:
- 具有相同配置(例如从 podTemplate 创建)的多个 Pod 会由于节点上文件的不同而在不同节点上有不同的行为。
- 当 Kubernetes 按照计划添加资源感知的调度时,这类调度机制将无法考虑由
hostPath使用的资源。 - 基础主机上创建的文件或目录只能由 root 用户写入。您需要在特权容器中以 root 身份运行进程,或者修改主机上的文件权限以便容器能够写入
hostPath卷。
1 | apiVersion: v1 |
就是共享本机的目录。
1 | [root@master volume]# kubectl create -f hostPath.yaml |
删除这个pod时,文件不会删除掉,还要保存到node上。
PV与PVC
PV 的全称是:PersistentVolume(持久化卷),是对底层的共享存储的一种抽象,PV 由管理员进行创建和配置,它和具体的底层的共享存储技术的实现方式有关,比如 Ceph、GlusterFS、NFS 等,都是通过插件机制完成与共享存储的对接。
PVC 的全称是:PersistentVolumeClaim(持久化卷声明),PVC 是用户存储的一种声明,PVC 和 Pod 比较类似,Pod 消耗的是节点,PVC 消耗的是 PV 资源,Pod 可以请求 CPU 和内存,而 PVC 可以请求特定的存储空间和访问模式。对于真正使用存储的用户不需要关心底层的存储实现细节,只需要直接使用 PVC 即可。

生命周期
PV是集群中的资源。PVC是对这些资源的请求,也是对资源的索赔检查。 PV和PVC之间的相互作用遵循这个生命周期:Provisioning ——-> Binding ——–>Using——>Releasing——>Recycling
Provisioning
这里有两种PV的提供方式:静态或者动态。
- Static:集群管理员创建多个PV。 它们携带可供集群用户使用的真实存储的详细信息。 它们存在于Kubernetes API中,可用于消费。
- Dynamic:当管理员创建的静态PV都不匹配用户的PersistentVolumeClaim时,集群可能会尝试为PVC动态配置卷。 此配置基于StorageClasses:PVC必须请求一个类,并且管理员必须已创建并配置该类才能进行动态配置。 要求该类的声明有效地为自己禁用动态配置
Binding绑定
在动态配置的情况下,用户创建或已经创建了具有特定数量的存储请求和特定访问模式的PersistentVolumeClaim。 主机中的控制回路监视新的PVC,找到匹配的PV(如果可能),并将它们绑定在一起。 如果为新的PVC动态配置PV,则循环将始终将该PV绑定到PVC。 否则,用户总是至少得到他们要求的内容,但是卷可能超出了要求。 一旦绑定,PersistentVolumeClaim绑定是排他的,不管用于绑定它们的模式。
如果匹配的卷不存在,PVC将保持无限期。 随着匹配卷变得可用,PVC将被绑定。 例如,提供许多50Gi PV的集群将不匹配要求100Gi的PVC。 当集群中添加100Gi PV时,可以绑定PVC。
PVC 保护的目的是确保由 pod 正在使用的 PVC 不会从系统中移除,因为如果被移除的话可能会导致数据丢失 当启用PVC 保护 alpha 功能时,如果用户删除了一个 pod 正在使用的 PVC,则该 PVC 不会被立即删除。PVC 的 删除将被推迟,直到 PVC 不再被任何 pod 使用。
PV访问模式
PersistentVolume可以以资源提供者支持的任何方式挂载到主机上。例如,NFS 可以支持多个读/写客户端,但特定的 NFS PV 可能 以只读方式导出到服务器上。每个 PV 都有一套自己的用来描述特定功能的访问模式。
- ReadWriteOnce——该卷可以被单个节点以读/写模式挂载
- ReadOnlyMany——该卷可以被多个节点以只读模式挂载
- ReadWriteMany——该卷可以被多个节点以读/写模式挂载
- 在命令行中,访问模式缩写为:
- RWO - ReadWriteOnce
- ROX - ReadOnlyMany
- RWX - ReadWriteMany
下表是一些常用的 Volume 插件支持的访问模式:
| Volume Plugin | ReadWriteOnce | ReadOnlyMany | ReadWriteMany |
|---|---|---|---|
| AWSElasticBlockStore | ✓ | - | - |
| AzureFile | ✓ | ✓ | ✓ |
| AzureDisk | ✓ | - | - |
| CephFS | ✓ | ✓ | ✓ |
| Cinder | ✓ | - | - |
| CSI | depends on the driver | depends on the driver | depends on the driver |
| FC | ✓ | ✓ | - |
| FlexVolume | ✓ | ✓ | depends on the driver |
| Flocker | ✓ | - | - |
| GCEPersistentDisk | ✓ | ✓ | - |
| Glusterfs | ✓ | ✓ | ✓ |
| HostPath | ✓ | - | - |
| iSCSI | ✓ | ✓ | - |
| Quobyte | ✓ | ✓ | ✓ |
| NFS | ✓ | ✓ | ✓ |
| RBD | ✓ | ✓ | - |
| VsphereVolume | ✓ | - | - (works when Pods are collocated) |
| PortworxVolume | ✓ | - | ✓ |
| ScaleIO | ✓ | ✓ | - |
| StorageOS | ✓ | - | - |
回收策略Reclaiming
- Retain(保留):手动回收
- Recycle(回收):基本擦除( rm -rf /thevolume/* )
- Delete(删除):关联的存储资产(例如 AWS EBS、GCE PD、Azure Disk 和 OpenStack Cinder 卷) 将被删除
- 当前,只有 NFS 和 HostPath 支持回收策略。AWS EBS、GCE PD、Azure Disk 和 Cinder 卷支持删除策略
状态
卷可以处于以下的某种状态:
- Available(可用):一块空闲资源还没有被任何声明绑定
- Bound(已绑定):卷已经被声明绑定
- Released(已释放):声明被删除,但是资源还未被集群重新声明
- Failed(失败):该卷的自动回收失败 命令行会显示绑定到 PV 的 PVC 的名称
hostPath实例演示
创建PV
1 | apiVersion: v1 |
创建好了显示如下:
1 | [root@master pv]# kubectl create -f pv-volume.yaml |
可以看到这个PV为10G,访问模式为RWO,卸载后保留,目前的STATUS为可用状态。
创建PVC
1 | apiVersion: v1 |
要求的资源要大于3G,类型为manual,这里一定要跟创建PV时对应上。
1 | [root@master pv]# kubectl create -f pv-claim.yaml |
主要看状态,变成Bound了。查看pvc的状态,也可以看到分配到了10G的资源。
创建POD
1 | apiVersion: v1 |
注意,创建的PV是在master上,目录是在/data下,但是POD被调度到node1上,这样来访问一下:
1 | [root@master ~]# kubectl get pods -o wide task-pv-pod |
创建成功之后,可以看到一个curl 与 cat出现的内容不一样。POD里面的的文件内容是node1上面的,而不是master节点上面的。所以hostPath只能调度到自己的机器上。
参考链接
https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/