在 Kubernetes 中,有几种特殊的 Volume,它们存在的意义不是为了存放容器里的数据,也不是用来进行容器和宿主机之间的数据交换。这些特殊 Volume 的作用,是为容器提供预先定义好的数据。这些Volume的信息就仿佛是被k8s投射进入容器中的,这也正是Project Volume的含义。

k8s支持的Project Volume一共有四种:

  • Secret
  • ConfigMap
  • Downward API
  • ServiceAccountToken

Secret

Pod想要访问的加密数据,存放到Etcd中,然后通过在Pod的容器中挂载Volume的方式,访问到这些Secret里保存的信息。

最经典的例子,就是存放数据库的Crediential信息,例如

apiVersion: v1
kind: Pod
metadata:
  name: test-projected-volume 
spec:
  containers:
  - name: test-secret-volume
    image: busybox
    args:
    - sleep
    - "86400"
    volumeMounts:
    - name: mysql-cred
      mountPath: "/projected-volume"
      readOnly: true
  volumes:
  - name: mysql-cred
    projected:
      sources:
      - secret:
          name: user
      - secret:
          name: pass

这里声明的容器挂载的Volume并不是emptyDir或者hostPath类型,而是projected类型。其数据来源是名为user和pass的Secret对象,分别对应数据库的用户名和密码。正是以Secret对象的形式提交给k8s保存的,下面的命令很清晰:

$ cat ./username.txt
admin
$ cat ./password.txt
c1oudc0w!
 
$ kubectl create secret generic user --from-file=./username.txt
$ kubectl create secret generic pass --from-file=./password.txt

通过kubectl get secrets命令即可查看secret对象。

$ kubectl get secrets
NAME           TYPE                                DATA      AGE
user          Opaque                                1         51s
pass          Opaque                                1         51s

secret对象也可以通过YAML的方式来创建,secret对象的数据必须是经过base64转码的

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  user: YWRtaW4=
  pass: MWYyZDFlMmU2N2Rm

虽然经过转码,但并没有经过加密,在生产环境中,还需要开启k8s中的secret加密插件来增强安全性。

ConfigMap

与Secret类似,但是不同的是,ConfigMap存放的是不需要加密的应用配置。两种用法几乎完全一样。

从properties文件中创建ConfigMap对象。

kubectl create configmap [ui-config对象名] --from-file=xxx.properties

查看对象信息:

kubectl get configmaps [ui-config对象名] -o yamk

Download API

这个project volume的作用是让Pod里的容器能够直接获得这个Pod API对象本身的信息

声明如下Pod YAML:

 
apiVersion: v1
kind: Pod
metadata:
  name: test-downwardapi-volume
  labels:
    zone: us-est-coast
    cluster: test-cluster1
    rack: rack-22
spec:
  containers:
    - name: client-container
      image: k8s.gcr.io/busybox
      command: ["sh", "-c"]
      args:
      - while true; do
          if [[ -e /etc/podinfo/labels ]]; then
            echo -en '\n\n'; cat /etc/podinfo/labels; fi;
          sleep 5;
        done;
      volumeMounts:
        - name: podinfo
          mountPath: /etc/podinfo
          readOnly: false
  volumes:
    - name: podinfo
      projected:
        sources:
        - downwardAPI:
            items:
              - path: "labels"
                fieldRef:
                  fieldPath: metadata.labels

通过这样的声明方式,当前 Pod 的 Labels 字段的值,就会被 Kubernetes 自动挂载成为容器里的 /etc/podinfo/labels 文件

这个容器启动后,会不断打印/etc/podinfo/labels中的信息。

$ kubectl create -f dapi-volume.yaml
$ kubectl logs test-downwardapi-volume
cluster="test-cluster1"
rack="rack-22"
zone="us-est-coast"

目前download API支持的字段已经非常丰富了

1. 使用fieldRef可以声明使用:
spec.nodeName - 宿主机名字
status.hostIP - 宿主机IP
metadata.name - Pod的名字
metadata.namespace - Pod的Namespace
status.podIP - Pod的IP
spec.serviceAccountName - Pod的Service Account的名字
metadata.uid - Pod的UID
metadata.labels['<KEY>'] - 指定<KEY>的Label值
metadata.annotations['<KEY>'] - 指定<KEY>的Annotation值
metadata.labels - Pod的所有Label
metadata.annotations - Pod的所有Annotation
 
2. 使用resourceFieldRef可以声明使用:
容器的CPU limit
容器的CPU request
容器的memory limit
容器的memory request

需要注意的是,Download API能够获取的信息,一定是Pod里的容器启动之前就能够确定下来的信息。如果想要获取容器运行后才会获得信息,那么就要考虑使用sidecar容器。

ServiceAccountToken

这个Project volume诞生的想法为:能否在一个Pod容器内部访问k8s,这样就可以直接在容器内部操作k8s的API了。

要完成这个目的,就需要解决k8s的apiserver的授权问题。ServiceAccount就是k8s内置的服务账户,这些账户具有对apiserver的访问权限,并且这样的ServiceAccount信息保存在一个特殊的secret对象里,这个对象就是ServiceAccountToken对象。 任何运行在k8s集群上的应用,都必须使用保存在ServiceAccountToken里的授权信息,也就是Token,才可以合法访问apiserver。

实际上,k8s只有三种project volume,因为serviceAccountToken只是一种特殊的secret

k8s有一个默认账户,每一个运行在k8s中的Pod,都可以直接使用这个默认的ServiceAccount。因为使用kubectl describe pod xxx查看Pod的详细信息就可以发现,每个Pod都会自动挂载一个类型是secret的project volume挂载到容器的固定目录,这个目录就可以获取默认ServiceAccount的授权信息了。应用程序只要加载这个目录下的文件就可以操作k8s的api了。使用官方的client包还可以自动加载。允许设置默认不为Pod里的容器自动挂载这个volume。


tags: volume pod k8s 容器持久化存储