这里介绍Kubernetes配置的ConfigMap
创建ConfigMap
对于非敏感性、非机密性的配置数据,Kubernetes提供了ConfigMap进行存储。具体地,其以键值对的形式进行存储。下面即是一个简单的利用Yaml文件定义配置数据的ConfigMap示例
1 2 3 4 5 6 7 8 9 10
| apiVersion: v1
kind: ConfigMap metadata: name: my-configmap-1 data: mysql.ip: 196.168.1.2 mysql.user: root mysql.password: "123456"
|
效果如下所示
事实上,ConfigMap还支持通过命令行进行创建。具体地:
- —from-literal=[key]=[value] :从字面量定义配置
- —from-file=[fileName] :从指定文件创建配置,Key默认为文件名,Value为该文件的内容
- —from-file=[key]=[fileName] :从指定文件创建配置,Key为指定名称,Value为该文件的内容
- —from-file=[folderName] :从指定文件夹创建配置, Key为该文件夹下各文件名, Value为相应文件的内容
假设目前应用的所有配置文件按如下方式存储
则我们可通过下述命令创建ConfigMap
1 2 3 4 5 6 7 8 9 10
| kubectl create configmap my-configmap-2 \ ` --from-file=PersonInfo/ \ ` --from-file=MongoDB.properties \ ` --from-file=pgdb=PostgreSQL.properties \ ` --from-literal=score="98"
|
效果如下所示
使用ConfigMap
基于环境变量
对于容器而言,其使用ConfigMap最简单的方式即是通过环境变量实现。具体地,利用ConfigMap的条目来初始化容器运行过程中所需的环境变量值。这里我们构建一个名为demo:1.0的容器镜像,Dockerfile如下所示
1 2 3 4 5
|
FROM ubuntu:22.10 COPY demo.sh /home/aaron/ ENTRYPOINT ["sh", "/home/aaron/demo.sh" ]
|
该镜像很简单,就是执行一个Shell脚本,具体地如下所示,获取环境变量的值、重复打印即可
1 2 3 4 5 6
| #!/bin/bash while true do echo "${greet}, I'm ${name}. I want to say: ${msg}" sleep 5s done
|
文件结构如下所示。Docker镜像构建完毕后推送至中央仓库Docker Hub当中,以便后续Kubernetes可以从中央仓库中拉取、使用该镜像
我们可以先通过Docker创建容器来验证下镜像是否正常
1 2 3 4
| docker run --name demo1 --rm -it \ --env greet="Hello" \ --env name="Tom" \ --env msg="Good Luck" demo:1.0
|
效果如下所示,符合预期
现在我们创建一个ConfigMap,并将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 47 48 49 50 51 52 53 54 55 56 57 58 59
|
apiVersion: v1 kind: ConfigMap metadata: name: my-configmap-3 data: app.greet: Hi app.name: Tom app.msg: Thank you
---
apiVersion: apps/v1 kind: ReplicaSet metadata: name: my-app-rs-1 spec: replicas: 1 selector: matchLabels: app: my-app-1 template: metadata: labels: app: my-app-1 spec: containers: - name: my-app-1 image: aaron1995/demo:1.0 env: - name: greet valueFrom: configMapKeyRef: name: my-configmap-3 key: app.greet optional: true - name: name valueFrom: configMapKeyRef: name: my-configmap-3 key: app.name optional: true - name: msg valueFrom: configMapKeyRef: name: my-configmap-3 key: app.msg optional: true
---
|
效果如下所示,通过查看容器日志说明其成功获取到了配置信息
如果ConfigMap的条目非常多,一个一个定义环境变量显然非常繁琐、麻烦。故我们还可以一次性将ConfigMap中的所有条目全部设置容器当中的环境变量。其中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
|
apiVersion: v1 kind: ConfigMap metadata: name: my-configmap-4 data: greet: Hello name: Aaron msg: I Love U
---
apiVersion: apps/v1 kind: ReplicaSet metadata: name: my-app-rs-2 spec: replicas: 1 selector: matchLabels: app: my-app-2 template: metadata: labels: app: my-app-2 spec: containers: - name: my-app-2 image: aaron1995/demo:1.0 envFrom: - configMapRef: name: my-configmap-4
---
|
效果如下所示,通过查看容器日志说明其成功获取到了配置信息
基于命令行参数
在Kubernetes中镜像的ENTRYPOINT、CMD指令均可以被覆盖,仅需在容器定义时设置command、args属性的值即可。虽然我们定义容器时无法对args属性直接引用ConfigMap中的条目。但可以先利用ConfigMap条目初始化环境变量,然后在args属性中引用该环境变量。以此实现将ConfigMap中的条目通过命令行参数暴露、传递给容器
这里我们定义一个名为demo:2.0的容器镜像,Dockerfile如下所示。其本质就是调用一个Shell脚本
1 2 3 4 5
|
FROM ubuntu:22.10 COPY demo.sh /home/aaron/ ENTRYPOINT ["sh", "/home/aaron/demo.sh" ]
|
该Shell脚本如下所示,其获取命令行参数并循环打印
1 2 3 4 5 6 7 8 9 10
| #!/bin/bash greet=$1 name=$2 msg=$3
while true do echo "${greet}, My name is ${name}. say: ${msg}" sleep 5s done
|
文件结构如下所示。Docker镜像构建完毕后推送至中央仓库Docker Hub当中,以便后续Kubernetes可以从中央仓库中拉取、使用该镜像
我们可以先通过Docker创建容器来验证下镜像是否正常
1 2
| docker run --name demo2 --rm -it demo:2.0 \ "Hi" "Lucy" "Have a nice Weekend"
|
效果如下所示,符合预期
现在我们创建一个ConfigMap,并将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 47 48 49 50 51 52 53 54 55
|
apiVersion: v1 kind: ConfigMap metadata: name: my-configmap-5 data: app.greet: Hi app.name: Tony app.msg: Good Night
---
apiVersion: apps/v1 kind: ReplicaSet metadata: name: my-app-rs-3 spec: replicas: 1 selector: matchLabels: app: my-app-3 template: metadata: labels: app: my-app-3 spec: containers: - name: my-app-3 image: aaron1995/demo:2.0 args: ["$(my.greet)", "$(my.name)", "$(my.msg)"] env: - name: my.greet valueFrom: configMapKeyRef: name: my-configmap-5 key: app.greet - name: my.name valueFrom: configMapKeyRef: name: my-configmap-5 key: app.name - name: my.msg valueFrom: configMapKeyRef: name: my-configmap-5 key: app.msg
---
|
效果如下所示,通过查看容器日志说明其成功获取到了配置信息
基于ConfigMap类型卷
基于环境变量、命令行参数的方式适用于少量配置的场景。且在上述两种方式当中,一旦ConfigMap中的条目值发生更新,容器无法在不重启的前提下感知到新的配置值。故可以通过ConfigMap类型卷的方式将ConfigMap中的条目暴露、传递到容器当中。显然该方式更适合较多配置的场景。且当ConfigMap发生更新后,ConfigMap类型卷中的文件也会自动更新。而无需重启容器
在此之前,我们先创建一个ConfigMap。其从文件、字面量当中创建配置
然后我们利用ConfigMap类型卷将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
| apiVersion: apps/v1 kind: ReplicaSet metadata: name: my-app-rs-5 spec: replicas: 1 selector: matchLabels: app: my-app-5 template: metadata: labels: app: my-app-5 spec: containers: - name: my-app-5 image: luksa/kubia volumeMounts: - name: my-volume-app-conf mountPath: /AppConf readOnly: true volumes: - name: my-volume-app-conf configMap: name: my-configmap-6
|
效果如下所示,符合预期
此外还可以将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
|
apiVersion: apps/v1 kind: ReplicaSet metadata: name: my-app-rs-6 spec: replicas: 1 selector: matchLabels: app: my-app-6 template: metadata: labels: app: my-app-6 spec: containers: - name: my-app-6 image: luksa/kubia volumeMounts: - name: my-volume-app-conf mountPath: /AppConf readOnly: true volumes: - name: my-volume-app-conf configMap: name: my-configmap-6 items: - key: PostgreSQL.properties path: pg.properties
|
效果如下所示,符合预期
众所周知,在Linux系统当中将文件系统挂载到非空文件夹时,会导致该非空文件夹下原有的文件全部被隐藏。此时原有文件自然也无法正常访问使用。为避免该问题,我们可以将ConfigMap中的指定条目挂载到容器的指定文件中。具体地,通过subPath选项实现。但需要注意的是,此时会导致配置无法进行热更新。即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
|
apiVersion: apps/v1 kind: ReplicaSet metadata: name: my-app-rs-7 spec: replicas: 1 selector: matchLabels: app: my-app-7 template: metadata: labels: app: my-app-7 spec: containers: - name: my-app-7 image: luksa/kubia volumeMounts: - name: my-volume-app-conf mountPath: /usr/db.conf subPath: PostgreSQL.properties - name: my-volume-app-conf mountPath: /usr/sex.conf subPath: sex volumes: - name: my-volume-app-conf configMap: name: my-configmap-6 defaultMode: 0742
|
效果如下所示,符合预期
Note
当ConfigMap中的配置值为数字时,如果以环境变量的方式进行暴露。会出现cannot convert int64 to string错误。究极原因是对于环境变量而言,其值永远都是字符串类型。解决办法也很简单,就是对ConfigMap中相关配置的值添加双引号,使其成为字符串类型
1 2 3 4 5 6 7
| apiVersion: v1 kind: ConfigMap metadata: name: my-configmap-demo data: app.count: "2" app.msg: Thank you
|
参考文献
- Kubernetes in Action中文版 Marko Luksa著
- 深入剖析Kubernetes 张磊著