ConfigMap

前面的资源对象并不能满足日常工作中的所有需求,一个最重要的需求就是应用的配置管理,特别是可变配置。

比如,在开发过程中程序需要配置 MySQL 或者 Redis 的连接地址。如果是以前的部署方式,此时想要修改这些信息,就需要修改代码的配置,然后重新打包部署。如果使用 ConfigMap,它能够向容器中注入配置信息,不仅可以是单个配置,也可以是整个配置文件。后面只需要修改 ConfigMap 的配置就能实现应用的配置更新。

ConfigMap 资源清单

ConfigMap 资源清单示例:

apiVersion: v1
kind: ConfigMap
metadata:
  name: cm-demo
data:
  serviceName: "demo-service"
  listenPort: "8080"
  config: |
    mysql.ip="192.168.2.1"
    mysql.port="3306"
    redis.ip="192.168.2.2"
    redis.port="6379"

在这个配置清单中,前两项是单个属性配置,config 字段中的可以看成是一个配置文件,其中的 | 的作用在于,保留下面属性的换行符和每行相对于第一行的缩进,多余的缩进和行尾的空白都会被删除。

使用示例:

config: |
  第一行
    第二行
      第三行
  第四行

转换成 JSON 格式就是:

{"config": "第一行\n  第二行\n    第三行\n第四行"}

如果将 | 换成 >,表示折叠的意思,只有空白和才会被识别成换行,原来的换行符则会被识别成空格:

config: >
  第一行
  第二行
  第三行

  第五行

转换成 JSON 格式就是:

{"config": "第一行 第二行 第三行\n第五行"}

还可以使用竖线和加号或者减号进行配合使用,+ 表示保留文字块末尾的换行,- 表示删除字符串末尾的换行。

config: |
  "hello"
# Json 格式:{"config": "hello\n"}  
  
config: |-
  "hello"
# Json 格式:{"config": "hello"}  

config: |+
  "hello"
  
# Json 格式:{"config": "hello\n\n"}
# 有几个换行则加几个

创建 ConfigMap

创建 ConfigMap 的命令:

# 通过指定目录创建 ConfigMap
kubectl create configmap cm-demo --from-file=/path/dir
  
# 通过指定文件创建 ConfigMap,可以是多个文件
kubectl create configmap cm-demo --from-file=key1=/path/dir/file1.txt --from-file=key2=/path/dir/file2.txt

# 直接指定键值创建 ConfigMap
kubectl create configmap cm-demo --from-literal=key1=value1 --from-literal=key2=value2

准备一个目录 /cm/config/,下面准备两个文件 mysql.confredis.conf

# mysql.conf 内容
host="192.168.2.1"
port="3306"

# redis.conf 内容
host="192.168.2.2"
port="6379"

测试创建:

# 直接通过整个目录创建,默认的 Key 就是文件名
kubectl create configmap cm-demo1 --from-file=/cm/config

# 指定文件创建,可以指定对于的 Key
kubectl create configmap cm-demo2 --from-file=mysqlConfig=/cm/config/mysql.conf --from-file=redisConfig=/cm/config/redis.conf

# 指定 K/V 直接创建
kubectl create configmap cm-demo3 --from-literal=k1=v1 --from-literal=k2=v2

使用 ConfigMap(环境变量)

在 ConfigMap 创建成功之后,有以下方法在 Pod 中使用它:

  • 设置环境变量的值
  • 在容器中设置命令行参数
  • 在数据卷中挂载配置文件

使用环境变量示例:

apiVersion: v1
kind: Pod
metadata:
  name: pod-cm-demo1
spec:
  containers:
  - name: c-cm-demo1
    image: busybox:latest
    command: [/bin/sh, -c, "env"]
    # 将每个配置文件单独给一个环境变量
    env:
      - name: MYSQL_CONFIG
        valueFrom:
          configMapKeyRef:
            name: cm-demo1
            key: mysql.conf
      - name: REDIS_CONFIG
        valueFrom:
          configMapKeyRef:
            name: cm-demo1
            key: redis.conf
    # 直接导入整个 ConfigMap 到环境变量中
    envFrom:
      - configMapRef:
          name: cm-demo

通过查看创建 Pod 之后输出的日志,可以看到设置的环境变量为:

# cm-demo 的 mysql.conf Key
MYSQL_CONFIG=host="192.168.2.1"
port="3306"

# cm-demo 的 redis.conf Key
REDIS_CONFIG=host="192.168.2.2"
port="6379"

# cm-demo 的配置生成了三个环境变量
config=mysql.ip="192.168.2.1"
mysql.port="3306"
redis.ip="192.168.2.2"
redis.port="6379"

serviceName=demo-service
listenPort=8080

使用 ConfigMap(容器运行参数)

作为容器的运行参数示例:

apiVersion: v1
kind: Pod
metadata:
  name: pod-cm-demo2
spec:
  containers:
  - name: c-cm-demo2
    image: busybox:latest
    command: [/bin/sh, -c, "echo ${ENV_V1}-${ENV_V2}"]
    env:
      - name: ENV_V1
        valueFrom:
          configMapKeyRef:
            name: cm-demo3
            key: k1
      - name: ENV_V2
        valueFrom:
          configMapKeyRef:
            name: cm-demo3
            key: k2

使用 ConfigMap(数据卷挂载)

以数据卷的方式挂载到 Pod 中使用:

apiVersion: v1
kind: Pod
metadata:
  name: pod-cm-demo3
spec:
  volumes:
    - name: v-cm-demo
      configMap:
        name: cm-demo1
  containers:
  - name: c-cm-demo3
    image: busybox:latest
    command: [/bin/sh, -c, "ls -lh /opt/config/ && cat /opt/config/mysql.conf"]
    volumeMounts:
      - name: v-cm-demo
        mountPath: /opt/config/

此时 ConfigMap 中的 Key 就能够变成文件名,然后挂载到指定的目录下。而且当使用数据卷的方式挂载到 Pod 中,此时更新 ConfigMap,挂载的数据也是会跟着热更新的。

这意味着以配置文件名称作为 Key 名称,然后使用 volume 挂载的方式是最适合开发场景的。

只有通过 Kubernetes API 创建的 Pod 才能使用 ConfigMap,其他方式创建的(比如静态 Pod)不能使用,同时 ConfigMap 文件大小限制为 1MB(ETCD 的要求)。