一、什么是ConfigMap
ConfigMap翻译过来即为“配置字典”,在实际的生产环境中,应用程序配置经常需要且又较为复杂,参数、config文件、变量等如果直接打包到镜像中,将会降低镜像的可移植性,因此期望有一种方式可以将配置从应用程序中解耦出来,ConfigMap正是在此背景下诞生的,它用于保存配置数据的键值(key-value)对,可以用来保存单个属性,也可以用来保存配置文件。ConfigMap 跟 secret 很类似,但它可以更方便地处理不包含敏感信息的字符串。
二、适用场景?
适用于存储不包含敏感信息的变量、属性或文件。
比如在一个集群中,可将应用程序所需的参数、变量、配置文件存放到ConfigMap中,在开发、测试和生产环境将同1个ConfigMap(前提是同1个namespace)挂载到Pod中,这样既可以实现配置和容器镜像的分离,也可方便的实现统一管理,比如可以利用其热更新的机制,修改完成后会同步到挂载了此ConfigMap的所有Pod中。
三、ConfigMap的创建
1、文件目录创建
支持以目录的方式创建ConfigMap,其中文件名将作为key,文件内容作为value,有几个文件将会存在几个键值对,如下图,先创建1个目录,此目录下存在两个文件
[root@k8s-master confdirtest]# ls conftest1.txt conftest.txt
[root@k8s-master consecret]# kubectl create configmap con-dir-test --from-file=confdirtest/ configmap/con-dir-test created
其格式为kubectl creat configmap "configmap的名字" --from-file="目录"/,这种适用于将某个目录下的所有文件作为key,文件内容作为value进行创建。
[root@k8s-master consecret]# kubectl get cm | grep con-dir-test con-dir-test 2 20s [root@k8s-master consecret]# kubectl describe cm con-dir-test Name: con-dir-test Namespace: default Labels: <none> Annotations: <none> Data ==== conftest.txt: ---- name=this is test #文件conftest.txt的内容 conftest1.txt: ---- name=this is test1 #文件conftest1.txt的内容 Events: <none>
2、文件方式创建
--from-file的方式除了用于目录的方式之外,同样还适用于指定文件的方式进行创建,其中文件名称将作为key名称,文件内容作为value,如下所示,先建立一个配置文件testconf.cfg
[root@k8s-master consecret]# cat testconf.cfg listenport=8080 name=testconf serverip=10.0.0.1
接下里将其生成1个configmap文件,如下所示,其格式为:kubectl create configmap "configmap名称" --from-file=“文件名”
[root@k8s-master consecret]# kubectl create configmap conf-file-test --from-file=testconf.cfg configmap/conf-file-test created [root@k8s-master consecret]# kubectl describe cm conf-file-test Name: conf-file-test Namespace: default Labels: <none> Annotations: <none> Data ==== testconf.cfg: ---- listenport=8080 name=testconf serverip=10.0.0.1 Events: <none>
此方式适用于将某个或多个配置文件生成同一个configmap文件的场景
3、直接创建key-value
可直接指定需要data的key-value键值对进行创建,如下所示,使用"--from-literal"选项可在命令行直接创建configmap对象,若是创建多个,可重复多次进行创建,但是注意其key的名称不可重复,这种方式适用于直接指定key-value的方式进行创建。
[root@k8s-master consecret]# kubectl create configmap con-key-value --from-literal=key1=name1 configmap/con-key-value created [root@k8s-master consecret]# kubectl describe cm con-key-value Name: con-key-value Namespace: default Labels: <none> Annotations: <none> Data ==== key1: ---- name1 Events: <none> [root@k8s-master consecret]# kubectl create configmap con-key-value-test --from-literal=class.1=202 --from-literal=class.2=502 configmap/con-key-value-test created [root@k8s-master consecret]# kubectl describe cm con-key-value-test Name: con-key-value-test Namespace: default Labels: <none> Annotations: <none> Data ==== class.1: ---- 202 class.2: ---- 502 Events: <none>
4、导入环境变量创建
可将环境变量以--from-env-file的方式进行创建,其格式为:kubectl crete configmap "configmap的名称" --from-env=file=环境变量文件.env
[root@k8s-master consecret]# echo -e "testenv1=1\testenv2=2" | tee configtest.env testenv1=1 estenv2=2 [root@k8s-master consecret]# kubectl create configmap conf-env-test --from-env-file=configtest.env configmap/conf-env-test created [root@k8s-master consecret]# kubectl describe cm conf-env-test Name: conf-env-test Namespace: default Labels: <none> Annotations: <none> Data ==== testenv1: ---- 1 estenv2=2 Events: <none>
四、ConfigMap的使用
1、热更新(目录形式挂载)
首先先成功创建一个ConfigMap
[root@k8s-master consecret]# cat conf-delete-test.yaml apiVersion: v1 kind: ConfigMap metadata: name: zltest-conf-delete namespace: default data: zltest.show: delete-test
[root@k8s-master consecret]# kubectl delete deployment dep-deleye-conf-test deployment.apps "dep-deleye-conf-test" deleted [root@k8s-master consecret]# kubectl create -f conf-delete-test.yaml configmap/zltest-conf-delete created [root@k8s-master consecret]# kubectl get cm | grep zltest-conf-delete zltest-conf-delete 1 44s
将其以卷目录形式挂载到Pod容器中,创建一个deployment
[root@k8s-master zhanglei]# cat dep-delete-con.yaml apiVersion: apps/v1 kind: Deployment metadata: name: dep-deleye-conf-test namespace: default labels: app: nginx-delete-conf-test spec: replicas: 2 selector: matchLabels: app: nginx-deployment-delete template: metadata: labels: app: nginx-deployment-delete spec: containers: - name: nginx image: nginx:latest ports: - name: testconf containerPort: 80 volumeMounts: - name: nginxconf mountPath: /data/deletetest volumes: - name: nginxconf configMap: name: zltest-conf-delete
[root@k8s-master zhanglei]# kubectl create -f dep-delete-con.yaml deployment.apps/dep-deleye-conf-test created [root@k8s-master zhanglei]# kubectl get deployment |grep dep-deleye-conf-test dep-deleye-conf-test 2/2 2 2 56s
执行以上的步骤后,名为zltest-conf-delete的ConfigMap已被成功挂载到Pod的容器中,如果在运行的过程中,修改下ConfigMap的文件,会出现怎样的情况呢?先edit下ConfigMap,增加一个键值对
[root@k8s-master zhanglei]# kubectl describe cm zltest-conf-delete Name: zltest-conf-delete Namespace: default Labels: <none> Annotations: <none> Data ==== zltest.show: ---- delete-test Events: <none>
[root@k8s-master consecret]# kubectl edit cm zltest-conf-delete # Please edit the object below. Lines beginning with a ‘#‘ will be ignored, # and an empty file will abort the edit. If an error occurs while saving this file will be # reopened with the relevant failures. # apiVersion: v1 data: zltest.show: delete-test addkey: addvalue # 新增的键值对 kind: ConfigMap metadata: creationTimestamp: "2020-07-23T11:29:11Z" managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:data: .: {} f:zltest.show: {} manager: kubectl operation: Update time: "2020-07-23T11:29:11Z" name: zltest-conf-delete namespace: default
[root@k8s-master consecret]# kubectl edit cm zltest-conf-delete
configmap/zltest-conf-delete edited
验证下新增的键值对是否会同步热更新到Pod的容器中,通过exec的方式登录到容器中进行查看,新添加的键值对以同步更新到Pod的容器中,
不需要以容器进行额外的操作,这是卷目录的形式挂载的热更新,但是若是通过环境变量env或者通过文件的形式挂载到容器中,是不会支持热更新的,这里需要注意下。
[root@k8s-master consecret]# kubectl exec -it dep-deleye-conf-test-869747b77f-67w9h -- bash root@dep-deleye-conf-test-869747b77f-67w9h:/# cd data root@dep-deleye-conf-test-869747b77f-67w9h:/data# ls deletetest root@dep-deleye-conf-test-869747b77f-67w9h:/data# cd deletetest/ root@dep-deleye-conf-test-869747b77f-67w9h:/data/deletetest# ls addkey zltest.show
如果删除已将挂载到Pod中的容器的ConfigMap会出现怎样的情况呢,先删除ConfigMap,然后再次登录到容器中进行验证
[root@k8s-master consecret]# kubectl delete cm zltest-conf-delete configmap "zltest-conf-delete" deleted [root@k8s-master consecret]# kubectl exec -it dep-deleye-conf-test-869747b77f-67w9h -- bash root@dep-deleye-conf-test-869747b77f-67w9h:/data/deletetest# ls addkey zltest.show
若未对Pod进行删除的操作,删除ConfigMap成功,但是挂载到容器的目录依然会存在,并不会一起被删除,此时若删除Pod,副本控制器会重新拉
起1个Pod,会创建成功吗?接下来验证下
[root@k8s-master consecret]# kubectl get pod | grep dep-deleye-conf-test dep-deleye-conf-test-869747b77f-kgzqt 1/1 Running 0 134m dep-deleye-conf-test-869747b77f-mf6vc 0/1 ContainerCreating 0 2m13s
重新拉起Pod一直会是ContainerCreating状态,详细查看下原因
[root@k8s-master consecret]# kubectl describe pod dep-deleye-conf-test-869747b77f-mf6vc Name: dep-deleye-conf-test-869747b77f-mf6vc Namespace: default Priority: 0 Node: k8s-master/192.168.126.129 Start Time: Thu, 23 Jul 2020 21:47:00 +0800 Labels: app=nginx-deployment-delete pod-template-hash=869747b77f Annotations: <none> Status: Pending IP: IPs: <none> Controlled By: ReplicaSet/dep-deleye-conf-test-869747b77f Containers: nginx: Container ID: Image: nginx:latest Image ID: Port: 80/TCP Host Port: 0/TCP State: Waiting Reason: ContainerCreating Ready: False Restart Count: 0 Environment: <none> Mounts: /data/deletetest from nginxconf (rw) /var/run/secrets/kubernetes.io/serviceaccount from default-token-74s86 (ro) Conditions: Type Status Initialized True Ready False ContainersReady False PodScheduled True Volumes: nginxconf: Type: ConfigMap (a volume populated by a ConfigMap) Name: zltest-conf-delete Optional: false default-token-74s86: Type: Secret (a volume populated by a Secret) SecretName: default-token-74s86 Optional: false QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s node.kubernetes.io/unreachable:NoExecute for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled <unknown> default-scheduler Successfully assigned default/dep-deleye-conf-test-869747b77f-mf6vc to k8s-master Warning FailedMount 11s (x8 over 75s) kubelet, k8s-master MountVolume.SetUp failed for volume "nginxconf" : configmap "zltest-conf-delete" not found
可以看到是FailedMount,volume异常了,K8S中删除的时候是不会判断这个依赖关系的,因此在生产的实际使用中,这点还是需要注意。
2、通过环境变量引入
除了通过volume的方式挂载到容器中使用之外,还可将configmap作为环境变量的方式引入到容器中,这里以con-key-value-test作为例子
[root@k8s-master consecret]# kubectl get cm |grep con-key-value-test con-key-value-test 2 34m
[root@k8s-master zhanglei]# cat dep-conf-test.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-conf-env-test namespace: default labels: app: nginx-deployment spec: replicas: 1 selector: matchLabels: app: nginx-deployment template: metadata: labels: app: nginx-deployment spec: containers: - name: nginx image: nginx:latest # command: [ "/bin/bash","-c","env" ] ports: - containerPort: 80 env: - name: test-env1-conf # 环境变量名称1 valueFrom: configMapKeyRef: name: con-key-value-test key: class.1 # 指定key名称即可 - name: test-env2-conf # 环境变量名称2 valueFrom: configMapKeyRef: name: con-key-value-test # 引入configmap key: class.2
[root@k8s-master zhanglei]# kubectl create -f dep-conf-test.yaml deployment.apps/nginx-conf-env-test created [root@k8s-master zhanglei]# kubectl get pod |grep env-test nginx-conf-env-test-56f5c9b88-xt86x 1/1 Running 0 34s
可以看到Pod处于running的状态,登入到容器验证下以存在环境变量,如下所示,验证成功,值得注意的是,这种方式相当于新生成的环境变量指向configmap中的key所对应的value
root@nginx-conf-env-test-56f5c9b88-xt86x:/# ls bin docker-entrypoint.d home media proc sbin tmp boot docker-entrypoint.sh lib mnt root srv usr dev etc lib64 opt run sys var root@nginx-conf-env-test-56f5c9b88-xt86x:/# env test-env2-conf=502 # 环境变量=原class.1的value test-env1-conf=202
五、总结
configmap是K8s中重要的配置管理方式,本文介绍了configmap的概念、使用场景、多种创建的方式、最后介绍了如何进行使用。
作者简介:云计算容器\Docker\K8s\Serverless方向产品经理,学点技术,为更好地设计产品。