Kubernetes 的 Pod 可以 mount 很多种 Volume,常见的 volume 有
- emptyDir
- hostPath
- configMap, secret
- persistentVolumeClaim
- nfs, gitRepo, cephfs, iscsi, cinder 等
其中,emptyDir 是最简单的一种,用于挂载一些临时文件,比如同一个 Pod 中两个 container 需要通过 unix socket 通信,那么把 socket 放在 emptyDir 中是最简单的方法。
甚至可以指定把这个抽象的目录放在内存,从而加快速度。
volumes:
- name: html
emptyDir:
medium: Memory
hostPath 是把数据直接存在 kubernetes 某个 worker node 上,这种方法一般不推荐使用,因为当 Pod 被调度到其他节点上后,数据就丢失了。
那么什么样的情况适合挂载 hostPath 呢?一些系统级的组件,需要挂载 node 上系统本身自带的一些文件时,比如需要读取 host 的 cert 目录,或者 etc 目录。常见的有 kube-system
空间下的 coreDNS 组件等。
当 Pod 中的程序需要把数据持久化到外部存储时,最推荐的用法是先在系统中定义 StorageClass,然后配合 persistentVolumeClaim (PVC)
和 persistentVolume (PV)
一起动态的分配空间。
persistentVolume
persistentVolume (PV) 是对底层物理存储系统的抽象,系统管理员定义 PV,用户通过 persistentVolumeClaim 来把这个 PV 绑定到 PVC,然后在 Pod 中 mount 这个 PVC 即可。
PV 是 kubernetes 系统级的,它不属于某个 namespace。
例如下面这个操作,就是从 NFS server 上映射了 40G 的空间到 kubernetes 的名叫 test-pv
的 PV。
apiVersion: v1
kind: PersistentVolume
metadata:
name: test-pv
labels:
name: test-pv
spec:
storageClassName: "nfs"
capacity:
storage: 40Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /nfs/test-pv
server: 192.168.31.68
关于回收策略,
- Retain, 允许手动回收资源,当删除PVC的时候,PV仍然存在。可以由管理员手动删除 PV 。
- Delete, 删除 PV 对象,并在物理存储上执行删除操作(根据不同的 provisioner 删除的操作也不同,有的所谓删除其实是重命名文件夹,比如 NFS provisioner)
persistentVolumeClaim
用户通过 PVC 把系统的 PV 中绑定。之后就可以在 Pod 中 mount 这个 PVC 了。
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: your-pvc
namespace: yourname
labels:
name: your-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 40Gi
storageClassName: nfs
selector:
matchLabels:
name: test-pv
如果我们把这个 PVC 删除,然后再 apply 这个一模一样的 YAML file 会发生什么呢? PVC 会重新 bind 这个 PV 吗? 不会。
$ kubectl delete pvc your-pvc
$ kubectl apply -f pvc.yaml
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
your-pvc Pending 13s
可以看到,再次创建的 pvc 一直处于 “Pending” 状态,而对应的 PV 显示的是 Released
, 而不是之前的 Available
。
kubernetes 这样设计的目的是为了防止其他人再次 mount 之前的 PV,从而导致数据的泄漏。
如果我想再次使用某个 PV 怎么办呢? 只能把这个 PV 删除,然后再创建一个一模一样的 PV。
StorageClass
通过上面 PV 和 PVC 的关系,不难发现,如果用户想用 PVC,那么系统中必须先让管理员创建好 PV,这显然是比较低效的方式,我们希望能让用户 apply PVC 的时候,kubernetes 能自动创建 PV。
StorageClass 就是自动完成 PV 的创建,并且绑定到用户的 PVC。
如果你使用的是云服务商提供的 kubernetes,比如 GKE,那么系统自带了 provisioner
,而如果是在 lab 里自建的 kubernetes 集群,那么需要安装一个 nfs-client-provisioner
假设已经安装完成了一个 provisioner
,接着就可以用它来创建 StorageClass。
如果是 lab 里的 kubernetes,并且使用 NFS 作为物理存储,需要这样创建 StorageClass
allowVolumeExpansion: true
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
annotations:
storageclass.kubernetes.io/is-default-class: "true"
labels:
app: nfs-client-provisioner
name: nfs
parameters:
archiveOnDelete: "true"
provisioner: cluster.local/nfs-client-provisioner
reclaimPolicy: Delete
volumeBindingMode: Immediate
StorageClass 同样是 kubernetes 系统资源,不属于某个 namespace。 其中 storageclass.kubernetes.io/is-default-class: "true"
把这个 StorageClass 指定为系统默认的 StorageClass。
有了 default 的 StorageClass 之后,用户使用 PVC 直接 request 需要的大小即可。
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1024Mi
可以看到,通过 StorageClass 自动创建的 PV 都是以 pvc-xxx
开头的,
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS
pvc-027c06e7-d7c0-11ea-90d4-0cc47a305488 10Gi RWO Delete Bound
pvc-06883888-c2d9-11ea-aebf-0cc47a305488 10Gi RWX Delete Bound
pvc-0a3ce16a-a764-11ea-aebf-0cc47a305488 50Gi RWO Delete Bound
pvc-0ba5d4bc-d74e-11ea-90d4-0cc47a305488 10Gi RWO Delete Bound
pvc-1b50b2d2-d745-11ea-90d4-0cc47a305488 10Gi RWO Delete Bound
pvc-1b648fdc-9931-11ea-aebf-0cc47a305488 10Gi RWO Retain Bound
pvc-2b53dfb5-c73b-11ea-aebf-0cc47a305488 10Gi RWX Delete Bound
pvc-2cb67748-c6bd-11ea-aebf-0cc47a305488 100Gi RWO Delete Bound
pvc-30bda38e-9488-11ea-aebf-0cc47a305488 10Gi RWX Retain Bound
我们看到有的 RECLAIM POLICY 是 Delete, 在第一节提到过关于 Delete 的操作,不通的 provisioner 也不同, nfs-client-provisioner
对于一个被删除的 PV 在 NFS server 上仍然保留,只是重命名成了 archived
开头的文件夹。
关于 PV,PVC,StorageClass 就先说到这里。