在 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 51ssecret对象也可以通过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 yamkDownload 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。