2.6 配置管理 #
服务中的配置信息,从数据安全的角度来看可以分成两类:一类是明文配置,可以任意查询修改,比如服务端口、运行参数、文件路径等等。另一类则是机密配置,由于涉及敏感信息需要保密,不能随便查看,比如密码、密钥、证书等等。这两类配置信息本质上都是字符串,只是由于安全性的原因,在存放和使用方面有些差异。
Kubernetes 中的 ConfigMap API 用来保存明文配置,Secret API 用来保存秘密配置。
2.6.1 ConfigMap #
export out="--dry-run=client -o yaml" # 定义Shell变量
kubectl create cm info --from-literal=k=v $out
ConfigMap 里的数据都是 Key-Value 结构,所以 --from-literal 参数使用 k=v 的形式生成数据。ConfigMap 的 YAML 描述大概如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: info
data:
count: '10'
debug: 'on'
path: '/etc/systemd'
greeting: |
say hello to kubernetes.
由上图可知,现在 ConfigMap 的 Key-Value 信息就已经存入了 etcd 数据库,后续就可以被其他 API 对象使用。
2.6.2 Secret #
Secret 和 ConfigMap 的结构和用法很类似,不过 Secret 对象又细分出很多类,比如:
- 访问私有镜像仓库的认证信息
- 身份识别的凭证信息
- HTTPS 通信的证书和私钥
- 一般的机密信息(格式由用户自行解释)
最后一种比较常见。创建 YAML 样板的命令是 kubectl create secret generic ,可以使用参数 --from-literal 给出 Key-Value 值:
kubectl create secret generic user --from-literal=name=root $out
echo 的 -n 参数是为了去掉字符串里隐含的换行符
比如有如下的一个 Secret YAML 描述:
apiVersion: v1
kind: Secret
metadata:
name: user
data:
name: cm9vdA== # root
pwd: MTIzNDU2 # 123456
db: bXlzcWw= # mysql
Secret 对配置参数做了 base64 加密。kubectl describe 不能直接看到内容,只能看到数据的大小。
2.6.3 使用配置 #
ConfigMap 和 Secret 只是一些存储在 etcd 里的字符串,如果想要在运行时产生效果,就必须要以某种方式 “注入” 到 Pod 里,让应用去读取。有两种实现途径:环境变量和加载文件。
环境变量 #
在 Pod 里描述容器的字段 “containers” 里有一个 “env”,它定义了 Pod 里容器能够看到的环境变量。可以使用 “value” 的形式,把环境变量的值写死在了 YAML 里,比如:
spec:
containers:
- image: busybox:latest
name: busy
env:
- name: os
value: "ubuntu"
这里的 os 环境变量就固定写死是 ubuntu 了。
实际上 env 还可以使用 “valueFrom” 字段,从 ConfigMap 或者 Secret 对象里获取值,这样就实现了把配置信息以环境变量的形式注入进 Pod,也就是配置与应用的解耦。
可以使用 kubectl explain 查看对 valueFrom 的说明:
valueFrom 字段指定了环境变量值的来源,可以是 configMapKeyRef 或者 secretKeyRef,然后需要再进一步指定应用的 ConfigMap/Secret 的 name 和它里面的 key,需要注意的是这个 name 字段是 API 对象的名字,也就是 ConfigMap 或是 Secret 对象里的metadata.name
的值,而不是 Key-Value 的名字。
如下的例子,ConfigMap YAML:
apiVersion: v1
kind: ConfigMap
metadata:
name: info
data:
count: '10'
debug: 'on'
path: '/etc/systemd'
greeting: |
say hello to kubernetes.
Secret YAML:
apiVersion: v1
kind: Secret
metadata:
name: user
data:
name: cm9vdA== # root
pwd: MTIzNDU2 # 123456
db: bXlzcWw= # mysql
env-pod YAML 引用了 ConfigMap 和 Secret 对象里的配置:
apiVersion: v1
kind: Pod
metadata:
name: env-pod
spec:
containers:
- env:
- name: COUNT
valueFrom:
configMapKeyRef:
name: info
key: count
- name: GREETING
valueFrom:
configMapKeyRef:
name: info
key: greeting
- name: USERNAME
valueFrom:
secretKeyRef:
name: user
key: name
- name: PASSWORD
valueFrom:
secretKeyRef:
name: user
key: pwd
image: busybox
name: busy
imagePullPolicy: IfNotPresent
command: [ "/bin/sleep", "300" ]
对于 env-pod,apply 运行起来之后,可以通过 kubectl exec 进到 pod 中:
envFrom #
如果 ConfigMap 里的信息比较多,用 env.valueFrom 一个个地写会非常麻烦,容易出错,而 envFrom 可以一次性地把 ConfigMap 里的字段全导入进 Pod,并且还能够指定变量名的前缀,非常方便。比如下面的这个示例:
cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: maria-cm
data:
DATABASE: 'db'
USER: 'wp'
PASSWORD: '123'
ROOT_PASSWORD: '123'
pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: maria-pod
labels:
app: wordpress
role: database
spec:
containers:
- image: mariadb:10
name: maria
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3306
envFrom:
- prefix: 'MARIADB_'
configMapRef:
name: maria-cm
这里使用 envFrom 将 maria-cm 的数据全部加载进来到 pod 里,并设置了一个 prefix 前缀。
加载文件 #
Pod 有 Volume 存储卷的概念,如果把 Pod 理解成是一个虚拟机,那么 Volume 就相当于是虚拟机里的磁盘。可以为 Pod “挂载(mount)” 多个 Volume,里面存放供 Pod 访问的数据,这种方式有点类似 docker run -v。
在 Pod 里挂载 Volume 只需要在 “spec” 里增加一个 “volumes” 字段,然后再定义卷的名字和引用的 ConfigMap/Secret 就可以。Volume 属于 Pod,不属于容器,所以这个字段和 “containers” 字段是同级的,都属于 “spec”。
比如,分别引用 ConfigMap 和 Secret,名字是 cm-vol 和 sec-vol:
spec:
volumes:
- name: cm-vol
configMap:
name: info
- name: sec-vol
secret:
secretName: user
在容器里挂载需用到 volumeMounts 字段,该字段可以把定义好的 Volume 挂载到容器里的某个路径下,还需要在里面用 mountPath,name 明确地指定挂载路径和 Volume 的名字,配置信息就可以加载成文件。
containers:
- volumeMounts:
- mountPath: /tmp/cm-items
name: cm-vol
- mountPath: /tmp/sec-items
name: sec-vol
比如如下的 vol-pod YAML:
apiVersion: v1
kind: Pod
metadata:
name: vol-pod
spec:
volumes:
- name: cm-vol
configMap:
name: info
- name: sec-vol
secret:
secretName: user
containers:
- volumeMounts:
- mountPath: /tmp/cm-items
name: cm-vol
- mountPath: /tmp/sec-items
name: sec-vol
image: busybox
name: busy
imagePullPolicy: IfNotPresent
command: [ "/bin/sleep", "300" ]
apply 创建后可以通过 exec 进入 pod 查看:
ConfigMap 和 Secret 都变成了目录的形式,而里面的 Key-Value 变成了一个个的文件,而文件名就是 Key。
ConfigMap 在设计上不是用来保存大量数据的。在 ConfigMap 中保存的数据不可超过 1 MiB。如果需要保存超出此尺寸限制的数据,可以考虑挂载存储卷。
环境变量用法简单,更适合存放简短的字符串,而 Volume 更适合存放大数据量的配置文件,在 Pod 里加载成文件后让应用直接读取使用。