ljzsdut
GitHubToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

5.1 K8s配置中心之 Config Map

ConfigMap:k8s配置中心

一、概述

简称: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使用注意事项:

  • ConfigMap必须在Pod之前创建
  • 只有与当前ConfigMap在同一个namespace内的pod才能使用这个ConfigMap,换句话说,ConfigMap不能跨命名空间调用。

三、创建ConfigMap

1、命令行定义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为字符串而不是文本

2、配置清单定义ConfigMap:

注意: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

四、ConfigMap的使用

3.1、定义ConfigMap

[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>

3.2、在pod中使用ConfigMap(环境变量):

[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

3.3、在pod中使用ConfigMap(存储卷):

[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时,会在挂载点下再创建此路径。注意路径中不能包含"..",不能是绝对路经。 

3.4、示例:使用volumeMounts[].subPath

​ 一个普通的volume中可以有多个目录和文件,一个configMap类型的volume中也可以有多个文件,这个文件或目录可能在Pod的不同路径上使用,此时就需要一种机制将不同的目录和文件映射到Pod内不同的路径上。

​ volumeMounts.subPath特性可以用来指定只使用卷中的一个子目录,而不是直接使用卷的根目录(对volume使用subPath指定的子目录或文件挂载到mountPath上)。 但是注意的是:使subPath会使configmap的volume挂载方式的热更新作用失效。

volumeMounts.subPath 属性可用于指定所引用的卷内的子路径,而不是其根路径。

subPath与mountPath的关系:

subPathmountPathresult
文件文件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

五、补充

1、configmap行错乱,有"\n"

原因:行末有“\r\n”;行末有不可见的空格。

解决方法:

1、第一步:转换格式
dos2unix web.properties
2、删除行尾的空格以及DOS回车符。(使用vim)
:%s#\s*\r\?$##
3、处理\tw为4个空格
:%s/\t/    /g
sed -i 's/\t/    /g'