• K8S(六):Pod的配置管理——ConfigMap使用


    𝑰’𝒎 𝒉𝒉𝒈, 𝑰 𝒂𝒎 𝒂 𝒈𝒓𝒂𝒅𝒖𝒂𝒕𝒆 𝒔𝒕𝒖𝒅𝒆𝒏𝒕 𝒇𝒓𝒐𝒎 𝑵𝒂𝒏𝒋𝒊𝒏𝒈, 𝑪𝒉𝒊𝒏𝒂.

    • 🏫 𝑺𝒉𝒄𝒐𝒐𝒍: 𝑯𝒐𝒉𝒂𝒊 𝑼𝒏𝒊𝒗𝒆𝒓𝒔𝒊𝒕𝒚
    • 🌱 𝑳𝒆𝒂𝒓𝒏𝒊𝒏𝒈: 𝑰’𝒎 𝒄𝒖𝒓𝒓𝒆𝒏𝒕𝒍𝒚 𝒍𝒆𝒂𝒓𝒏𝒊𝒏𝒈 𝒅𝒆𝒔𝒊𝒈𝒏 𝒑𝒂𝒕𝒕𝒆𝒓𝒏, 𝑳𝒆𝒆𝒕𝒄𝒐𝒅𝒆, 𝒅𝒊𝒔𝒕𝒓𝒊𝒃𝒖𝒕𝒆𝒅 𝒔𝒚𝒔𝒕𝒆𝒎, 𝒎𝒊𝒅𝒅𝒍𝒆𝒘𝒂𝒓𝒆 𝒂𝒏𝒅 𝒔𝒐 𝒐𝒏.
    • 💓 𝑯𝒐𝒘 𝒕𝒐 𝒓𝒆𝒂𝒄𝒉 𝒎𝒆:𝑽𝑿
    • 📚 𝑴𝒚 𝒃𝒍𝒐𝒈: 𝒉𝒕𝒕𝒑𝒔://𝒉𝒉𝒈𝒚𝒚𝒅𝒔.𝒃𝒍𝒐𝒈.𝒄𝒔𝒅𝒏.𝒏𝒆𝒕/
    • 💼 𝑷𝒓𝒐𝒇𝒆𝒔𝒔𝒊𝒐𝒏𝒂𝒍 𝒔𝒌𝒊𝒍𝒍𝒔:𝒎𝒚 𝒅𝒓𝒆𝒂𝒎

    1 configMap作用,为什么需要它

      应用部署的一个最佳实践是将应用所需的配置信息与程序进行分离,这样可以使应用程序被更好地复用,通过不同的配置也能实现更灵活的功能。将应用打包为容器镜像后,可以通过环境变量或者外挂文件的方式在创建容器时进行配置注入,但在大规模容器集群的环境中,对多个容器进行不同的配置将变得非常复杂。从Kubernetes 1.2开始提供了一种统一的应用配置管理方案—ConfigMap。

      应用程序的运行可能会依赖一些配置,而这些配置又是可能会随着需求产生变化的,如果我们的应用程序架构不是应用和配置分离的,那么就会存在当我们需要去修改某些配置项的属性时需要重新构建镜像文件的窘境。现在,ConfigMap组件可以很好的帮助我们实现应用和配置分离,避免因为修改配置项而重新构建镜像。

      ConfigMap 用于保存配置数据的键值对,可以用来保存单个属性,也可以用来保存配置文件。ConfigMap 跟 Secret 很类似,但它可以更方便地处理不包含敏感信息的字符串。

    1.1 ConfigMap供容器使用的典型用法。

    1. 生成为容器内的环境变量。
    2. 设置容器启动命令的启动参数(需设置为环境变量)。
    3. 以Volume的形式挂载为容器内部的文件或目录。

    ConfigMap以一个或多个key:value的形式保存在Kubernetes系统中供应用使用,既可以用于表示一个变量的值(例如apploglevel=info),也可以用于表示一个完整配置文件的内容(例如server.xml=…)
    可以通过YAML配置文件或者直接使用kubectl create configmap命令行的方式来创建ConfigMap。

    2 创建configMap资源

    就像java一样,要用某个对象你得先new一个,要先创建了这个configMap资源别人才能用呀。

    2.1 通过yaml文件创建

    2.1.1 key: value (value是变量值)

    • cm-appvars.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: cm-appvars
    data:                    # 定义了两个key: value形式的配置
      apploglevel: info
      appdatadir: /var/data
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    创建命令:

    [root@k8s-master Chapter3]# kubectl apply -f cm-appvars.yaml 
    configmap/cm-appvars created
    
    • 1
    • 2

    查看configMap

    [root@k8s-master Chapter3]# kubectl describe configmap cm-appvars
    Name:         cm-appvars
    Namespace:    default
    Labels:       
    Annotations:  
    
    Data
    ====
    apploglevel:
    ----
    info
    appdatadir:
    ----
    /var/data
    
    BinaryData
    ====
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.1.2 key:value (value是一个完整的文件)

    创建 Kubernetes 的 ConfigMap 资源,用于存储 Mysql 的配置文件 my.cnf 内容:

    • mysql-config.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: mysql-config
      labels:
        app: mysql
    data:
      my.cnf: |-
        [client]
        default-character-set=utf8mb4
        [mysql]
        default-character-set=utf8mb4
        default-time_zone = '+8:00'
        [mysqld] 
        max_connections = 2000
        secure_file_priv=/var/lib/mysql
        sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    这里就是一个完整的my.conf: ${value} value是一个完整的配置文件。

    2.2 通过kubectl 手动创建

    不使用YAML文件,直接通过kubectl create configmap也可以创建ConfigMap,可以使用参数–from-file或–from-literal指定内容,并且可以在一行命令中指定多个参数。

    这种方式应该用的少,我看到的一般都是用yaml,所以这里只是记录可以这么干。真要这么用,再查吧。

    $ ls docs/user-guide/configmap/kubectl/
    game.properties
    ui.properties
    
    $ cat docs/user-guide/configmap/kubectl/game.properties
    enemies=aliens
    lives=3
    enemies.cheat=true
    enemies.cheat.level=noGoodRotten
    secret.code.passphrase=UUDDLRLRBABAS
    secret.code.allowed=true
    secret.code.lives=30
    
    $ cat docs/user-guide/configmap/kubectl/ui.properties
    color.good=purple
    color.bad=yellow
    allow.textmode=true
    how.nice.to.look=fairlyNice
    
    应用:
    kubectl create configmap game-config --from-file=docs/user-guide/configmap/kubectl
    
    —from-file指定在目录下的所有文件都会被用在ConfigMap里面创建一个键值对,键的名字就是文件名,值就是文件的内容。
    
    $ kubectl describe configmaps game-config
    Name:           game-config
    Namespace:      default
    Labels:         <none>
    Annotations:    <none>
    
    Data
    ====
    game.properties:        158 bytes
    ui.properties:          83 bytes
    
    我们以yaml格式输出配置。
    kubectl get configmaps game-config -o yaml
    
    ----output----
    apiVersion: v1
    data:
      game.properties: |
        enemies=aliens
        lives=3
        enemies.cheat=true
        enemies.cheat.level=noGoodRotten
        secret.code.passphrase=UUDDLRLRBABAS
        secret.code.allowed=true
        secret.code.lives=30
      ui.properties: |
        color.good=purple
        color.bad=yellow
        allow.textmode=true
        how.nice.to.look=fairlyNice
    kind: ConfigMap
    metadata:
      creationTimestamp: 2016-02-18T18:34:05Z
      name: game-config
      namespace: default
      resourceVersion: "407"
      selfLink: /api/v1/namespaces/default/configmaps/game-config
      uid: 30944725-d66e-11e5-8cd0-68f728db1985
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    这个案例没有自己尝试,都是其他人的。

    3 在Pod中使用ConfigMap

    3.1 用作环境变量

      在Pod“cm-test-pod”的定义中,将ConfigMap“cm-appvars”中的内容以环境变量(APPLOGLEVEL和APPDATADIR)方式设置为容器内部的环境变量,容器的启动命令将显示这两个环境变量的值(“env | grep APP”):

    • cm-test-pod-use-envvar.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: cm-test-pod
    spec:
      containers:
      - name: cm-test
        image: busybox
        command: [ "/bin/sh", "-c", "env | grep APP" ]
        env:
        - name: APPLOGLEVEL
          valueFrom:
            configMapKeyRef:
              name: cm-appvars
              key: apploglevel
        - name: APPDATADIR                                # 环境变量的名称APPDATADIR
          valueFrom:                                      # 值来源于
            configMapKeyRef:                              # 引用configMap里面的值
              name: cm-appvars                            # configMap的名称
              key: appdatadir                             # configMap中的key
      restartPolicy: Never                                # Pod重启策略
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    kubectl apply -f cm-test-pod-use-envvar.yaml
    
    • 1

    验证:

    [root@k8s-master Chapter3]# kubectl logs cm-test-pod
    APPDATADIR=/var/data
    APPLOGLEVEL=info
    
    • 1
    • 2
    • 3

    或者如果说,你需要configMap所有的环境变量的话,可以这么写:

    apiVersion: v1
    kind: Pod
    metadata:
      name: cm-test-pod
    spec:
      containers:
      - name: cm-test
        image: busybox
        command: [ "/bin/sh", "-c", "env" ]
        envFrom:
        - configMapRef:
           name: cm-appvars
      restartPolicy: Never
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    那么环境变量的名称就是configMap里面的key,环境变量的值就是configMap里面的value。

    • Tips:
      需要说明的是,环境变量的名称受POSIX命名规范([a-zA-Z_][a-zA-Z0-9_]*)约束,不能以数字开头。如果包含非法字符,则系统将跳过该条环境变量的创建,并记录一个Event来提示环境变量无法生成,但并不阻止Pod的启动。

    3.2 通过volumeMount使用ConfigMap

    这个就比较有用了,为什么呢?例如一个mysql服务,你的配置文件不可能在容器里面改来改去,一定是要有一个地方专门去存储的。configMap就可以做到,因为,它可以将configMap里面的内容直接映射到container容器指定的一个目录下面去。

    3.2.1 configMap定义

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: cm-appconfigfiles
    data:
      key-serverxml: |
        
        
          
          
          
          
          
          
            
          
    
          >
            >
            >
            >
              >
                >
              >
              >
                "%r" %s %b" />
    
              >
            >
          >
        >
      key-loggingproperties: "handlers
        = 1catalina.org.apache.juli.FileHandler, 2localhost.org.apache.juli.FileHandler,
        3manager.org.apache.juli.FileHandler, 4host-manager.org.apache.juli.FileHandler,
        java.util.logging.ConsoleHandler\r\n\r\n.handlers = 1catalina.org.apache.juli.FileHandler,
        java.util.logging.ConsoleHandler\r\n\r\n1catalina.org.apache.juli.FileHandler.level
        = FINE\r\n1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs\r\n1catalina.org.apache.juli.FileHandler.prefix
        = catalina.\r\n\r\n2localhost.org.apache.juli.FileHandler.level = FINE\r\n2localhost.org.apache.juli.FileHandler.directory
        = ${catalina.base}/logs\r\n2localhost.org.apache.juli.FileHandler.prefix = localhost.\r\n\r\n3manager.org.apache.juli.FileHandler.level
        = FINE\r\n3manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs\r\n3manager.org.apache.juli.FileHandler.prefix
        = manager.\r\n\r\n4host-manager.org.apache.juli.FileHandler.level = FINE\r\n4host-manager.org.apache.juli.FileHandler.directory
        = ${catalina.base}/logs\r\n4host-manager.org.apache.juli.FileHandler.prefix =
        host-manager.\r\n\r\njava.util.logging.ConsoleHandler.level = FINE\r\njava.util.logging.ConsoleHandler.formatter
        = java.util.logging.SimpleFormatter\r\n\r\n\r\norg.apache.catalina.core.ContainerBase.[Catalina].[localhost].level
        = INFO\r\norg.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers
        = 2localhost.org.apache.juli.FileHandler\r\n\r\norg.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level
        = INFO\r\norg.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers
        = 3manager.org.apache.juli.FileHandler\r\n\r\norg.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level
        = INFO\r\norg.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers
        = 4host-manager.org.apache.juli.FileHandler\r\n\r\n"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    其中configMap中分别定义了两个key,一个是key-serverxml,另一个是key-loggingproperties。这两个key的value都是一个文件。所以我们需要通过volumeMount,对这两个进行相应的挂载。

    3.2.2 通过items,设置挂载的文件名

    • cm-test-app.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: cm-test-app
    spec:
      containers:
      - name: cm-test-app
        image: kubeguide/tomcat-app:v1
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: serverxml
          mountPath: /configfiles        # 将name=serverxml的volume,改在到/configfiles这个目录之下
      volumes:
      - name: serverxml
        configMap:
          name: cm-appconfigfiles
          items:
          - key: key-serverxml           #key就是configMap的key
            path: server.xml             #将value里面的内容形成server.xml文件<==>/configfiles/server.xml
          - key: key-loggingproperties
            path: logging.properties
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    3.2.3 不指定items的默认情况

      如果在引用ConfigMap时不指定items,则使用volumeMount方式在容器内的目录下为每个item都生成一个文件名为key的文件。
    在这里插入图片描述
      登录容器,查看到在/configfiles目录下存在key-loggingproperties和key-serverxml文件,文件的名称来自在ConfigMap cm-appconfigfiles中定义的两个key的名称,文件的内容则为value的内容:

    那么也就是说,如果你不指定的话,key最好就写成文件名就好了,这样也省的麻烦

    3.2.4 关于configMap 挂载时候的文件覆盖问题

      在一般情况下 通过configmap 挂载文件时,会先覆盖掉挂载目录也就是这里/configfiles原来的内容会被覆盖,然后再将 congfigmap 中的内容作为文件挂载进行。如果想不对原来的文件夹下的文件造成覆盖,只是将 configmap 中的每个 key,按照文件的方式挂载到目录下,可以使用 subpath 参数。比如这样:

    apiVersion: v1 
    kind: Pod 
    metadata:
      name: dapi-test-pod 
    spec:
      containers:
        - name: test-container 
          image: hub.coreqi.cn/library/myapp:v1 
          command: [ "/bin/sh", "-c", "cat /etc/config/special.how" ]
          # 把config-volume下的key1的值。完整地赋值给appsettings.Production.json
          volumeMounts:
          - name: config-volume 
            mountPath: /app/appsettings.Production.json
            subPath: key1
      # 导入“special-config”的configmap,并命名为config-volume
      volumes:
        - name: config-volume
          configMap:
            name: special-config
      restartPolicy: Never
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    4 ConfigMap的热更新问题

    1. 热更新只有对volume挂载文件的使用方式有效(Pod 同步间隔(默认10秒) + ConfigMap 本地缓存的 TTL)
    2. 对该ConfigMap挂载的Env不会同步更新
    3. 对subPath热更新是无效的,可以通过其他方式强制更新,搜一下就知道了,比如这里通过更改annotation的方法,但是这种方法是否是最恰当的,现在还未知。
    kubectl patch deployment mysql --patch '{"spec": {"template": {"metadata": {"annotations": {"update": "2" }}}}}'
    
    • 1

    参考文献

  • 相关阅读:
    Python线程
    linux 强大的搜索命令 grep
    2022年BAT最新java800+合集面试复盘,能掌握80%就去进阿里大厂!
    yolov5+车辆重识别【附代码】
    Springboot毕业设计毕设作品,农产品销售系统设计与实现
    C语言运算符优先级一览表
    maven 打包 deploy 项目时 出现 401 Unauthorized
    标题组合-标题组合软件-免费标题生成组合软件
    Redis_AOF
    解释一下Kubernetes Minikube是什么,以及如何在本地运行一个Minikube集群
  • 原文地址:https://blog.csdn.net/qq_41376740/article/details/126287412