pod本身具有生命周期,故其内部运行的容器及其相关数据自身均无法持久存在。docker支持配置容器使用存储卷将数据持久存储于容器自身文件系统之外的存储空间中,它们可以是节点文件系统或网络文件系统之上的存储空间。相应地,k8s也支持类似地存储卷功能,不过,其存储卷是与pod资源绑定而非容器。简单来说,存储卷是定义在pod资源之上、可被其内部的所有容器挂载的共享目录,它关联至某外部的存储设备之上的存储空间,从而独立于容器自身的文件系统,而数据是否具有持久能力则取决于存储卷自身是否支持持久机制。
1、支持的存储卷类型
k8s支持非常多的存储卷类型,包括本地存储和网络存储系统中的诸多存储机制以及secret和configMap资源。对于pod来说,卷类型主要是为关联相关的存储系统时提供相关的配置参数。emptyDir与hostPath属于节点级别的卷类型,emptyDir的生命周期与pod资源相同,而使用了hostPath卷的pod一旦被重新调度至其他节点,那么它将无法再使用此前的数据,因此,这两种类型都不具有持久性。要想使用持久类型的存储卷,就得使用网络存储系统,如nfs、ceph、glusterfs等,或者云端存储。k8s专门为网络存储系统设计了一种集群级别的资源PersisitentVolume,配置存储系统而后通过persistentVolumeClaim存储卷直接申请使用的机制大大简化了终端存储用户的配置过程,有效降低了使用难度。
1)、secret用于向pod中传递敏感信息,如密码、私钥、证书文件等,这些信息如果直接定义在镜像中很容易导致泄露。有了secret资源,用户可以将这些信息存储于集群中而后由pod进行挂载,从而实现将敏感数据与系统解耦。
2)、ConfigMap资源则用于向pod注入非敏感数据,使用时,用户将数据直接存储于configMap中,而后直接在pod中使用configmap卷引用即可,它可以帮助实现容器配置文件集中化定义和管理。
2、存储卷的使用方式
在pod中定义使用存储卷的配置由两部分组成:一是通过spec.volumes字段定义在pod之上的存储卷列表,其支持使用多种不同类型的存储卷切配置参数差别很大;另一个是通过spec.containers.volumeMounts字段在容器上定义的存储卷挂载列表,它只能挂载当前pod资源中定义的具体存储卷。在pod级别定义存储卷时,spec.volumes字段的值是对象列表格式,每个对象为一个存储卷的定义,它由存储卷名称或存储卷对象组成
3、临时存储卷
emptyDir存储卷的生命周期与其所属的pod对象相同,它无法脱离pod对象的生命周期提供数据存储功能,因此emptyDir通常仅用于数据缓存或临时存储。不过,基于emptyDir构建的gitRepo存储卷可以在pod对象的生命周期起始时从相应的git仓库中复制相应的数据文件到底层的emptyDir中,从而使得它具有了一定意义上的持久性。
1)、emptyDir存储卷是pod对象生命周期中的一个临时目录,在pod对象启动时即被创建,而在pod对象被移除时会被一并删除。不具有持久能力的emptyDir存储卷只能用于某些特殊场景中,例如,同一pod内的多个容器间文件的共享,或者作为容器数据的临时存储目录用于数据缓存系统等。
medium:此目录所在的存储介质的类型,可取值为default或Memory,默认default,表示使用节点的默认存储介质;Memory表示使用基于ram的临时文件系统tmpfs,空间受限于内存,但性能非常好,通常用于为容器中的应用提供缓存空间。
sizeLimit:当前存储卷的空间限额,默认值为nil,表示不限制;在medium字段值为Memory时,建议务必定义此限额。
apiVersion: v1
kind: Pod
metadata:
name: vol-emptydir-pod
spec:
volumes:
- name: html
emptyDir: {}
containers:
- name: nginx
image: nginx:1.12-alpine
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
- name: pagegen
image: alpine
volumeMounts:
- name: html
mountPath: /html
command: ["/bin/sh","-c"]
args:
- while true; do
echo $(hostname) $(date) >> /html/index.html;
sleep 10;
done
2)、gitRepo存储卷可以看作是emptyDir存储卷的一种实际应用,使用该存储卷的pod资源可以通过挂载目录访问指定的代码仓库中的数据。使用gitRepo存储卷得分pod资源在创建时,会首先创建一个空目录并克隆一份指定的git仓库中的数据至该目录,而后再创建容器并挂载该存储卷。定义gitRepo类型的存储卷时,可使用的字段如下:
repository:git仓库的url,必选字段
directory:目标目录名称,名称中不能包含“..”字符;“.”字符表示仓库中的数据直接复制到卷目录中,否则,即为复制到卷目录中以用户指定的字符串为名称的子目录中
revision:特定revision的提交哈希码
apiVersion: v1
kind: Pod
metadata:
name: vol-gitrepo-pod
spec:
containers:
- name: nginx
image: nginx:1.12-alpine
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
gitRepo:
repostory: https://github.com/ikubernetes/k8s_book.git
directory:
revision: "master"
gitRepo存储卷构建于emptyDir存储卷之上,它的生命周期与隶属的pod对象相同,因此使用时不建议再此类存储卷中保存由容器生成的重要数据。另外,自k8s1.12版起,gitRepo存储卷已经废弃,所以在之后的版本中若要使用它配置pod对象,建议借助初始化容器将仓库中的数据复制到emptyDir存储卷上,并在主容器中使用此存储卷。
4、节点存储卷hostPath
hostPath类型的存储卷是指将工作节点上某文件系统的目录或文件挂载于pod中的一种存储卷,它可独立于pod资源的生命周期,因为具有持久性,但是它是工作节点本地的存储空间,仅适用于特定情况下的存储卷使用需求,例如,将工作节点上的文件系统关联为pod的存储卷,从而使得容器访问节点文件系统上的数据。这一点在运行有管理任务的系统级pod资源需要访问节点上的文件时尤为有用。配置houPath存储卷的嵌套字段工两个:一个是用于指定工作节点上的目录路径的必选字段path;另一个是指定存储卷类型的type,它支持使用的卷类型包含如下几种:
DirectoryOrCreate:指定的路径不存在时自动将其创建为权限为0755的空目录,属主属组均为kubelet。
Directory:必须存在的目录路径
FileOrCreate:指定的路径不存在时自动创建为权限是0644的空文件,属主属组都是kubelet
File:必须存在的文件路径
Socket:必须存在的Socket文件路径
CharDevice:必须存在的字符设备文件路径
BlockDevice:必须存在的块设备文件路径
apiVersion: v1
kind: Pod
metadata:
name: vol-hostpath-pod
spec:
containers:
- name: filebeat
image: ikubenetes/filebeat:5.6.7-alpine
env:
- name: REDIS_HOST
value: redis.ilinux.io:6379
- name: LOG_LEVEL
value: info
volumeMounts:
- name: varlog
mountPath: /var/log
- name: socket
mountPath: /var/run/docker.sock
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: socket
hostPath:
path: /var/run/docker.sock
这类pod资源通常受控于daemonset类型的pod控制器,它运行于集群中的每个工作节点上,负责收集工作节点上系统级的相关数据,因此使用hostPath存储卷也是理所应当的。
5、网络存储卷
1)、NFS存储卷
k8s的nfs存储卷用于将某事先存在的nfs服务器上导出的存储空间挂载到pod中以供容器使用。于emptyDir不同的是,NFS存储卷在pod对象终止后仅是被卸载而非删除。另外,nfs是文件系统级共享服务,它支持同时存在的多路挂载请求。
server:nfs服务器的IP地址或主机名,必选字段
path:nfs服务器共享的文件系统路径,必选字段
readOnly:是否以只读方式挂载,默认为false
apiVersion: v1
kind: Pod
metadata:
name: vol-nfs-pod
labels:
app: redis
spec:
containers:
- name: redis
image: redis:4-alpine
ports:
- containerPort: 6379
name: redisport
volumeMounts:
- mountPath: /data
name: redisdata
volumes:
- name: redisdata
nfs:
server: nfs.ilinux.io
path: /data/redis
readOnly: false
6、RBD存储卷
在使用rbd存储卷时,需要事先满足以下几个条件:存在某可用的ceph rbd存储集群,否则就需要创建一个;在ceph rbd集群中创建一个能满足pod资源数据存储需要的存储映像;在k8s集群内的各节点上安装ceph客户端程序包(ceph-common)。
在配置rbd类型的存储卷时,需要指定要连接的目标服务器和认证信息等,这一点通常使用以下嵌套字段进行定义:
monitors:ceph存储监视器,逗号分隔的字符串列表;必选字段
image:rados image的名称,必选字段
pool:rados存储池的名称,默认为RBD
user:rados用户名,默认为admin
keyring:rbd用户认证时使用的保存有相应认证信息的secret对象,会覆盖由keyring字段提供的密钥信息
readOnly:是否以只读方式进行访问
fsType:要挂载的存储卷的文件系统类型,至少应该是节点操作系统支持的文件系统,如ext4、xfs、ntfs等,默认为ext4
apiVersion: v1
kind: Pod
metadata:
name: vol-rbd-pod
spec:
containers:
- name: redis
image: redis:4-alpine
ports:
- containerPort: 6379
name: redisport
volumeMounts:
- mountPath: /data
name: redis-rbs-vol
volumes:
- name: redis-rbd-vol
rbd:
monitors:
- '172.16.0.56:6789'
- '172.16.0.57:6789'
- '172.16.0.58:6789'
pool: kube
image: redis
fsType: ext4
readOnly: false
user: admin
secretRef:
name: ceph-secret