Kubernetes 的 Pod 可以 mount 很多种 Volume,常见的 volume 有

  1. emptyDir
  2. hostPath
  3. configMap, secret
  4. persistentVolumeClaim
  5. 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 就先说到这里。