01 引言
声明:本文为《Kubernetes权威指南:从Docker到Kubernetes实践全接触(第5版)》的读书笔记
容器内部存储的生命周期是短暂的,会随着容器环境的销毁而销毁,具有不稳定性。如果多个容器希望共享同一份存储,则仅仅依赖容器本身是很难实现的。在Kubernetes
系统中,将对容器应用所需的存储资源抽象为存储卷 (Volume
)概念 来解决这些问题。
Volume
是与Pod
绑定的(独立于容器)与Pod
具有相同生命周期的资源对象,我们可以将Volume
的内容理解为目录或文件。
02 volume分类
Kubernetes
目前支持的Volume
类型包括Kubernetes
的内部资源对象类型、开源共享存储类型、存储厂商提供的硬件存储设备和公有云提供的存储等。
将Kubernetes特定类型的资源对象映射为目录或文件,包括以下类型的资源对象:
类型 | 描述 |
ConfigMap | 应用配置 |
Secret | 加密数据 |
DownwardAPI | Pod或Container的元数据信息 |
ServiceAccountToken | Service Account中的token数据 |
Projected Volume | 一种特殊的存储卷类型,用于将一个或多个上述资源对象一次性挂载到容器内的同一个目录下 |
Kubernetes管理的宿主机本地存储类型如下:
类型 | 描述 |
EmptyDir | 临时存储 |
HostPath | 宿主机目录 |
持久化存储(PV))和网络共享存储类型如下:
类型 | 描述 |
CephFS | 一种开源共享存储系统 |
Cinder | 一种开源共享存储系统 |
CSI | 容器存储接口(由存储提供商提供驱动程序和存储管理程序) |
FC(Fibre Channel) | 光纤存储设备 |
FlexVolume | 一种基于插件式驱动的存储 |
Flocker | 一种开源共享存储系统 |
Glusterfs | 一种开源共享存储系统 |
iSCSI | iSCSI存储设备 |
Local | 本地持久化存储 |
NFS | 网络文件系统 |
PersistentVolumeClaim | 简称PVC,持久化存储的申请空间 |
Portworx Volumes | Portworx提供的存储服务 |
Quobyte Volumes | Quobyte提供的存储服务 |
RBD(Ceph Block Device) | Ceph块存储 |
存储厂商提供的存储卷类型如下:
类型 | 描述 |
ScalelO Volumes | DellEMC的存储设备 |
StorageOS | StorageOS提供的存储服务 |
VsphereVolume | VMWare提供的存储系统 |
公有云提供的存储卷类型如下:
类型 | 描述 |
AWSElasticBlockStore | AWS公有云提供的Elastic Block Store |
AzureDisk | Azure公有云提供的Disk |
AzureFile | Azure公有云提供的File |
GCEPersistentDisk | GCE公有云提供的Persistent Disk |
03 将资源对象映射为存储卷
在Kubernetes
中有一些资源对象可以以存储卷的形式挂载为容器内的目录或文件,目前包括ConfigMap、Secret、Downward API、ServiceAccountToken、Projected Volume。
3.1 ConfigMap
ConfigMap主要保存应用程序所需的配置文件,并且通过Volume
形式挂载到容器内的文件系统中,供容器内的应用程序读取。
之前在pod篇有写过,可以参考:《k8s教程(pod篇)-配置管理》
3.2 Secret
假设在Kubernetes中已经存在如下Secret资源:
apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: password: dmFsdWUtMgOK username: dmFsdWUtMOOK
与ConfigMap
的用法类似,在Pod
的YAML
配置中可以将Secret设置为一个
Volume
,然后在容器内通过volumeMounts
将Secret
类型的Volume
挂载到/etc/foo
目录下:
apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mycontainer image: redis volumeMounts: - name: foo mountPath: "/etc/foo" volumes: - name: foo secret: secretName: mysecret
3.3 Downward API
通过Downward API
可以将Pod
或Container
的某些元数据信息(例如Pod
名称、Pod IP
、Node IP
、Label
、Annotation
、容器资源限制等)以文件的形式挂载到容器内,供容器内的应用使用。
之前在pod篇有写过,可以参考:《k8s教程(pod篇)-容器获取pod信息(Downward API)》
3.4 Projected Volume
Projected Volume
是一种特殊的存储卷类型,用于将一个或多个上述资源对象(ConfigMap、Secret、Downward API)一次性挂载到容器内的同一个目录。
下面是一个使用Projected Volume挂载ConfigMap
、Secret
、Downward API
共3种资源的示例:
apiVersion: v1 kind: Pod metadata: name: volume-test spec: containers: - name: container-test image: busybox volumeMounts: - name: all-in-one mountPath: "/projected-volume" readonly: true volumes: - name: all-in-one projected: sources: - secret: name: mysecret items: - key: username path: my-group/my-username - downwardAPI: items: - path: "labels" fieldRef: fieldPath: metadata.labels - path: "cpu_limit" resourceFieldRef: containerName: container-test resource: limits.cpu - configMap: name: myconfigmap items: - key: config path: my-group/my-config
此外,Kubernetes从1.l1版本开始引入对ServiceAccountToken
的挂载支持, 在1.l2版本时达到Beta阶段。ServiceAccountToken
通常用于容器内应用访问API Server
鉴权的场景中,例子如下:
apiVersion: v1 kind: Pod metadata: name: sa-token-test spec: containers: - name: container-test image: busybox volumeMounts: - name: token-vol mountPath: "/service-account" readOnly: true volumes: - name: token-vol projected: sources: - serviceAccountToken: audience: api # 预期受众的名称,Token的接收者必须使用其中的audience标识符来标识自己,否则拒绝该token expirationSeconds: 3600 # Service Account Token国企时间,默认1h path: token # 挂载目录下的相对路径
04 Node本地存储卷
Kubernetes管理的Node本地存储卷(Volume)的类型如下:
类型 | 描述 |
EmptyDir | 与Pod同生命周期的Nodell临时存储 |
HostPath | Node目录 |
Local | 基于持久卷(PV))管理的Node目录 |
4.1 EmptyDir
这种类型的Volume将在Pod
被调度到Node
时进行创建,在初始状态下目录中是空的,所以命名为“空目录”(Empty Directory)。它与Pod
具有相同的生命周期,当Pod
被销毁时,Node
上相应的目录也会被删除。同一个Pod
中的多个容器都可以挂载这种Volume
。
由于EmptyDir类型的存储卷的临时性特点,它通常可以用于以下应用场景中:
- 基于磁盘进行合并排序操作时需要的暂存空间;
- 长时间计算任务的中间检查点文件;
- 为某个Web服务提供的临时网站内容文件。
在默认情况下,kubelet
会在Node
的工作目录下为Pod
创建EmptyDir
目录,这
个目录的存储介质可能是本地磁盘、SSD
磁盘或者网络存储设备,取决于环境的
配置。
另外,
EmptyDir
可以通过medium
字段设置存储介质为“Memory
”,表示使用基于内存的文件系统(tmpfs
、RAM-backed filesystem
)。虽然tmpfs
的读写速度非常快,但与磁盘中的目录不同,在主机重启之后,tmpfs
的内容就会被清空。此外,写入tmpfs
的数据将被统计为容器的内存使用量,受到容器级别内存资源上限 (Memory Resource Limit
)的限制。
下面是使用EmptyDir类型的存储卷的Pod的YAML配置示例,该类型的存储卷的参数只有一对花括号“{}”:
apiVersion: v1 kind: Pod metadata: name: test-pod spec: containers: - image: busybox name: test-container volumeMounts: - mountPath: /cache name: cache-volume volumes: - name: cache-volume emptyDir: {}
4.2 HostPath
HostPath
类型的存储卷用于将Node文件系统的目录或文件挂载到容器内部使用。
对于大多数容器应用来说,都不需要使用宿主机的文件系统,适合使用HostPath
存储卷的一些应用场景如下:
- 容器应用的关键数据需要被持久化到宿主机上;
- 需要使用
Docker
中的某些内部数据,可以将主机的/var/ib/docker
目录挂载到容器内;- 监控系统,例如
cAdvisor
需要采集宿主机/sys
目录下的内容;Pod
的启动依赖于宿主机上的某个目录或文件就绪的场景。
HostPath存储卷的主要配置参数为path
,设置为宿主机的目录或文件路径; 还可以设置一个可选的参数type,表示宿主机路径的类型,目前支持的type配置参数和校验规则如下所示:
type配置参数 | 校验规则 |
空 | 系统默认值,为向后兼容的设置,意为系统在挂载path时不做任何校验 |
DirectoryOrCreate | path指定的路径必须是目录,如果不存在,则系统将自动创建该目录,将权限设置为0755,与kubelet具有相同的owner和group |
Directory | path指定的目录必须存在,否则挂载失败 |
FileOrCreate | path指定的路径必须是文件,如果不存在,则系统将自动创建该文件,将权限设置为0644,与kubelet具有相同的owner和group |
File | path指定的文件必须存在,否则挂载失败 |
Socket | path指定的UNIX socket必须存在,否则挂载失败 |
CharDevice | path指定的字符设备(character device)必须存在,否则挂载失败 |
BlockDevice | path指定的块设备(block device)必须存在,否则挂载失败 |
下面是使用HostPath
类型的存储卷的Pod
的YAML
配置示例,其中将宿主机的/data
目录挂载为容器内的/host-data
目录:
apiVersion: v1 kind: Pod metadata: name: test-pod spec: containers: - image: busybox name: test-container volumeMounts: - mountPath: /host-data name: test-volume volumes: - name: test-volume hostPath: path: /data #宿主机目录 type: Directory #可选,"Directory"表示该目录必须存在
由于HostPath
使用的是宿主机的文件系统,所以在使用时有以下注意事项:
- 对于具有相同
HostPath
设置的多个Pod
(例如通过podTemplate
创建的)来说,可能会被Master
调度到多个Node
上运行,但如果多个Node
上HostPath
中的文件内容(例如是配置文件)不同,则各Pod
应用的运行可能出现不同的结果;- 如果管理员设置了基于存储资源情况的调度策略,则HostPath目录下的磁盘空间将无法计入
Node
的可用资源范围内,可能出现与预期不同的调度结果;- 如果是之前不存在的路径,则由kubelet自动创建出来的目录或文件的
owner
将是root
,这意味着如果容器内的运行用户(User
)不是root
,则将无法对该目录进行写操作,除非将容器设置为特权模式(Privileged
),或者由管理员修改HostPath
的权限以使得非root
用户可写。HostPath
设置的宿主机目录或文件不会随着Pod
的销毁而删除,在Pod
不再存在之后,需要由管理员手工删除。
05 文末
由于篇幅有限,关于持久卷的内容,后续再出相关的文章,谢谢大家的阅读,希望能帮助到大家,本文完!