配置管理-ConfigMap和Secret

配置管理需解决的问题:
  • 可变的配置参数如何打包到镜像中
  • 敏感信息防止泄露,如密码、密钥等
  • 每次配置更新都要重新打包,镜像版本过多也给镜像存储管理带来负担
  • 定制化太严重、可扩展能力差,且不容易复用

ConfiMap

  • 作用:主要用来保存一些非敏感数据,如环境变量、命令行参数或挂载到存储卷中。
  • ConfigMap通过键值对来存储信息,是个namespace级别的资源,kubectl操作时可简写成cm
  • 元数据使用data: 后跟相关键值
  • 支持键值对(值是数字需用双引号,即需用字符串来表示)、多行的文本(键后使用| 跟多行文本)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ cat cm-demo-mix.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-demo-mix # 对象名字
namespace: demo # 所在的命名空间
data: # 这是跟其他对象不太一样的地方,其他对象这里都是spec
# 每一个键都映射到一个简单的值
player_initial_lives: "3" # 注意这里的值如果数字的话,必须用字符串来表示
ui_properties_file_name: "user-interface.properties"
# 也可以来保存多行的文本
game.properties: |
enemy.types=aliens,monsters
player.maximum-lives=5
user-interface.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true

$ cat cm-demo-all-env.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-demo-all-env
namespace: demo
data:
SPECIAL_LEVEL: very
SPECIAL_TYPE: charm
可以通过kubectl create cm基于目录、文件或者字面值来创建。
1
2
3
kubectl create configmap <map-name> <data-source>
# <map-name> 是要设置的ConfigMap名称,<data-source> 是要从中提取数据的目录、文件或者字面值。
# 可以使用kubectl describe 或者 kubectl get 获取有关 ConfigMap 的信息。
基于目录创建ConfigMap
1
2
3
使用 kubectl create configmap 基于同一目录中的多个文件创建 ConfigMap。 
当你基于目录来创建 ConfigMap 时,kubectl 识别目录下基本名可以作为合法键名的 文件,并将这些文件打包到新的 ConfigMap 中。
普通文件之外的所有目录项都会被 忽略(例如,子目录、符号链接、设备、管道等等)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 创建本地目录
mkdir -p configure-pod-container/configmap/

# 将实例文件下载到 `configure-pod-container/configmap/` 目录
wget https://kubernetes.io/examples/configmap/game.properties -O configure-pod-container/configmap/game.properties
wget https://kubernetes.io/examples/configmap/ui.properties -O configure-pod-container/configmap/ui.properties

# 创建 configmap
kubectl create configmap game-config --from-file=configure-pod-container/configmap/
# 以上命令将 configure-pod-container/configmap 目录下的所有文件,也就是 game.properties 和 ui.properties 打包到 game-config ConfigMap 中。

kubectl describe configmaps game-config
Name: game-config
Namespace: default
Labels: <none>
Annotations: <none>

Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties:
----
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
kubectl get configmaps game-config -o yaml
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2016-02-18T18:52:05Z
name: game-config
namespace: default
resourceVersion: "516"
selfLink: /api/v1/namespaces/default/configmaps/game-config
uid: b4952dc3-d670-11e5-8cd0-68f728db1985
data:
game.properties: |
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
基于文件创建ConfigMap
1
2
# 可以使用 kubectl create configmap 基于单个文件或多个文件创建 ConfigMap。
kubectl create configmap game-config-2 --from-file=configure-pod-container/configmap/game.properties

Pod 必须和 ConfigMap 在同一个 namespace 下面;
在创建 Pod 之前,请务必保证 ConfigMap 已经存在,否则 Pod 创建会报错

ConfigMap的几大使用场景
  • 命令行参数
  • 环境变量,可以只注入部分变量,也可全部注入
  • 挂载文件,可以是单个文件也可以是所有键值对,用每个键值作为文件名。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
$ cat cm-demo-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: cm-demo-pod
namespace: demo
spec:
containers:
- name: demo
image: busybox:1.28
  command:
  - "bin/sh"
