K8S-ConfigMap和Secret
ConfigMap和Secret性质上比较类似,K8S中都通常用来存储一些配置信息,Secret一般用来保存密码、token、密钥等敏感数据的配置问题,定义声明式文件的时候可以用volume或者环境变量方式引用,ConfigMap通常用来存一些没那么敏感的数据。
ConfigMap
简介
ConfigMap API资源用来保存key-value pair配置数据,这个数据可以在pods里使用,或者被用来为像controller一样的系统组件存储配置数据。ConfigMap不是属性配置文件的替代品,ConfigMaps只是作为多个properties文件的引用,比如下面这个例子中
data一栏包括很多配置数据,可以用来保存单个属性,也可以用来保存一个配置文件,配置的数据可以在pod中来使用,ConfigMaps可以被用来:
- 设置环境变量的值
- 在容器里设置命令行参数
- 在数据卷里创建config文件
一个简单的ConfigMap
config-example.yml
1 | kind: ConfigMap |
我们使用如下命令就可以创建这个ConfigMap了
1 | kubectl apply -f config-example.yml |
创建ConfigMap的几种方式
同时我们可以使用如下命令查看如何创建ConfigMap
1 | [root@localhost home]# kubectl create configmap -h |
使用文件夹创建ConfigMap
比如我们现在有如下两个properties文件:
game.properties
1 | enemies=aliens |
ui.properties
1 | color.good=purple |
现在我们把这两个文件都放在/home/properties
目录下
1 | [root@localhost properties]# cat /home/properties/game.properties |
我们使用如下命令创建出这个ConfigMap
1 | [root@localhost properties]# kubectl create configmap game-config --from-file=/home/properties/ |
--from-file
指定的是只要在目录下面的所有文件都会被用在ConfigMap里面创建一个键值对,键的名字就是文件名字,值就是文件内容
可以使用如下命令查看这个刚创建的ConfigMap,并且使用-o yaml
指定以yaml的格式输出
1 | [root@localhost properties]# kubectl get configmap game-config -o yaml |
使用单个文件创建ConfigMap
也可以使用之前的单个properties文件进行创建ConfigMap,比如使用如下命令创建game.properties
的ConfigMap,并且使用yaml格式进行查看
1 | [root@localhost properties]# kubectl create configmap game-config-222 --from-file=/home/properties/game.properties |
命令行指定key-value创建ConfigMap
我们可以直接在create的时候指定创建的ConfigMap的key-value,比如下面的命令
1 | [root@localhost properties]# kubectl create configmap special-config2 --from-literal=test=good --from-literal=test2=good2 |
Pod中使用ConfigMap
使用ConfigMap来替代环境变量
定义如下文件pod-config-env.yml
1 | apiVersion: v1 |
上文中我们定义了两个ConfigMap,一个是special-config
,一个是env-config
,分别以不同的方式引入,一种是直接envFrom将env-config
整体引入pod作为环境变量,一种是通过env
的定义按需引入,指定name为ConfigMap
的名字,key为ConfigMap
中的key。
使用如下命令进行创建
1 | [root@localhost properties]# kubectl apply -f /home/pod-config-env.yml |
ConfigMap 的更新
ConfgiMap 更新后,如果是以文件夹方式挂载的,会自动将挂载的 Volume 更新。如果是以文件形式挂载的,则不会自动更新。
但是对多数情况的应用来说,配置文件更新后,最简单的办法就是重启 Pod(杀掉再重新拉起)。如果是以文件夹形式挂载的,可以通过在容器内重启应用的方式实现配置文件更新生效。即便是重启容器内的应用,也要注意 ConfigMap 的更新和容器内挂载文件的更新不是同步的,可能会有延时,因此一定要确保容器内的配置也已经更新为最新版本后再重新加载应用。
Secret
Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 ssh key。将这些信息放在 Secret
中比放在 Pod
的定义或者 docker 镜像中来说更加安全和灵活。
创建一个简单的 Secret
1 | Create files needed for rest of example. |
使用 kubectl 将这个文件打包为一个 Secret 中并在 APIServer 中创建了一个对象。generic 指的是从本地 file, directory 或者 literal value 创建一个 secret
1 | kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt |
使用如下指令可以看到创建好的 Secret,重点关注 data 字段。
1 | [root@localhost ~]# kubectl get secret db-user-pass -o yaml |
仔细看你会发现,这个 data 字段并不是一开始我们写入的值,我们写入的 password.txt 是 “1f2d1e2e67df”, 写入 username.txt 的是 “admin”。
默认情况下,get 和 describe 命令都不会显示文件的内容。这是为了防止将 secret 中的内容被意外暴露给从终端日志记录中刻意寻找它们的人,每一项值都会经过 base64 编码。
1 | [root@localhost ~]# echo -n "admin" | base64 |
Secret 的使用
Secret 可以作为数据卷被挂载,或作为环境变量暴露出来以供 pod 中的容器使用。它们也可以被系统的其他部分使用,而不直接暴露在 pod 内。例如,它们可以保存凭据,系统的其他部分应该用它来代表您与外部系统进行交互。
Pod 中使用 Secret
Pod 的 volume 中使用:
- 创建一个新的 Secret 或者使用已经有的 secret,多个 pod 可以使用同一个 Secret
- volumes数组中
spec.volumes[].secret.secretName
必须等于 Secret 对象的名字 - 将
spec.containers[].volumeMounts[]
加到需要用到该 secret 的容器中。指定spec.containers[].volumeMounts[].readOnly = true
和spec.containers[].volumeMounts[].mountPath
为您想要该 secret 出现的尚未使用的目录
1 | kind: Secret |
使用如下命令创建这个 pod-secret.yml
文件生成的 pod 和 secret,容器内已经被解码。
1 | kubectl apply -f pod-secret.yml |
Secret 的值作为环境变量
这个 pod 的两个环境变量使用我们之前创建的 Secret 的变量值。
1 | apiVersion: v1 |
进入 Pod 容器内部查看
1 | kubectl exec -ti secret-env-pod /bin/bash |
Secret 的自动更新
当已经在 volume 中被消费的 secret 被更新时,被映射的 key 也将被更新。
Kubelet 在周期性同步时检查被挂载的 secret 是不是最新的。但是,它正在使用其基于本地 ttl 的缓存来获取当前的 secret 值。结果是,当 secret 被更新的时刻到将新的 secret 映射到 pod 的时刻的总延迟可以与 kubelet 中的secret 缓存的 kubelet sync period + ttl 一样长。
经过实验,挂载 Secret 到文件目录的 Pod 中确实能实时更新到,但是使用 Secret 值作为环境变量的 Pod 并未更新。