1, 存储卷概述
由于容器本身是非持久化的, 因此需要解决在容器中运行应用程序遇到的一些问题. 首先, 当容器崩溃时, kubelet 将重新启动容器, 但是写入容器的文件将会丢失, 容器将会以镜像的初始状态重新开始; 第二, 在通过一个 Pod 中一起运行的容器, 通常需要共享容器之间一些文件. Kubernetes 通过存储卷解决上述的两个问题.
在 Docker 有存储卷的概念卷, 但 Docker 中存储卷只是磁盘的或另一个容器中的目录, 并没有对其生命周期进行管理. Kubernetes 的存储卷有自己的生命周期, 它的生命周期与使用的它 Pod 生命周期一致. 因此, 相比于在 Pod 中运行的容器来说, 存储卷的存在时间会比的其中的任何容器都长, 并且在容器重新启动时会保留数据. 当然, 当 Pod 停止存在时, 存储卷也将不再存在. 在 Kubernetes 支持多种类型的卷, 而 Pod 可以同时使用各种类型和任意数量的存储卷. 在 Pod 中通过指定下面的字段来使用存储卷:
spec.volumes: 通过此字段提供指定的存储卷
spec.containers.volumeMounts: 通过此字段将存储卷挂接到容器中
2, 存储卷类型和示例
当前 Kubernetes 支持如下所列这些存储卷类型, 并以 hostPath,nfs 和 persistentVolumeClaim 类型的存储卷为例, 介绍如何定义存储卷, 以及如何在 Pod 中被使用.
- awsElasticBlockStore
- azureDisk
- azureFile
- cephfs
- configMap
- csi
- downwardAPI
- emptyDir
- fc (fibre channel)
- flocker
- gcePersistentDisk
- gitRepo
- glusterfs
- hostPath
- iscsi
- local
- nfs
- persistentVolumeClaim
- projected
- portworxVolume
- quobyte
- rbd
- scaleIO
- secret
- storageos
- vsphereVolume
- 2.1 hostPath
hostPath 类型的存储卷用于将宿主机的文件系统的文件或目录挂接到 Pod 中, 除了需要指定 path 字段之外, 在使用 hostPath 类型的存储卷时, 也可以设置 type,type 支持的枚举值由下表. 另外在使用 hostPath 时, 需要注意下面的事项:
具有相同配置的 Pod(例如: 从同一个 podTemplate 创建的), 可能会由于 Node 的文件不同, 而行为不同.
在宿主机上创建的文件或目录, 只有 root 用户具写入的权限. 您要么在容器中以 root 身份运行进程, 要么在主机上修改的文件或目录的权限, 以便具备写入内容到 hostPath 的存储卷中.
值 | 行为 |
---|---|
空字符串(默认)是用于向后兼容,这意味着在挂接主机路径存储卷之前不执行任何检查。 | |
DirectoryOrCreate | 如果 path 指定目录不存在,则会在宿主机上创建一个新的目录,并设置目录权限为 0755,此目录与 kubelet 拥有一样的组和拥有者。 |
Directory | path 指定的目标必需存在 |
FileOrCreate | 如果 path 指定的文件不存在,则会在宿主机上创建一个空的文件,设置权限为 0644,此文件与 kubelet 拥有一样的组和拥有者。 |
File | path 指定的文件必需存在 |
Socket | path 指定的 UNIX socket 必需存在 |
CharDevice | path 指定的字符设备必需存在 |
BlockDevice | 在 path 给定路径上必须存在块设备。 |
下面是使用 hostPath 作为存储卷的 YAML 文件, 此 YAML 文件定义了一个名称为 test-pd 的 Pod 资源. 它通过 hostPath 类型的存储卷, 将 Pod 宿主机上的 / data 挂接到容器中的 / teset-pd 目录.
- 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
- # this field is optional
- type: Directory
- 2.2 NFS
在 Kubernetes 中, 可以通过 nfs 类型的存储卷将现有的 NFS(网络文件系统) 到的挂接到 Pod 中. 在移除 Pod 时, NFS 存储卷中的内容被不会被删除, 只是将存储卷卸载而已. 这意味着在 NFS 存储卷总可以预先填充数据, 并且可以在 Pod 之间共享数据. NFS 可以被同时挂接到多个 Pod 中, 并能同时进行写入. 需要注意的是: 在使用 nfs 存储卷之前, 必须已正确部署和运行 NFS 服务器, 并已经设置了共享目录.
下面是一个 redis 部署的 YAML 配置文件, redis 在容器中的持久化数据保存在 / data 目录下; 存储卷使用 nfs,nfs 的服务地址为: 192.168.8.150, 存储路径为:/k8s-nfs/redis/data. 容器通过 volumeMounts.name 的值确定所使用的存储卷.
- apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
- kind: Deployment
- metadata:
- name: redis
- spec:
- selector:
- matchLabels:
- app: redis
- revisionHistoryLimit: 2
- template:
- metadata:
- labels:
- app: redis
- spec:
- containers:
- # 应用的镜像
- - image: redis
- name: redis
- imagePullPolicy: IfNotPresent
- # 应用的内部端口
- ports:
- - containerPort: 6379
- name: redis6379
- env:
- - name: ALLOW_EMPTY_PASSWORD
- value: "yes"
- - name: REDIS_PASSWORD
- value: "redis"
- # 持久化挂接位置, 在 docker 中
- volumeMounts:
- - name: redis-persistent-storage
- mountPath: /data
- volumes:
- # 宿主机上的目录
- - name: redis-persistent-storage
- nfs:
- path: /k8s-nfs/redis/data
- server: 192.168.8.150
- 2.3 persistentVolumeClaim
persistentVolumeClaim 类型存储卷将 PersistentVolume 挂接到 Pod 中作为存储卷. 使用此类型的存储卷, 用户并不知道存储卷的详细信息.
此处定义名为 busybox-deployment 的部署 YAML 配置文件, 使用的镜像为 busybox. 基于 busybox 镜像的容器需要对 / mnt 目录下的数据进行持久化, 在 YAML 文件指定使用名称为 nfs 的 PersistenVolumeClaim 对容器的数据进行持久化.
- # This mounts the nfs volume claim into /mnt and continuously
- # overwrites /mnt/index.html with the time and hostname of the pod.
- apiVersion: v1
- kind: Deployment
- metadata:
- name: busybox-deployment
- spec:
- replicas: 2
- selector:
- name: busybox-deployment
- template:
- metadata:
- labels:
- name: busybox-deployment
- spec:
- containers:
- - image: busybox
- command:
- - sh
- - -c
- - 'while true; do date> /mnt/index.html; hostname>> /mnt/index.html; sleep $(($RANDOM % 5 + 5)); done'
- imagePullPolicy: IfNotPresent
- name: busybox
- volumeMounts:
- # name must match the volume name below
- - name: nfs
- mountPath: "/mnt"
- volumes:
- - name: nfs
- persistentVolumeClaim:
- claimName: nfs-pvc
参考资料
1.Volumes地址: https://kubernetes.io/docs/concepts/storage/volumes/
2.nfs地址: https://github.com/kubernetes-incubator/external-storage/tree/master/nfs
作者简介:
季向远, 北京神舟航天软件技术有限公司产品经理. 本文版权归原作者所有.