- "-c"
  - "echo PLAYER_INITIAL_LIVES=$PLAYER_INITIAL_LIVES && sleep 10000"
  env:
  # 定义环境变量
  - name: PLAYER_INITIAL_LIVES # 请注意这里和 ConfigMap 中的键名是不一样的
      valueFrom:
      configMapKeyRef:
          name: cm-demo-mix # 这个值来自ConfigMap
          key: player_initial_lives # 需要取值的键
  - name: UI_PROPERTIES_FILE_NAME
      valueFrom:
      configMapKeyRef:
          name: cm-demo-mix
          key: ui_properties_file_name
  envFrom: # 可以将 configmap 中的所有键值对都通过环境变量注入容器中
  - configMapRef:
  name: cm-demo-all-env
  volumeMounts:
  - name: full-config # 这里是下面定义的 volume 名字
mountPath: "/config" # 挂载的目标路径
  readOnly: true
  - name: part-config
  mountPath: /etc/game/
  readOnly: true
volumes: # 您可以在 Pod 级别设置卷,然后将其挂载到 Pod 内的容器中
- name: full-config # 这是 volume 的名字
  configMap:
  name: cm-demo-mix # 提供你想要挂载的 ConfigMap 的名字
- name: part-config
  configMap:
  name: cm-demo-mix
  items: # 我们也可以只挂载部分的配置
  - key: game.properties
      path: properties

Secret

  • 用secret保存一些敏感数据信息,比如密码、密钥、token等
  • 用法和ConfigMap基本一致,都可以用作环境变量或者文件挂载
1
2
3
4
5
6
# 使用kubectl来创建secret,支持三种类型
kubectl create secret -h
Available Commands:
docker-registry Create a secret for use with a Docker registry
generic Create a secret from a local file, directory or literal value
tls Create a TLS secret
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 创建一个secret来保存私有容器仓库的身份信息
$ kubectl create secret -n demo docker-registry regcred \
--docker-server=yourprivateregistry.com \
--docker-username=liyk \
--docker-password=mypassw0rd \
--docker-email=liyk@example.com
secret/regcred created
$ kubectl get secret -n demo regcred
NAME TYPE DATA AGE
regcred kubernetes.io/dockerconfigjson 1 28s

# 可看出创建出来的secret类型是:kubernetes.io/dockerconfigjson
$ kubectl get secret regcred -n demo --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode
{"auths":{"yourprivateregistry.com":{"username":"allen","password":"mypassw0rd","email":"allen@example.com","auth":"YWxsZW46bXlwYXNzdzByZA=="}}}
# Secret 保存的数据都是通过 base64 加密后的数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 平时使用较为广泛的还有另外一种Opaque类型的 Secret
$ cat secret-demo.yaml
apiVersion: v1
kind: Secret
metadata:
name: dev-db-secret
namespace: demo
type: Opaque
data: # 这里的值都是 base64 加密后的
password: UyFCXCpkJHpEc2I9
username: ZGV2dXNlcg==

# 也可以通过如下等价的 kubectl 命令来创建出来
$ kubectl create secret generic dev-db-secret -n demo \
--from-literal=username=devuser \
--from-literal=password='S!B\*d$zDsb='

# 或通过文件来创建对象
$ echo -n 'username=devuser' > ./db_secret.txt
$ echo -n 'password=S!B\*d$zDsb=' >> ./db_secret.txt
$ kubectl create secret generic dev-db-secret -n demo \
--from-file=./db_secret.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 在pod中使用secret
$ cat pod-secret.yaml
apiVersion: v1
kind: Pod
metadata:
name: secret-test-pod
namespace: demo
spec:
containers:
- name: demo-container
image: busybox:1.28
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- secretRef:
name: dev-db-secret
restartPolicy: Never
写在最后
1
2
3
ConfigMap 和 Secret 是 Kubernetes 常用的保存配置数据的对象,你可以根据需要选择合适的对象存储数据。
通过 Volume 方式挂载到 Pod 内的,kubelet 都会定期进行更新。
但是通过环境变量注入到容器中,这样无法感知到 ConfigMap 或 Secret 的内容更新。
  • 如果业务自身支持reload,可直接定期进行reload(可以配合readlinessProbe一起使用)。比如nginx -s reload可以通过inotify感知到文件更新。
  • 如果业务没上述能力,可以采用滚动升级的方式。借助开源工具Reloader,一旦发现configmap和secret更新就自动触发对deployment或statefulset等工作负载对象进行滚动升级。 (https://github.com/stakater/Reloader)
-------------本文结束感谢您的阅读-------------
原创技术分享,感谢您的支持。