-
docker version:20.10.2
-
kubernetes version:1.20.1
本文概述Kubernetes存储的基本组成。
概述
Kubernetes支持诸多类型的卷。卷的核心是包含一些数据的一个目录。存储卷属于Pod,Pod的存储卷Pod内的容器能够共享使用。
临时卷的生命周期与Pod相同,持久卷则有自己独立的生命周期。
使用.spec.volumes
字段为Pod设置卷,在.spec.containers[*].volumeMounts
字段中声明卷在容器中的挂载位置。卷挂载在镜像内的指定路径上,卷不能挂载到其他卷之上,也不能与其他卷有硬链接。
volumeMounts
pod.spec.containers.volumeMounts
,将卷挂载到容器。
常用字段:
pod.spec.containers.volumeMounts.mountPath:挂载到容器内的路径
pod.spec.containers.volumeMounts.mountPropagation:卷的挂载传播特性
pod.spec.containers.volumeMounts.name:挂载的卷的名称
pod.spec.containers.volumeMounts.readOnly:挂载的卷是否只读,默认false
pod.spec.containers.volumeMounts.subPath:子路径挂载
pod.spec.containers.volumeMounts.subPathExpr:带有变量的子路径挂载
挂载卷的传播
挂在卷的传播能力允许将容器安装的卷共享到同一Pod中的其他容器,甚至共享到同一节点上的其他Pod。
卷的挂载传播特性由pod.spec.containers.volumeMounts.mountPropagation
字段控制。值如下:
- None:此卷挂载模式将不会感知到主机后续在此卷或其任何子目录上执行的挂载变化,同样,容器所创建的卷挂载在主机上也是不可见的。
默认模式
。该模式等同于Linux中private
挂载传播选项。 - HostToContainer:此卷挂载模式将会感知到主机后续针对此卷或其任何子目录的挂载操作。该模式等同于Linux中
rslave
挂载传播选项。 - Bidirectional:与
HostToContainer
表现相同,另外,容器创建的卷挂载将被传播回至主机和使用同一卷的所有Pod的所有容器。该模式等同于Linux中rehared
挂载传播选项。
Notes:Bidirectional
形式的挂载传播可能比较危险。 它可以破坏主机操作系统,因此它只被允许在特权容器中使用。
Docker mount share
挂载传播需要Docker配置正确的挂载共享。
编辑Docker systemd服务文件,设置MountFlags
:
MountFlags=shared
如果存在MountFlags=slave
就删除掉。然后重启Docker守护进程。
PersistentVolume
持久卷(PersistentVolume,PV)属于集群资源。持久卷是集群中的一块存储,可以事先定义或动态供应。PV持久卷和普通的卷一样,使用卷插件来实现,持久卷有自己独立的生命周期。
PersistentVolume API资源对象中记录了存储的实现细节,无论其背后是NFS、iSCSI还是特定的云平台存储系统。
PV是集群中的资源,PVC(PersistentVolumeClaim)是对这些资源的请求。
定义一个NFS类型的PV示例:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0003
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /tmp
server: 172.17.0.2
存储卷类型
emptyDir
emptyDir:临时存储空间,使用集群节点的存储空间映射到Pod中。Pod结束则存储空间生命周期结束。
emptyDir的一些用途:
- 缓存空间
- 为耗时较长的计算提供检查点,以便任务能够方便地从崩溃前状态恢复执行
- 在Web服务器容器服务数据时,保存内容管理器容器获取的文件
emptyDir.medium
的类型可以指定为"Memory
",在节点重启时会被清除,未指定大小时默认为主机系统内存的50%
。容器崩溃时并不会导致Pod从节点上移除,因此容器崩溃期间emptyDir卷中的数据是安全的。
常用字段:
pod.spec.volumes.emptyDir.medium:存储类型;空("")为使用磁盘,Memory为使用内存
pod.spec.volumes.emptyDir.medium:存储上限
示例:
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: {}
hostPath
hostPath:将主机节点文件系统上的文件或目录挂载到Pod中。
hostPath的一些用法:
- 运行一个需要访问Docker内部机制的容器;可使用hostPath挂载/var/lib/docker路径
- 在容器中运行cAdvisor时,以hostPath方式挂载/sys
- 允许Pod指定给定的hostPath在运行Pod之前是否应该存在,是否应该创建以及应该以什么方式存在
常用字段:
pod.spec.volumes.hostPath.path:节点的路径
pod.spec.volumes.hostPath.type:hostPath的类型;默认为空;
hostPath支持以下type
:
取值 | 行为 |
---|---|
空字符串(默认)用于向后兼容,这意味着在安装hostPath卷之前不会执行任何检查。 | |
DirectoryOrCreate | 如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为0755,具有与kubelet相同的组和属主信息。 |
Directory | 在给定路径上必须存在的目录。 |
FileOrCreate | 如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件,权限设置为0644,具有与kubelet相同的组和所有权。 |
File | 在给定路径上必须存在的文件。 |
Socket | 在给定路径上必须存在的UNIX套接字。 |
CharDevice | 在给定路径上必须存在的字符设备。 |
BlockDevice | 在给定路径上必须存在的块设备。 |
Notes:FileOrCreate 模式不会负责创建文件的父目录。 如果欲挂载的文件的父目录不存在,Pod启动会失败。 为了确保这种模式能够工作,可以尝试把文件和它对应的目录分开挂载。
注意:
- 在具有相同配置(例如基于同一PodTemplate创建)的多个Pod会由于节点上文件的不同而在不同节点上有不同的行为。
- 下层主机上创建的文件或目录只能由root用户写入。需要在特权容器中以root身份运行进程,或者修改主机上的文件权限以便容器能够写入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
local
local:某个被挂载的本地存储设备,如磁盘、分区或者目录。
local卷只能用作静态创建的持久卷,尚不支持动态配置。
与hostPath卷相比,local卷能够以持久和可移植的方式使用,而无需手动将Pod调度到节点。系统通过查看PersistentVolume的节点亲和性配置,能够了解卷的节点约束。
local卷仍然取决于底层节点的可用性,并不适合所有应用程序。如果节点出现问题,那么local卷也将变得不可被Pod访问,使用它的Pod将不能运行。
常用字段:
pv.spec.local.fsType:文件系统类型,如ext4、xfs、ntfs,可不指定
pv.spec.local.path:节点上的路径,必选
示例:
具有nodeAffinity的local持久卷
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-pv
spec:
capacity:
storage: 100Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /mnt/disks/ssd1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- example-node
使用local卷是,需要设置PersistentVolume对象的nodeAffinity字段,调度器通过该详细来将使用local卷的Pod调度到正确的节点上。
PersistentVolume对象的volumeMount
字段可被设置为Block
(而不是默认值Filesystem),以将local卷作为原始块设备暴露出来。
使用local卷时,建议设置一个StorageClass
并将其volumeBiddingMode
设置为WaitForFirstConsumer
。延迟卷绑定的操作可以确保作出绑定决策时,会评估Pod可能具有的其他节点约束,例如:节点资源需求、节点选择器、Pod亲和性和Pod反亲和性。
NFS
nfs:将NFS挂载到Pod中。Pod删除时,nfs卷内容被保存,数据可以在Pod间共享。
注意:使用NFS卷之前,必须要配置好NFS服务器并将其exports
常用字段:
pod.spec.volumes.nfs.path:nfs的exports路径
pod.spec.volumes.nfs.readOnly:是否只读;默认false
pod.spec.volumes.nfs.server:nfs服务器地址
示例:
创建一个NFS pv
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs
spec:
capacity:
storage: 1Mi
accessModes:
- ReadWriteMany
nfs:
server: nfs-server.default.svc.cluster.local
path: "/"
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字段。
gitRepo
gitRepo:该卷挂载一个空目录,并将一个Git代码仓库克隆到这个目录中供Pod使用。
注意:已弃用,如果需要在容器中提供git仓库,请将一个EmptyDir卷挂载到InitContainer中,使用git命令完成仓库的克隆操作, 然后将EmptyDir卷挂载到Pod的容器中。
downwardAPI
downwardAPI:用于使downward API数据对应用程序可用。这种卷类型挂载一个目录并在纯文本文件中写入所请求的数据。
容器以subPath
卷挂载方式使用downward API时,将不能接收到它的更新。
PVC
persistentVolumeClaim:将持久卷(PersistentVolume)挂载到Pod中。
其他
一些分布式存储:glusterfs、rbd、cephfs
一些云存储:EBS、AzureDisk、gcePersistentDisk
subPath
有时,在单个Pod中共享卷以供多方使用是很有用的。volumeMounts.subPath
属性用于指定所引用的卷内的子路径,而不是其根路径。
示例:
PHP应用的代码和相关数据映射到卷的html文件夹,MySQL数据库存储在卷的mysql文件夹中
apiVersion: v1
kind: Pod
metadata:
name: my-lamp-site
spec:
containers:
- name: mysql
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "rootpasswd"
volumeMounts:
- mountPath: /var/lib/mysql
name: site-data
subPath: mysql
- name: php
image: php:7.0-apache
volumeMounts:
- mountPath: /var/www/html
name: site-data
subPath: html
volumes:
- name: site-data
persistentVolumeClaim:
claimName: my-lamp-site-data
带有扩展变量的subPath
使用subPathExpr
字段可以基于Downward API环境变量来构造subPath目录名。subPath和subPathExpr属性是互斥的。
在这个示例中,Pod使用subPathExpr来hostPath卷/var/log/pods中创建目录pod1。hostPath卷采用来自downwardAPI的Pod名称生成目录名。宿主目录/var/log/pods/pod1被挂载到容器的/logs中。
apiVersion: v1
kind: Pod
metadata:
name: pod1
spec:
containers:
- name: container1
env:
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
image: busybox
command: [ "sh", "-c", "while [ true ]; do echo 'Hello'; sleep 10; done | tee -a /logs/hello.txt" ]
volumeMounts:
- name: workdir1
mountPath: /logs
subPathExpr: $(POD_NAME)
restartPolicy: Never
volumes:
- name: workdir1
hostPath:
path: /var/log/pods