5.1 K8s配置中心之 Config Map
简称:cm
ConfigMap是k8s的标准资源对象,其扮演着k8s配置中心的角色,支持配置文件的动态修改。在ConfigMap中所有信息都保存为key-value模式,value既可以是一个简单的字符串,也可以是一个文本文件。
ConfigMap将配置注入到容器中有两种方式,无论value是一个简单字符串还是一个文本文件,ConfigMap都可以使用如下两种方式注入到容器中:
- 通过Pod.containers[].env的valueFrom方式去引用在ConfigMap中保存的数据;该方式在修改ConfigMap后,Pod中的数据不会实时修改,只会在第一次创建(重启)Pod时修改。
- 直接将ConfigMap作为一个存储卷,挂载到某个目录下:以key为文件名,以value为文件内容;此方法在修改ConfigMap时,Pod中的文件自动生效(需要一段时间,大约10s,**热更新 **)。这种方式configmap内容应该会每隔一段时间刷新到pod中(未验证),所以pod起来后再通过
kubectl edit configmap …修改configmap,过一会pod内部的配置也会刷新。
- ConfigMap必须在Pod之前创建
- 只有与当前ConfigMap在同一个namespace内的pod才能使用这个ConfigMap,换句话说,ConfigMap不能跨命名空间调用。
语法:kubectl create configmap NAME [–from-file=[key=]source] [–from-literal=key1=value1]
# Create a new configmap named my-config based on folder bar
#基于bar目录创建一个名称为my-config的configmap对象
kubectl create configmap my-config --from-file=path/to/bar #path/to/bar为目录,如果目录下有多个文件,会创建多个key-value,每个文件创建为一个key-value,其中key为每个文件的文件名,value为其对应的文本内容。
# Create a new configmap named my-config with specified keys instead of file basenames on disk
kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt #指定key的值,value为文本。--from-file可以使用多次
# Create a new configmap named my-config from the key=value pairs in the file
kubectl create configmap my-config --from-file=path/to/bar #bar为文件,因为未显示指定key值,默认将文件名作为key,文件内容作为value
# Create a new configmap named my-config from an env file
kubectl create configmap my-config --from-env-file=path/to/bar.env
# Create a new configmap named my-config with key1=config1 and key2=config2
kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2 #--from-litera表示value为字符串而不是文本
注意:ConfigMap的定义中没有spec,而是使用data字段(或者binaryData)
[root@k8smaster configmap]# cat nginx-congfig-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
namespace: default
data: #如果是二进制字节数据,使用binaryData定义。
nginx_port: "80"
server_name: ljzsdut.linuxabc.com
my.cnf: | #“|”表示文件内容开始,yaml语法中“key:”后面使用竖线,表示换行,这样可以像shell脚本一样写很多行语句。
[mysqld]
log-bin = mysql-bin
app.properties: |
property.1 = value-1
property.2 = value-2
property.3 = value-3
[root@k8smaster configmap]# kubectl create configmap nginx-config --from-literal=nginx_port=80 --from-literal=server_name=ljzsdut.linuxabc.com
configmap/nginx-config created
[root@k8smaster configmap]# kubectl get cm nginx-config
NAME DATA AGE
nginx-config 2 17s
[root@k8smaster configmap]# kubectl describe cm nginx-config
Name: nginx-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
nginx_port:
----
80
server_name:
----
ljzsdut.linuxabc.com
Events: <none>
[root@k8smaster configmap]# cat pod-cm.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-cm
namespace: default
labels:
app: myapp
tier: frontend
#labels: {app:myapp,tier:frontend}
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
env: #方式1(可以重新定义环境变量名称)
- name: NGINX_SERVER_PORT #变量名,注意:在docker中,定义的变量名使用中划线也会自动转换为下划线
valueFrom:
configMapKeyRef: #变量取值来源,类似参数:secretKeyRef、fieldRef、resourceFieldRef
name: nginx-config #引用哪个ConfigMap
key: nginx_port #引用ConfigMap中的哪个key
#envFrom: #方式2
# - configMapRef:
# name: nginx-config
[root@k8smaster configmap]# kubectl apply -f pod-cm.yaml
pod/pod-cm created
[root@k8smaster configmap]# cat pod-cm2.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-cm-2
namespace: default
labels:
app: myapp
tier: frontend
#labels: {app:myapp,tier:frontend}
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
volumeMounts:
- name: nginxconf #要挂载的volume名称
mountPath: /etc/nginx/conf.d
readOnly: true #不允许Pod改变该文件,但不会影响configmap对该文件的热更新
volumes:
- name: nginxconf
configMap: #使用ConfigMap作为存储卷
name: nginx-config
#items: #如果不指定items,会将ConfigMap中的每一个key-value映射到volume中;否则,只映射下面列出的key到指定路径。
#- key: nginx_port
# path: path/to/filename #相对路径,相对于挂载点(volumeMounts.mountPath),即挂载到Pod时,会在挂载点下再创建此路径。注意路径中不能包含"..",不能是绝对路经。
一个普通的volume中可以有多个目录和文件,一个configMap类型的volume中也可以有多个文件,这个文件或目录可能在Pod的不同路径上使用,此时就需要一种机制将不同的目录和文件映射到Pod内不同的路径上。
volumeMounts.subPath特性可以用来指定只使用卷中的一个子目录,而不是直接使用卷的根目录(对volume使用subPath指定的子目录或文件挂载到mountPath上)。 但是注意的是:使subPath会使configmap的volume挂载方式的热更新作用失效。
volumeMounts.subPath 属性可用于指定所引用的卷内的子路径,而不是其根路径。
subPath与mountPath的关系:
| subPath | mountPath | result |
|---|---|---|
| 文件 | 文件 | subPath文件内容覆盖mountPath文件内容 |
| 文件 | 目录 | ==========报错========== |
| 文件 | 不存在 | 容器中创建文件,subPath文件内容覆盖mountPath文件内容 |
| 目录 | 文件 | ==========报错========== |
| 目录 | 目录 | subPath目录内容覆盖mountPath目录内容 |
| 目录 | 不存在 | 容器中创建目录,subPath目录内容覆盖mountPath目录内容 |
| 不存在 | 文件 | ==========报错========== |
| 不存在 | 目录 | 新建目录,覆盖目录 |
| 不存在 | 不存在 | 新建目录,覆盖目录 |
总结:
- subPath是configmap卷或存储卷内的文件或目录(src file),moutPath是容器内的文件或目录(dest file)。挂载时,subPath指定的值会挂载为mountPath指定的值。
- subPath的内容会覆盖mountPath的内容,注意是内容,不是文件名。目录的内容是其子文件和子目录。
- 如果subPath指定的值在volume中不存在,则会按照该值自动创建为目录。
- 如果mountPath值的值在容器中不存在,则会在容器中创建(文件或目录,取决于subPath是文件还是目录),然后将subPath挂载至mountPath上。
- 如果subPath和mountPath的值指定的文件或目录都存在,则二者要么都是文件,要么都是目录。否则会报错。
[root@physerver manifests]# ls config/
web.properties dbcp.properties
[root@physerver manifests]# kubectl create configmap cc-main-config --from-file=/root/manifests/config/
configmap/cc-main-config created
apiVersion: apps/v1
kind: Deployment
metadata:
name: main-deployment
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: main-app
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
template:
metadata:
name: main-pod
labels:
app: main-app
spec:
containers:
- name: cc-main
image: 192.168.5.110:5000/cc_main:8.6.1.2078
imagePullPolicy: IfNotPresent
command:
- "/bin/bash"
- "-c"
- "sleep 3600"
env:
- name: JAVA_OPTS
value: "-server -XX:PermSize=512M -XX:MaxPermSize=512M -Xms4196m -Xmx4196m"
ports:
- name: http
containerPort: 8080
volumeMounts:
- name: cc-main-config
mountPath: /u01/application/WEB-INF/classes/web.properties
subPath: web.properties #表示使用volume中的子文件或子目录(configmap类型的volume不存在子目录,只有子文件)映射到mountPath路径上,如果缺省,默认将整个volume根目录都映射到mountPath,
#如果mountPath是容器内事先存在文件(或目录),会将原先存在的文件覆盖,所以subPath的一个附加作用就是避免覆盖mountPath指定的的原先存在的文件或目录。 至于覆盖为文件还是目录,取决于subPath是文件还是目录。
#如果subPath是configmap卷或存储卷内一个事先存在的文件,那么mountPath不能是一个已经存在的目录,可以是一个已经存在或者不存在的文件。此外subPath会使容器内的文件的热更新作用失效。
#如果subPath指定的值在volume中不存在,则会自动会在volume中创建为目录。
readOnly: true #不允许Pod改变该文件
- name: dbcp-properties
mountPath: /u01/application/WEB-INF/classes/dbcp.properties
subPath: dbcp.properties
readOnly: true
volumes:
- name: cc-main-config
configMap: #使用ConfigMap作为存储卷
name: cc-main-config
原因:行末有“\r\n”;行末有不可见的空格。
解决方法:
1、第一步:转换格式
dos2unix web.properties
2、删除行尾的空格以及DOS回车符。(使用vim)
:%s#\s*\r\?$##
3、处理\tw为4个空格
:%s/\t/ /g
sed -i 's/\t/ /g'