ConfigMap配置文件存储
前面的课程中我们学习了Servie 的使用,Service是Kubernetes 系统中非常重要的一个核心概念,后面的课程中还会继续学习Service的一些使用方法的。这节课来学习另外一个非常重要的资源对象:ConfigMap ,在实际工作中许多应用经常会有从配置文件、命令行参数或者环境变量中读取一些配置信息,这些配置信息我们肯定不会直接写死到应用程序中去的,比如你一个应用连接一个redis服务,下一次想更换一个,还得重新去修改代码,重新制作一个镜像,这肯定是不可取的,而ConfigMap 就给我们提供了向容器中注入配置信息的能力,不仅可以用来保存单个属性,也可以用来保存整个配置文件,比如我们可以用来配置一个redis服务的访问地址,也可以用来保存整个redis 的配置文件。
创建
ConfigMap 资源对象使用key-value形式的键值对来配置数据,这些数据可以在Pod 里面使用,ConfigMap 可以比较方便的处理一些非敏感的数据,比如密码之类的还是需要使用Secrets来进行管理。下面举个例子说明下ConfigMap 的使用方法:
[root@k8s-master ~]# vim cm-demo.yaml
kind: ConfigMap
apiVersion: v1
metadata:
name: cm-demo
namespace: default
data:
data.1: hello #以键值对的方式进行存储
data.2: world #以键值对的方式进行存储
config: | #以文件的形式进行存储,可以在下方直接写配置文件的内容
property.1=value-1
property.2=value-2
property.3=value-3
可以使用kubectl create -f xx.yaml 来创建上面的ConfigMap 对象,也可以使用kubectl create configmap -h来查看关于创建ConfigMap 的帮助信息:
[root@k8s-master ~]# kubectl create -f cm-demo.yaml #创建configMap
configmap/cm-demo created
[root@k8s-master ~]# kubectl create configmap -h
#获取在命令行模式创建configMap的帮助信息
可以看到从一个给定的目录来创建一个ConfigMap 对象,比如我们有一个testcm 的目录,该目录下面包含一些配置文件,redis和mysql的连接信息,如下
[root@k8s-master ~]# mkdir testcm
[root@k8s-master ~]# cat > testcm/redis.conf <<EOF
> host=127.0.0.1
> port=6379
> EOF
[root@k8s-master ~]# cat >testcm/mysql.conf <<EOF
> host=127.0.0.1
> port=3306
> EOF
[root@k8s-master ~]# ll testcm
总用量 8
-rw-r--r-- 1 root root 25 3月 4 12:04 mysql.conf
-rw-r--r-- 1 root root 25 3月 4 12:04 redis.conf
我们可以使用from-file关键字来创建包含这个目录下面所以配置文件的ConfigMap :
[root@k8s-master ~]# kubectl create configmap cm-demo1 --from-file=testcm
configmap/cm-demo1 created
#创建--from-file=指定的目录下的所有文件
[root@k8s-master ~]# kubectl get configmap | grep cm-demo1
cm-demo1 2 35s
可以看到已经创建了一个cm-demo1的ConfigMap 对象,然后可以使用describe命令查看详细信息:
[root@k8s-master ~]# kubectl describe configmap cm-demo1
Name: cm-demo1
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
mysql.conf: #testcm目录下的第一个文件
----
host=127.0.0.1 #testcm/mysql.conf文件中的内容
port=3306 #testcm/mysql.conf文件中的内容
redis.conf: #testcm目录下的第二个文件
----
host=127.0.0.1 #testcm/redis.conf文件中的内容
port=6379
Events: <none>
可以看到两个key 是testcm 目录下面的文件名称,对应的value值的话就是文件内容,这里值得注意的是如果文件里面的配置信息很大的话,describe的时候可能不会显示对应的值,要查看键值的话,可以使用如下命令:
[root@k8s-master ~]# kubectl get configmap cm-demo1 -o yaml
#查看一个configMap并以yaml的格式输出显示结果
apiVersion: v1
data:
mysql.conf: |
host=127.0.0.1
port=3306
redis.conf: |
host=127.0.0.1
port=6379
kind: ConfigMap
metadata:
creationTimestamp: "2021-03-04T04:07:41Z"
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:data:
.: {}
f:mysql.conf: {}
f:redis.conf: {}
manager: kubectl
operation: Update
time: "2021-03-04T04:07:41Z"
name: cm-demo1
namespace: default
resourceVersion: "39972"
selfLink: /api/v1/namespaces/default/configmaps/cm-demo1
uid: 7aebd648-2781-42c9-afdd-e34e0bb97eea
除了通过文件目录进行创建,也可以使用指定的文件进行创建ConfigMap ,同样的,以上面的配置文件为例,我们创建一个redis 的配置的一个单独ConfigMap 对象:
[root@k8s-master ~]# kubectl create configmap cm-demo2 --from-file=testcm/redis.con
configmap/cm-demo2 created
#在命令行创建一个名为cm-demo2的configMap,并指定配置文件为testcm/redis.con
[root@k8s-master ~]# kubectl describe configmaps cm-demo2
#查看详细信息
Name: cm-demo2
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
redis.conf: #因为指定单个配置文件,创建的configMap中也只有单个文件
----
host=127.0.0.1
port=6379
Events: <none>
可以看到一个关联redis.conf 文件配置信息的ConfigMap 对象创建成功了,另外值得注意的是–from-file这个参数可以使用多次,比如我们这里使用两次分别指定redis.conf 和mysql.conf 文件,就和直接指定整个目录是一样的效果了。如果有三个文件效果就不同了,未指定的文件就不会创建对应的configMap文件,但是指定目录还是会创建的
另外,通过帮助文档可以看到还可以直接使用字符串进行创建,通过-- from-literal参数传递配置信息,同样的,这个参数可以使用多次,格式如下:
[root@k8s-master ~]# kubectl create configmap cm-demo3 --from-literal=db.host=localhost --from-literal=db.port=3306
#创建一个configmap,文件中包含两个键值对,db.host=localhost db.port=3306
configmap/cm-demo3 created
#进行查看
[root@k8s-master ~]# kubectl get configmap cm-demo3 -o yaml
apiVersion: v1
data:
db.host: localhost #刚刚写入的文件
db.port: "3306" #刚刚写入的文件
kind: ConfigMap
metadata:
creationTimestamp: "2021-03-05T00:41:07Z"
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:data:
.: {}
f:db.host: {}
f:db.port: {}
manager: kubectl
operation: Update
time: "2021-03-05T00:41:07Z"
name: cm-demo3
namespace: default
resourceVersion: "43906"
selfLink: /api/v1/namespaces/default/configmaps/cm-demo3
uid: 40bdd418-6c3a-40c7-87af-e575ac3b5816
configMap的使用场景
ConfigMap 的配置数据可以通过很多种方式在Pod 里使用,主要有以下几种方式:
- 设置环境变量的值
- 在容器里设置命令行参数
- 在数据卷里面创建config文件,更新配置文件会热更新到容器中,但是服务不会重载,可以结合**inotify(监控文件的变化)**实现更新配置文件进行重载的脚本
首先,使用ConfigMap 来填充我们的环境变量:
[root@k8s-master ~]# vim testcm1-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: testcm1-pod
spec:
containers:
- name: testcm1
image: busybox
command: [ "/bin/sh", "-c", "env" ]
env:
- name: DB_HOST
valueFrom: #值从挂载卷中获取
configMapKeyRef: #从configMap中获取
name: cm-demo3 #从名称为cm-demo3的configMap中查找
key: db.host #查找db.host的值绑定给DB_HOST
- name: DB_PORT
valueFrom:
configMapKeyRef:
name: cm-demo3
key: db.port
envFrom:
- configMapRef:
name: cm-demo1 #直接将configMap配置文件挂载进去
创建并查看日志
[root@k8s-master ~]# kubectl create -f testcm1-pod.yaml
pod/testcm1-pod created
[root@k8s-master ~]# kubectl logs testcm1-pod | grep DB
DB_PORT=3306
DB_HOST=localhost
#可以查看到在configMap中获取的值
可以看到DB_HOST和DB_PORT都已经正常输出了,另外的环境变量是因为我们这里直接把cm-demo1给注入进来了,所以把他们的整个键值给输出出来了,这是符合预期的。
另外可以使用ConfigMap 来设置命令行参数,ConfigMap 也可以被用来设置容器中的命令或者参数值,如下Pod :
[root@k8s-master ~]# vim testcm2-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: testcm2-pod
spec:
containers:
- name: testcm2
image: busybox
command: [ "/bin/sh", "-c", "echo $(DB_HOST) $(DB_PORT)" ]
env:
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: cm-demo3
key: db.host
- name: DB_PORT
valueFrom:
configMapKeyRef:
name: cm-demo3
key: db.port
创建并运行
[root@k8s-master ~]# kubectl create -f testcm2-pod.yaml
pod/testcm2-pod created
[root@k8s-master ~]# kubectl logs testcm2-pod testcm2
localhost 3306
#先打印的DB_HOST的值,后打印的DB_PORT的值,没有做换行
另外一种是非常常见的使用ConfigMap 的方式:通过数据卷使用,在数据卷里面使用ConfigMap ,就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容:
通过数据卷把配置文件挂载到指定路径
[root@k8s-master ~]# vim testcm3-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: testcm3-pod
spec:
containers:
- name: testcm3
image: busybox
command: [ "/bin/sh", "-c", "cat /etc/config/redis.conf" ] #显示挂载的文件
volumeMounts: #卷挂载
- name: config-volume #挂载的名称
mountPath: /etc/config #挂载到容器中对的位置
volumes: #创建卷
- name: config-volume #创建的卷名称
configMap: #从configMap中挂载
name: cm-demo2 #挂载configMap中的cm-demo2
创建并运行查看日志
[root@k8s-master ~]# kubectl create -f testcm3-pod.yaml
pod/testcm3-pod created
[root@k8s-master ~]# kubectl logs testcm3-pod
host=127.0.0.1
port=6379
#此时已经查看到从configMap中cm-demo2的配置文件
当然也可以在ConfigMap 值被映射的数据卷里去控制路径,如下Pod 定义:
[root@k8s-master ~]# vim testcm4-pod.yaml
[root@k8s-master ~]# cat testcm4-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: testcm4-pod
spec:
containers:
- name: testcm4
image: busybox
command: [ "/bin/sh","-c","cat /etc/config/path/to/msyql.conf" ]
volumeMounts: #挂载卷
- name: config-volume #挂载的卷名称
mountPath: /etc/config #挂载到容器中的路径
volumes: #创建卷
- name: config-volume #创建的卷名称
configMap: #从configMap中获取
name: cm-demo1 #configMap中的卷名称
items: #项目
- key: mysql.conf #从configMap中的cm-demo1键 mysql.conf
path: path/to/msyql.conf #绑定给这个路径
因为有items的存在,mountPath:所挂载的/etc/config会加上items
绑定的路径也就是说挂载的是后完整路径是这样的**/etc/config/path/to/msyql.conf**
运行这个Pod 的,查看日志:
[root@k8s-master ~]# kubectl create -f testcm4-pod.yaml
pod/testcm4-pod created
[root@k8s-master ~]# kubectl logs testcm4-pod
host=127.0.0.1
port=3306
#文件中cat的文件路径是/etc/config/path/to/msyql.conf说明items绑定的路径生效了
另外需要注意的是,当ConfigMap 以数据卷的形式挂载进Pod 的时,这时更新ConfigMap (或删掉重建 ConfigMap ),Pod 内挂载的配置信息会热更新。这时可以增加一些监测配置文件变更的脚本,然后reload对应服务,可以使用inotify(监控文件的变化)如果有变化就重载对应容器中的服务
通过kubectl命令行的方式创建configMap
在kubectl create configmap命令种使用参数–from-file或–from-literal指定文件、目录或者文本,也可以创建一个或者多个ConfigMap参数。
(1)指定文件:
[root@k8s-master config]# pwd
/root/config
[root@k8s-master config]# echo "user nginx;
> worker_processes auto;
>
> error_log /var/log/nginx/error.log notice;
> pid /var/run/nginx.pid;
> " > nginx.test.conf
#模拟创建一个配置文件
[root@k8s-master config]# cat nginx.test.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
#以此配置文件创建configmap
kubectl create configmap nginx.test.conf --from-file
=nginx.test.conf
[root@k8s-master config]# kubectl get configmaps
NAME DATA AGE
nginx.test.conf 1 48s
#通过查看已经创建成功
[root@k8s-master config]# kubectl get configmaps nginx.test.conf -o yaml
apiVersion: v1
data:
nginx.test.conf: |+
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
kind: ConfigMap
metadata:
creationTimestamp: "2021-08-08T11:28:27Z"
name: nginx.test.conf
namespace: default
resourceVersion: "1415867"
selfLink: /api/v1/namespaces/default/configmaps/nginx.test.conf
uid: bfe617ed-c841-4bae-9daf-c53ba2a59f4a
(2)指定目录:
需要注意,目录中的每个配置文件名都被会被设置为key,文件中的内容将被设置为value,语法为:
[root@k8s-master config]# pwd
/root/config
[root@k8s-master config]# ls
default.conf nginx.conf
#查看到两个配置文件,通过指定目录创建这两个配置文件
[root@k8s-master config]# kubectl create configmap nginx.conf --from-file=/root/config/
configmap/nginx.conf created
[root@k8s-master config]# kubectl get configmaps
NAME DATA AGE
nginx.conf 2 30s
#此时两个configmap就可以使用了
使用configmap创建nginx配置文件
[root@k8s-master ~]# cd config/
[root@k8s-master config]# ls
conf.d fastcgi_params koi-utf koi-win mime.types nginx.conf scgi_params uwsgi_params win-utf
[root@k8s-master config]# cd conf.d/
[root@k8s-master conf.d]# ls
default.conf example_ssl.conf
#创建configMap
kubectl create configmap nginx --from-file=/root/config/
kubectl create configmap confd --from-file=/root/config/conf.d/
[root@k8s-master conf.d]# kubectl get configmaps
NAME DATA AGE
confd 2 13h
nginx 8 13h
将configMap挂载到容器内
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
labels:
k8s-app: nginx-demo
name: nginx-deploy
namespace: default
spec:
minReadySeconds: 5
progressDeadlineSeconds: 600
replicas: 10
revisionHistoryLimit: 10
selector:
matchLabels:
app: nginx
strategy:
rollingUpdate:
maxSurge: 3
maxUnavailable: 2
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx:1.7.9
imagePullPolicy: IfNotPresent # Always // Never
name: nginx
ports:
- containerPort: 80
protocol: TCP
volumeMounts:
- mountPath: /usr/share/nginx/html/
name: index
# - mountPath: /etc/nginx/
# name: config
- mountPath: /etc/nginx/
name: config
- mountPath: /etc/nginx/conf.d #挂载位置
name: confd #调用卷名称
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
terminationGracePeriodSeconds: 30
volumes:
- hostPath:
path: /root/nginx
name: index
- name: config
configMap:
name: nginx #使用的configMap名称
- name: confd #卷名称
configMap: #卷类型
name: confd #使用的configMap名称
前往容器中,进行验证
[root@k8s-master nginx]# kubectl exec nginx-deploy-c477c784d-bkn5f -it /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
# cat /etc/nginx/nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
#test222 #此处为标记信息
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
#
验证configMap热更新配置文件
[root@k8s-master nginx]# kubectl edit configmaps nginx
nginx.conf: |2
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
#test edit nginx.conf 更改内容
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
更改完毕后进入容器查看
[root@k8s-master nginx]# kubectl exec nginx-deploy-c477c784d-bkn5f -it /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
# cat /etc/nginx/nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
#test edit nginx.conf #此时配置文件已更新
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
#
如果使配置文件生效,只需要重载对应的服务即可