Overview

在 kubernetes 上部署服务,无论是「有状态」的,还是「无状态」的,可能大部分都有存储数据的需求。随之而来的就是对存储资源的需求。对于 k8s 来说,最底层的存储资源,我们可以直接利用 local storage,即机器的本地磁盘,也可以使用 ceph rbd 这种存储插件,单独的搭建一个存储的集群,使得运行在k8s 上的服务可以使用 network storage。

但是,在搭建好了一个 ceph 存储的集群之后,我们要如何使用它呢?

PV && PVC

在 k8s 中,定义了两个资源来管理和使用集群中的存储资源:

  • Persistent Volumes: 可以认为是 k8s 集群提供的存储资源的一种抽象,由 k8s 集群自动创建
  • PersistentVolumeClaim: 可以认为是 User(广义的 User,泛指一切想使用存储资源的事物) 对存储资源的一个请求声明

对于两者的「合作」模式,可以简单的做如下理解:

用户申请一个定量的存储资源,创建一个 PVC,集群内部的某些组件在收到 PVC 的创建消息之后,根据要求创建一个相应的 PV,并且会为这个 PV 分配实际的存储空间(在本地磁盘,或者是在 ceph rbd 这种网络存储上)。但是,如果不能满足 PVC 所申请的 volume 资源,那么 PV 不会被创建,而这个 PVC 也会一直保留在那里,直到它所申请的 Volume 容量被满足。

对于 PV 来说,集群对它的提供方式一般有两种:动态和静态。静态的 PV 一般都是由 k8s 集群内特定的组件预先分配好的,在用户需要使用的时候,可以直接将 PVC 和 PV 做一个「绑定」的操作即可。而动态的 PV 则需要一个叫做 StorageClass 的东西。

Storage Class

一个 storage class 的资源对象,可以认为是底层存储插件的一个抽象。若我们使用 rbd 作为底层的存储插件,那么就需要创建一个 ceph rbd 的 storage class 的资源对象,若我们使用 cinder, 那么就需要创建一个 openstack clinder 的 storage class 的资源对象。在有动态分配 PV 需求的情况下,它相当于底层存储插件和 PV 之间的一个桥梁。

对于一些第三方的存储插件来说,要创建对应的 Storage class 资源对象,可以在这个 repo 中搜索,并按照文件进行部署:external-storage/ceph/rbd at master · kubernetes-incubator/external-storage · GitHub

How to use?

一个 Pod 中的 container 通过 PVC 和 PV 使用存储资源的过程如下:

首先,我们要创建一个 PVC,也就是要申请一定额度的存储资源:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 8Gi
  storageClassName: slow
  selector:
    matchLabels:
      release: "stable"
    matchExpressions:
      - {key: environment, operator: In, values: [dev]}

其次,构造一个 pod 的编排文件, 并且在容器中通过挂在的方式使用之前通过 PVC 申请的存储资源:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
kind: Pod
apiVersion: v1
metadata:
  name: mypod
spec:
  containers:
    - name: myfrontend
      image: nginx
      volumeMounts:
      - mountPath: "/var/www/html"
        name: mypd
  volumes:
    - name: mypd
      persistentVolumeClaim:
        claimName: myclaim

这个编排文件像我们展示了如下几个关键的信息:

  1. 使用的 PVC 名称为 myclaim,ns 和 pod 被创建的 ns 相同
  2. 若申请存储资源顺利,那么最终存储资源将会挂载到名称为 myfrontend 的容器中的/var/www/html路径下

总结一下: spec.containers.volumeMounts.name<->volumes.name<->pvc.claimName<->pv<->storage resource