概述
Kubernetes 里使用 PV(PersistentVolume)来表示存储资源,通过 PVC(PersistentVolumeClaim)来声明存储资源需求,将存储的使用者与提供者解耦。PV/PVC 的关系类似于 Node/Pod,只不过一个描述的是存储资源,另一个描述的是计算资源。有状态应用的 Pod 需要绑定 PV,在 Pod 销毁和重建之间要保证绑定到之前的 PV,另外很多时候 Pod 的启动顺序有要求。
核心概念
存储卷/Volume
Volume 是最基本的存储抽象,支持多种类型,比如:本地存储卷 local、临时空目录 emptyDir、云服务等。Volume 可以直接被 Pod 使用,也可以被 PV使用。
KubernetesVolume 是一个目录,和DockerVolume 相似。当 Volume 被mount 到 Pod, Pod 中的所有容器都可以访问这个 Volume。Volume 的生命周期和 Pod 绑定,如果 Pod 挂掉以后会由 kubelet 再次重启 Pod,存储在 Volume 中的数据依然还在。只有当 Pod 删除时,Volume 才会被清理,数据是否丢失取决于具体的卷类型,如果是 emptyDir 那么数据就会丢失,如果是 PV 的话数据就不会丢失。
一个 Pod 可以挂载多个存储卷,一个存储卷也可以被同时挂载到多个 Pod 里,这样 Pod 之间也可以共享文件。在部署配置文件里,通过属性 spec.volumes
和 spec.containers.volumeMounts
来分别指定存储卷以及它被挂载到容器里的路径。
临时存储/Temp
- 用于存储临时数据的简单空目录:
emptyDir
emptyDir 可以在如下几种场景中使用:
- 临时空间,比如基于磁盘的合并排序
- 遇到崩溃事件可以设置检查点作为临时存储恢复未执行完毕的长计算
- 保存临时文件
本地化的暂存/Local Ephermeral
- 用于将目录从工作节点的文件系统挂载到 Pod 中:
hostPath
- 通过检出 Git 仓库的内容来初始化的卷:
gitRepo
- 本地存储卷:
local
- 用于将 Kubernetes 部分资源和集群信息公开给 Pod 的特殊类型卷:
configMap
、secret
、downwardAPI
网络化的持久存储(Networked Persistent)
- 用于挂载云服务商提供的特定存储类型:
gcePersistentDisk
(谷歌高性能型存储磁盘卷)、awsElasticBlockStore
(AmazonWeb 服务弹性块存储卷)、azureDisk
(Microsoft Azure 磁盘卷) - 用于挂载其他类型的网络存储:
cephfs
、iscsi
、flocker
、glusterfs
、quobyte
、rbd
、vsphereVolume
、scaleIO
PersistentVolume(PV)
PersistentVolume 是 kubernetes 集群中的一个共享网络存储资源对象,是对底层共享网络存储的抽象,PV 由管理员创建和配置,它与共享存储的具体实现直接相关,通过插件式的机制完成与共享存储的对接,然后应用通过 PVC 来请求访问和使用。
PV 有独立于 Pod 的生命周期,是由 PV Controller 控制 PV/PVC 的生命周期。
PV 的使用方式有两种,分别为静态存储和动态存储:
- 静态存储:由集群管理员创建大量的 PV,在 PV 中定义实际存储的详细信息,然后提供给集群用户使用。
- 动态存储:当管理员创建的静态 PV 中没有一个与用户需要的 PVC 匹配时,集群会尝试动态地为 PVC 提供一个卷。动态存储需要使用到 StorageClass,管理员需要先创建并配置 StorageClass,然后 PVC 设置使用的 StorageClass 类型,系统会自动创建符合要求的 PV 与 PVC 绑定。
PersistentVolumeClaim(PVC)
PersistentVolumeClaim(PVC) 是用户对存储资源 PV 的申请(Claim),PVC通常有普通用户创建和维护,当需要pod分配资源时,通过创建PVC 指明需要申请的存储空间大小和访问模式比如只读等信息。根据 PVC 中指定的条件 kubernetes 会动态寻找系统中的 PV 资源并进行绑定。
如果从 Storage Admin 和用户的角度看 PV 和 PVC:
- Storage Admin 负责创建和维护 PV;
- 用户只需要使用 PVC 声明存储大小和进入模式即可。
PV 和 PVC 匹配可以通过 StorageClassName
、matchLabels
或是 matchExpressions
三种方式。
StorageClass
将存储资源定义为某种类别(Class),比如:快速存储、慢速存储、有数据冗余、无数据冗余等,用户根据 StorageClass 的描述直观获取各种存储资源的特性,然后根据应用对存储资源的需求去申请存储资源。
使用 StorageClass 的好处在于可以动态创建 PV,节省了时间(不需要手动创建 Volume 或声明 PV),还可以封装不同类型的存储以供 PVC 选用。
因此,推荐的做法是声明 Pod 使用 PVC,而 PVC 使用 StorageClass。
关系图
临时存储/emptyDir
-
本地化的暂存/Local Ephermeral
用于将目录从工作节点的文件系统挂载到 Pod 中:
hostPath
- 通过检出 Git 仓库的内容来初始化的卷:
gitRepo
- 本地存储卷:
local
- 用于将 Kubernetes 部分资源和集群信息公开给 Pod 的特殊类型卷:
configMap
、secret
、downwardAPI
网络化的持久存储/Networked Persistent
- 用于挂载云服务商提供的特定存储类型:
gcePersistentDisk
(谷歌高性能型存储磁盘卷)、awsElasticBlockStore
(AmazonWeb 服务弹性块存储卷)、azureDisk
(Microsoft Azure 磁盘卷) 用于挂载其他类型的网络存储:
cephfs
、iscsi
、flocker
、glusterfs
、quobyte
、rbd
、vsphereVolume
、scaleIO
自定义存储卷/Others
Kubernetes 是开放的,如果没有合适的,可以自己实现。
可以自己开发驱动程序(卷插件)在节点上挂载卷:
FlexVolume
(不过这是一个 alpha 特性,将来可能会改变)- 容器存储接口,在 kubernetes 和外部存储系统之间建立一套标准的存储管理接口提供存储服务:Container Storage Interface(CSI)
hello world
创建pv
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-volume
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 2Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /tmp/data
查看创建结果
$ kubectl apply -f pv-volume.yaml
persistentvolume/pv-volume created
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-volume 2Gi RWO Retain Available manual 8s
创建pvc
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pv-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
查看pv状态
$ kubectl apply -f pv-claim.yaml
persistentvolumeclaim/pv-claim created
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-volume 2Gi RWO Retain Bound default/pv-claim manual 11m
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pv-claim Bound pv-volume 2Gi RWO manual 67s
创建dep
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
volumes:
- name: pv-storage
persistentVolumeClaim:
claimName: pv-claim
containers:
- name: nginx
image: nginx:1.8
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
volumeMounts:
- mountPath: '/usr/share/nginx/html'
name: pv-storage
创建
$kubectl apply -f pv-deployment.yaml
deployment.apps/nginx-deployment created
$kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-6c877fbc9c-lc6kd 1/1 Running 0 93s