# Kubernetes 中的几种存储

> 参考：`https://kubernetes.io/docs/concepts/storage/volumes/`

一个运行中的容器，缺省情况下，对文件系统的写入，都是发生在其分层文件系统的可写层的，一旦容器运行结束，所有写入都会被丢弃。因此需要对持久化支持。

Kubernetes 中通过 Volume 的方式提供对存储的支持。下面对一些常见的存储概念进行一点简要的说明。

## EmptyDir

顾名思义，`EmptyDir`是一个空目录，他的生命周期和所属的 Pod 是完全一致的，可能读者会奇怪，那还要他做什么？`EmptyDir`的用处是，可以在同一 Pod 内的不同容器之间共享工作过程中产生的文件。

缺省情况下，EmptyDir 是使用主机磁盘进行存储的，也可以设置`emptyDir.medium` 字段的值为`Memory`，来提高运行速度，但是这种设置，对该卷的占用会消耗容器的内存份额。

~~~yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}
~~~

## HostPath

这种会把宿主机上的指定卷加载到容器之中，当然，如果 Pod 发生跨主机的重建，其内容就难保证了。

这种卷一般和`DaemonSet`搭配使用，用来操作主机文件，例如进行日志采集的 FLK 中的 FluentD 就采用这种方式，加载主机的容器日志目录，达到收集本主机所有日志的目的。

~~~yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /test-pd
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      # directory location on host
      path: /data
~~~

## NFS/GlusterFS/CephFS/AWS/GCE 等等

作为一个容器集群，支持网络存储自然是重中之重了，Kubernetes 支持为数众多的云提供商和网络存储方案。

各种支持的方式不尽相同，例如 GlusterFS 需要创建 Endpoint，Ceph/NFS 之流就没这么麻烦了。

各种个性配置可移步参考文档。

## ConfigMap 和 Secret

镜像使用的过程中，经常需要利用配置文件、启动脚本等方式来影响容器的运行方式，如果仅有少量配置，我们可以使用环境变量的方式来进行配置。然而对于一些较为复杂的配置，例如 Apache 之类，就很难用这种方式进行控制了。另外一些敏感信息暴露在 YAML 中也是不合适的。

ConfigMap 和 Secret 除了使用文件方式进行应用之外，还有其他的应用方式；这里仅就文件方式做一点说明。

例如下面的 ConfigMap，将一个存储在 ConfigMap 中的配置目录加载到卷中。

~~~yaml
apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: gcr.io/google_containers/busybox
      command: [ "/bin/sh", "-c", "ls /etc/config/" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        # Provide the name of the ConfigMap containing the files you want
        # to add to the container
        name: special-config
  restartPolicy: Never
~~~

注意，这里的 ConfigMap 会映射为一个目录，ConfigMap 的 Key 就是文件名，每个 Value 就是文件内容，比如下面命令用一个目录创建一个 ConfigMap：

    kubectl create configmap \
    game-config \
    --from-file=docs/user-guide/configmap/kubectl

---

创建一个 Secret：

    kubectl create secret generic \
    db-user-pass --from-file=./username.txt \
    --from-file=./password.txt

使用 Volume 加载 Secret：

~~~yaml
apiVersion: v1
kind: Pod
metadata:
  name: mypod
  namespace: myns
spec:
  containers:
    - name: mypod
      image: redis
      volumeMounts:
        - name: foo
          mountPath: /etc/foo
          readOnly: true
  volumes:
    - name: foo
      secret:
        secretName: mysecret
~~~

可以看到 Secret 和 ConfigMap 的创建和使用是很相似的。在 RBAC 中，Secret 和 ConfigMap 可以进行分别赋权，以此限定操作人员的可见、可控权限。

## PV & PVC

PersistentVolume 和 PersistentVolumeClaim 提供了对存储支持的抽象，也提供了基础设施和应用之间的分界，管理员创建一系列的 PV 提供存储，然后为应用提供 PVC，应用程序仅需要加载一个 PVC，就可以进行访问。

而 1.5 之后又提供了 PV 的动态供应。可以不经 PV 步骤直接创建 PVC。

> 参考：`http://blog.fleeto.us/translation/dynamic-provisioning-and-storage-classes-kubernetes-0`
