本文主题
- K8s Volume 使用场景
- PVC/PV/StorageClass 基本操作和概念解析
- PVC+PV 体系的设计与实现原理
一、Volumes 介绍
Pod Volumes
首先来看一下 Pod Volumes 的使用场景:
- 场景一:如果 pod 中的某一个容器在运行时异常退出,被 kubelet 重新拉起之后,如何保证之前容器产生的重要数据没有丢失?
- 场景二:如果同一个 pod 中的多个容器想要共享数据,应该如何去做?
以上两个场景,其实都可以借助 Volumes 来很好地解决,接下来首先看一下 Pod Volumes 的常见类型:
- 本地存储,常用的有 emptydir/hostpath;
- 网络存储:网络存储当前的实现方式有两种,一种是 in-tree,它的实现的代码是放在 K8s 代码仓库中的,随着k8s对存储类型支持的增多,这种方式会给k8s本身的维护和发展带来很大的负担;而第二种实现方式是 out-of-tree,它的实现其实是给 K8s 本身解耦的,通过抽象接口将不同存储的driver实现从k8s代码仓库中剥离,因此out-of-tree 是后面社区主推的一种实现网络存储插件的方式;
- Projected Volumes:它其实是将一些配置信息,如 secret/configmap 用卷的形式挂载在容器中,让容器中的程序可以通过POSIX接口来访问配置数据;
- PV 与 PVC 就是今天要重点介绍的内容。
k8s支持的卷类型
cephfs
cephfs
卷允许你将现存的 CephFS 卷挂载到 Pod 中。 不像 emptyDir
那样会在 Pod 被删除的同时也会被删除,cephfs
卷的内容在 Pod 被删除 时会被保留,只是卷被卸载了。这意味着 cephfs
卷可以被预先填充数据,且这些数据可以在 Pod 之间共享。同一 cephfs
卷可同时被多个写者挂载。
更多信息请参考 CephFS 示例 https://github.com/kubernetes/examples/tree/master/volumes/cephfs/
configMap
configMap
卷 提供了向 Pod 注入配置数据的方法。 ConfigMap 对象中存储的数据可以被 configMap
类型的卷引用,然后被 Pod 中运行的 容器化应用使用。
引用 configMap 对象时,你可以在 volume 中通过它的名称来引用。 你可以自定义 ConfigMap 中特定条目所要使用的路径。 下面的配置显示了如何将名为 log-config
的 ConfigMap 挂载到名为 configmap-pod
的 Pod 中:
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod
spec:
containers:
- name: test
image: busybox
volumeMounts:
- name: config-vol
mountPath: /etc/config
volumes:
- name: config-vol
configMap:
name: log-config
items:
- key: log_level
path: log_level
log-config
ConfigMap 以卷的形式挂载,并且存储在 log_level
条目中的所有内容 都被挂载到 Pod 的 /etc/config/log_level
路径下。 请注意,这个路径来源于卷的 mountPath
和 log_level
键对应的 path
。
- 在使用 ConfigMap 之前你首先要创建它。
- 容器以 subPath 卷挂载方式使用 ConfigMap 时,将无法接收 ConfigMap 的更新。
- 文本数据挂载成文件时采用 UTF-8 字符编码。如果使用其他字符编码形式,可使用
binaryData
字段。
emptyDir
当 Pod 分派到某个 Node 上时,emptyDir
卷会被创建,并且在 Pod 在该节点上运行期间,卷一直存在。 就像其名称表示的那样,卷最初是空的。 尽管 Pod 中的容器挂载 emptyDir
卷的路径可能相同也可能不同,这些容器都可以读写 emptyDir
卷中相同的文件。 当 Pod 因为某些原因被从节点上删除时,emptyDir
卷中的数据也会被永久删除。
emptyDir
卷中的数据是安全的。emptyDir
的一些用途:
- 缓存空间,例如基于磁盘的归并排序。
- 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。
- 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。
取决于你的环境,emptyDir
卷存储在该节点所使用的介质上;这里的介质可以是磁盘或 SSD 或网络存储。但是,你可以将 emptyDir.medium
字段设置为 "Memory"
,以告诉 Kubernetes 为你挂载 tmpfs(基于 RAM 的文件系统)。 虽然 tmpfs 速度非常快,但是要注意它与磁盘不同。 tmpfs 在节点重启时会被清除,并且你所写入的所有文件都会计入容器的内存消耗,受容器内存限制约束。
SizeMemoryBackedVolumes
特性门控时, 你可以为基于内存提供的卷指定大小。 如果未指定大小,则基于内存的卷的大小为 Linux 主机上内存的 50%。emptyDir 配置示例
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
glusterfs
glusterfs
卷能将 Glusterfs (一个开源的网络文件系统) 挂载到你的 Pod 中。不像 emptyDir
那样会在删除 Pod 的同时也会被删除,glusterfs
卷的内容在删除 Pod 时会被保存,卷只是被卸载。 这意味着 glusterfs
卷可以被预先填充数据,并且这些数据可以在 Pod 之间共享。 GlusterFS 可以被多个写者同时挂载。
更多详情请参考 GlusterFS 示例。
hostPath
HostPath 卷存在许多安全风险,最佳做法是尽可能避免使用 HostPath。 当必须使用 HostPath 卷时,它的范围应仅限于所需的文件或目录,并以只读方式挂载。
如果通过 AdmissionPolicy 限制 HostPath 对特定目录的访问, 则必须要求 volumeMounts
使用 readOnly
挂载以使策略生效。
hostPath
卷能将主机节点文件系统上的文件或目录挂载到你的 Pod 中。 虽然这不是大多数 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 |
在给定路径上必须存在的块设备。 |
当使用这种类型的卷时要小心,因为:
- HostPath 卷可能会暴露特权系统凭据(例如 Kubelet)或特权 API(例如容器运行时套接字), 可用于容器逃逸或攻击集群的其他部分。
- 具有相同配置(例如基于同一 PodTemplate 创建)的多个 Pod 会由于节点上文件的不同 而在不同节点上有不同的行为。
- 下层主机上创建的文件或目录只能由 root 用户写入。你需要在 特权容器 中以 root 身份运行进程,或者修改主机上的文件权限以便容器能够写入
hostPath
卷。
hostPath 配置示例:
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
# 宿主上目录位置
path: /data
# 此字段为可选
type: Directory
rbd
rbd
卷允许将 Rados 块设备 卷挂载到你的 Pod 中. 不像 emptyDir
那样会在删除 Pod 的同时也会被删除,rbd
卷的内容在删除 Pod 时 会被保存,卷只是被卸载。 这意味着 rbd
卷可以被预先填充数据,并且这些数据可以在 Pod 之间共享。
RBD 的一个特性是它可以同时被多个用户以只读方式挂载。 这意味着你可以用数据集预先填充卷,然后根据需要在尽可能多的 Pod 中并行地使用卷。 不幸的是,RBD 卷只能由单个使用者以读写模式安装。不允许同时写入。
更多详情请参考 RBD 示例。