3.7 ConfigMap解耦配置文件
文章目录1、在docker镜像中定义命令行与参数2、在k8s的pod资源清单中定义容器执行的命令和参数2.1、通过pod定义传递命令参数2.2、通过pod定义传入环境变量2.3、pod定义的环境变量引用其他环境变量3、利用ConfigMap解耦配置3.1、创建ConfigMap3.2 通过ConfigMap给容器传递环境变量3.2.1 向容器传入ConfigMap单个key环境变量3.2.2 向容
容器中应用启动或运行需要依赖很多环境变量或参数,传统应用下, 都是把配置文件和应用打成同意的jar包,每次修改配置都要重新部署应用。在云容器时代,可以通过以下集中方式来处理配置变量:容器镜像、pod定义、ConfigMap解耦配置。
1、在docker镜像中定义命令行与参数
在docker中运行镜像之前,需要先通过dockerfile做好镜像文件,在做镜像文件时,可以把应用的启动命令与参数做在镜像中,如下dockerfile所示
FROM busybox
ENTRYPOINT ["sleep"]
CMD ["30"]
在容器中通过镜像启动时,通过ENTRYPOINT 指定默认执行的命令,CMD指定默认参数,容器启动后默认执行 sleep 30。
把命令与参数做到镜像中缺点:每次修改参数时,都需要重新做镜像,在生产上就需要停应用,启动新的镜像。
2、在k8s的pod资源清单中定义容器执行的命令和参数
2.1、通过pod定义传递命令参数
可以在k8s中的资源清单中传递命令和参数,当需要修改应用命令和参数时,只需要修改k8s的资源清单即可。
apiVersion: v1
kind: Pod
metadata:
name: busybox1
spec:
containers:
- image: busybox
name: buysbox1
imagePullPolicy: IfNotPresent
command: ["sleep"]
args: ["300"]
如上所示,只需要在定义pod时,通过command和args传入应用启动需要的命令和参数即可。
优点:修改参数,只需重启应用即可,不用重新做镜像。
缺点:改应用启动的命令和参数时,虽说不用重新做镜像,只修改pod资源清单即可,但修改清单后,容器会执行重启策略,修改命令参数导致了应用重启。
2.2、通过pod定义传入环境变量
在定义pod的资源清单时,可以通过env传入环境变量到容器中
pod_test.yaml
apiVersion: v1
kind: Pod
metadata:
name: busybox1
spec:
containers:
- image: busybox
name: buysbox1
imagePullPolicy: IfNotPresent
command: ["sleep"]
args: ["300"]
env: #通过env把model传递到容器中
- name: model
value: dev
创建上面的资源清单kubectl apply -f pod_test.yaml
进入pod中容器,查看内部环境变量
发现pod资源订单中定义的env的环境变量已经传递到容器中,在容器中就可以获取model的值进行运用了。
优点:修改应用环境变量,不用重新做镜像,只需重启应用即可。
缺点:修改应用环境变量,虽说不用重新做镜像,只修改pod资源清单即可,但修改清单后,容器会执行重启策略,修改命令参数导致了应用重启。
2.3、pod定义的环境变量引用其他环境变量
如下所示,在定义file的环境变量时引用model的环境变量。
apiVersion: v1
kind: Pod
metadata:
name: busybox1
spec:
containers:
- image: busybox
name: buysbox1
imagePullPolicy: IfNotPresent
command: ["sleep"]
args: ["300"]
env:
- name: model
value: "dev"
- name: file
value: "$(model)_file" #引用其他化境变量
优点:修改环境变量不需要重新做镜像
缺点:修改环境变量会重启应用,环境变量与应用源码耦合在一起,并且生产测试环境不同,有时要维护多套资源定义清单。
3、利用ConfigMap解耦配置
前面介绍不管是把配置定义在镜像中还是在pod中,如果修改配置就要重新做镜像或修改pod定义,尤其是维护多套环境时需要经常修改配置,尤其不方便,现可以通过ConfigMap把配置分离出来,修改配置时只需要修改ConfigMap即可。ConfigMap其实就是键值对,值可以时字面量值,也可以是整个文件。
3.1、创建ConfigMap
- 通过指定字面量值映射环境变量,创建configmap
kubectl create configmap myconfig1 --from-literal=model=prod
创建myconfig1时,指定了环境变量model=prod。
注:创建的ConfigMap的名字可以由字母、数字、破折号、下划线以及圆点组成。
- 通过yaml文件创建ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: myconfig2
data:
model: prod
file: prod_file
执行 kubectl apply -f config_test.yaml
如上所示,执行完创建命令后,会创建名字为myconfig2的ConfigMap,指定了model和file的环境变量。
- 通过文件内容创建ConfigMap
例如,有env_test.conf文件,内容如下,
model:prod
file:prod_file
author:lzj
现从该文件创建ConfigMap,执行kubectl create ConfigMap myconfig3 --from-file=envkey=env_test.conf
,创建的myconfig3的键名为envkey。如果要从多个文件创建ConfigMap,可以用多个–from-file指定。
- 通过文件夹创建ComfigMap
比如在env_work目录下存在env_test1.conf 和env_test.conf两个文件,env_test.conf内如如上面示例所示,env_test1.conf内容如下:
level:info
application:loan
现从env_work目录创建configmap,执行命令kubectl create configmap myconfig4 --from-file=env_work/
,创建成功后,会以文件名作为键名。
- 通过混合项创建ConfigMap
可以通过以上几种混合方式创建ConfigMap,如下所示
kubectl create configmap myconfig5 --from-literal=model=prod --from-file=env_test2.conf --from-file=env_work/
3.2 通过ConfigMap给容器传递环境变量
3.2.1 向容器传入ConfigMap单个key环境变量
现将上面创建的ConfigMap名为myconfig1中的model=prod传入到容器中,例如
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod1
spec:
containers:
- image: busybox
name: buysbox1
imagePullPolicy: IfNotPresent
command: ["/bin/sh", "-c", "sleep 300"]
env: #指定环境变量
- name: MODEL
valueFrom:
configMapKeyRef:
name: myconfig1
key: model
通过上述示例,指定该了容器中的MODEL变量的值来源于myconfig1中的model变量的值,即MODEL=prod
3.2.2 向容器传递ConfigMap的所有环境变量
将上面创建的名字为myconfig3的ConfigMap传入容器中,myconfig3中键为文件env_test.conf名,值为文件内容,把文件中所有的环境变量都传递到了容器中
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod2
spec:
containers:
- image: busybox
name: buysbox2
imagePullPolicy: IfNotPresent
command: ["/bin/sh", "-c", "sleep 300"]
envFrom: #将整个ConfigMap传递进来
- configMapRef:
name: myconfig3
通过该示例,env_test.conf文件被传递到容器中
3.2.3 通过ConfigMap向容器传递命令行参数
可以利用ConfigMap初始化某个环境变量,然后在命令行参数中引用该环境变量。如下所示
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod
spec:
containers:
- image: busybox
name: buysbox2
imagePullPolicy: IfNotPresent
command: ["/bin/sh", "-c", "echo $(model_env) > /root/test.txt & sleep 300"] #引用model_env环境变量的值
env:
- name: model_env
valueFrom:
configMapKeyRef: #从myconfig1中传递model环境变量
name: myconfig1
key: model
利用上面yaml创建pod并查看容器执行的命令
[root@k8s-master01 pod_work]# kubectl exec -it configmap-pod -- /bin/sh
/ # cd root
~ # ls
test.txt
~ # cat test.txt
prod
3.2.4 通过ConfigMap挂载数据卷
前面都是把键值对或文件传递到容器的环境变量中,本小节还可以通过ConfigMap把文件挂在到容器中指定的目录下。例如上面创建的myconfig3下挂在了env_test.conf文件,现把该文件挂在到容器中的/root/lzj目录下,如下所示
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod
spec:
containers:
- image: busybox
name: buysbox4
imagePullPolicy: IfNotPresent
command: ["/bin/sh", "-c", "sleep 300"]
volumeMounts:
- name: config-volume #名字要和volumes中的name一致
mountPath: /root/lzj #挂载卷目录
volumes:
- name: config-volume
configMap:
name: myconfig3
上述yaml,把volumes卷中的myconfig3中的文件挂载到容器中的/root/lzj目录。注意volumeMounts要和volumes中的name一致。下面查看挂载情况
[root@k8s-master01 pod_work]# kubectl apply -f pod4.yaml
pod/configmap-pod created
[root@k8s-master01 pod_work]# kubectl exec -it configmap-pod -- /bin/sh
/ # cd root
~ # ls
lzj
~ # cd lzj
~/lzj # ls
env_test.conf
~/lzj # vi env_test.conf
3.2.5 通过ConfigMap的指定key挂载数据卷
可以通过ConfigMap把指定key文件以一个新的文件名挂载到容器指定目录,例如把myconfig4下的env_test1.conf和env_test.conf两个文件挂载到容器中/root/lzj目录下的env1.conf和env.conf文件。如下所示
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod
spec:
containers:
- image: busybox
name: buysbox5
imagePullPolicy: IfNotPresent
command: ["/bin/sh", "-c", "sleep 300"]
volumeMounts:
- name: config-volume
mountPath: /root/lzj
volumes:
- name: config-volume
configMap:
name: myconfig4
items: #指定myconfig4的key,只把指定的key文件挂载到容器中
- key: env_test1.conf
path: env1.conf
- key: env_test.conf
path: env.conf
查看挂载的文件
[root@k8s-master01 pod_work]# kubectl apply -f pod5.yaml
pod/configmap-pod created
[root@k8s-master01 pod_work]# kubectl exec -it configmap-pod -- /bin/sh
/ # cd /root/lzj
~/lzj # ls
env.conf env1.conf
从示例可知,myconfig4下指定的两个key文件分别挂载到了容器/root/lzj目录下的env.conf和env1.conf文件。
3.2.6 ConfigMap的热更新
使用ConfigMap挂载卷到容器目录还有一个优点,修改ConfigMap不必重启pod,pod会热加载ConfigMap中修改的文件,如下所示
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: configmap-deployment
spec:
replicas: 1
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- name: config-volume
mountPath: /usr/share/nginx/html/
volumes:
- name: config-volume
configMap:
name: myconfig6
创建资源清单,并进入容器查看挂载的文件名为key的hello.html内容为hello world
[root@k8s-master01 pod_work]# kubectl apply -f test.yaml
deployment.apps/configmap-deployment created
[root@k8s-master01 pod_work]# kubectl exec -it configmap-deployment-676f46ffd8-hlk2j -- /bin/sh
# cd /usr/share/nginx/html
# ls
hello
# cat hello
hello world
修改myconfig6挂载的文件kubectl edit cm myconfig6
apiVersion: v1
data:
hello: |
hello shanghai
kind: ConfigMap
过一段时间,再进入容器查询容器挂载的文件,发现挂载文件内容变为hello shanghai
注:此时等待了很长一段时间。
[root@k8s-master01 pod_work]# kubectl exec -it configmap-deployment-676f46ffd8-hlk2j -- /bin/sh
# cat cd /usr/share/nginx/html^C
# ls
hello
# cat hello
hello shanghai
3.3 利用ConfigMap传递变量需要注意的问题
3.3.1 向容器挂载文件会隐藏原文件夹下内容
通过ConfigMap把文件挂载到容器指定目录时,如果目录下有内容就会隐藏掉原来的内容。例如通过nginx镜像创建pod,并把一个hello.html文件挂载到/usr/share/nginx/html文件夹下,那么hello.html文件就会隐藏掉/usr/share/nginx/html目录下原来所有的文件。
首先利用hello.html创建一个ConfigMap
kubectl create configmap myconfig6 --from-file=hello=hello.html
然后创建pod的资源清单,指定把myconfig6中的hello.html挂载到容器/usr/share/nginx/html目录下
apiVersion: v1
kind: Pod
metadata:
name: nginx-configmap
spec:
containers:
- name: my-nginx
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- name: config-volume
mountPath: /usr/share/nginx/html
volumes:
- name: config-volume
configMap:
name: myconfig6
items:
- key: hello
path: hello.html
查看挂载后情况,发现/usr/share/nginx/html目录下只有hello.html文件,如下所示,原来所有文件已被隐藏。
[root@k8s-master01 pod_work]# kubectl apply -f pod6.yaml
pod/nginx-configmap created
[root@k8s-master01 pod_work]# kubectl exec -it nginx-configmap -- /bin/sh
# cd /usr/share/nginx/html
# ls
hello.html
如果向容器挂载文件且不想隐藏原目录下文件解决办法:
向容器挂载时指定挂载的具体文件名字,需要借助subPath标签,如下所示指定把hello.html文件挂载到/usr/share/nginx/html目录下的helloworld.html文件,这样/usr/share/nginx/html目录下原来的文件都还在。
apiVersion: v1
kind: Pod
metadata:
name: nginx-configmap
spec:
containers:
- name: my-nginx
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- name: config-volume
mountPath: /usr/share/nginx/html/helloworld.html #挂载到容器中的文件名
subPath: hello.html #myconfig6中需要挂载的文件
volumes:
- name: config-volume
configMap:
name: myconfig6
items:
- key: hello
path: hello.html
3.3.2 设置ConfigMap挂载到容器卷文件读写权限
把ConfigMap中文件挂载到容器目录时,可以通过标签defaultMode设置文件读写权,例如把文件设置成读写权限,如下所示
apiVersion: v1
kind: Pod
metadata:
name: nginx-configmap
spec:
containers:
- name: my-nginx
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- name: config-volume
mountPath: /usr/share/nginx/html/helloworld.html
subPath: hello.html
volumes:
- name: config-volume
configMap:
name: myconfig6
defaultMode: 0666 #设置myconfig6中所有挂载文件的默认权限
items:
- key: hello
path: hello.html
查看挂载后文件的权限,发现挂载到容器后的helloworld.html文件变成了读写权限
[root@k8s-master01 pod_work]# kubectl apply -f pod7.yaml
pod/nginx-configmap created
[root@k8s-master01 pod_work]# kubectl exec -it nginx-configmap -- /bin/sh
# cd /usr/share/nginx/html/
# ls -l
total 12
-rw-r--r--. 1 root root 494 May 26 15:00 50x.html
-rw-rw-rw-. 1 root root 12 Aug 16 08:48 helloworld.html
-rw-r--r--. 1 root root 612 May 26 15:00 index.html
3.3.3 pod中引用不存在的ConfigMap
如果在创建Pod时引用了不存在的ConfigMap,当创建Pod后,Pod会启动容器失败,如果之后创建了不存在的ConfigMap,失败的容器会自动启动,无需重新创建Pod。
参考k8s in action
更多推荐
所有评论(0)