configMap

许多应用程序会从命令行参数、配置文件或环境变联众读取配置信息。configMap API个我们提供了向容器中注入配置信息的机制,configMap可以用来保存单个属性,也可以用来保存整个配置文件或者JSON二进制大对象。

它的主要目的是解决一下问题:

  1. 代码与配置分离:ConfigMap允许将应用的配置信息从容器镜像中分离出来,这样可以更轻松地管理配置,而不必重新构建和部署容器镜像。
  2. 统一的集群配置管理:ConfigMap提供了一个统一的机制,用于在K8s集群中存储、管理和传递配置信息。这使得配置数据可以在多个Pod、容器或服务之间共享和重用。
  3. 提高可移植性:通过将配置信息与容器镜像分离,ConfigMap使得容器镜像更加通用和可移植。同一个容器镜像可以在不同的环境中使用,只需通过ConfigMap提供不同的配置即可。
  4. 简化配置管理:ConfigMap支持以key-value对的形式存储配置数据,可以方便地通过kubectl命令行工具或YAML文件进行创建、查询、更新和删除。此外,ConfigMap还支持存储整个配置文件或JSON二进制对象,为复杂的配置管理提供了更大的灵活性。
  5. 支持多种使用场景:ConfigMap可以用于多种使用场景,如外部配置文件的管理、环境变量的设置、应用启动参数的动态传递等。这使得ConfigMap成为K8s集群中不可或缺的配置管理工具。
  6. 版本控制:由于ConfigMap是K8s的API资源对象,因此可以使用K8s的版本控制机制对其进行版本管理。这有助于跟踪和审计配置更改,确保集群的稳定性和可维护性。
  7. 注意事项:虽然ConfigMap提供了很多优点,但也有一些需要注意的地方。例如,ConfigMap不是加密的,不适合存储敏感信息(如密码、密钥等)。对于这类敏感信息,应该使用Kubernetes的Secret对象或其他加密手段进行存储和管理。此外,ConfigMap的大小也有限制(默认为1MB),需要根据实际情况进行规划和管理。

存储格式

ConfigMap 在 Kubernetes 中可以存储各种格式的文件内容,但本质上它只关心键(key)和值(value)的对应关系。不过,这些值经常是文本文件的内容,比如配置文件、脚本、JSON、YAML 等。

以下是一些示例,说明 ConfigMap 可以存储的文件格式及其用法:

1. 配置文件(如 INI、Properties 格式)

假设有一个名为 app.properties 的配置文件,内容如下:

database.url=jdbc:mysql://localhost:3306/mydb  
 database.user=root  
 database.password=secret

你可以使用这个文件来创建一个 ConfigMap:

kubectl create configmap my-config --from-file=path/to/app.properties

在 Pod 中,你可以通过挂载 ConfigMap 或使用环境变量来访问这些配置。

2. 脚本文件(如 Shell 脚本)

如果你有一个 Bash 脚本 startup.sh,内容如下:

#!/bin/bash  
 echo "Starting application..."  
 # 其他启动命令...

你也可以将其存储到 ConfigMap 中:

kubectl create configmap my-scripts --from-file=path/to/startup.sh

在 Pod 中,你可以通过挂载 ConfigMap 来执行这个脚本。

3. JSON 文件

JSON 文件也经常作为配置数据存储在 ConfigMap 中。例如,config.json 文件:

{  
 
   "host": "localhost",  
 
   "port": 8080,  
 
   "logLevel": "info"  
 
 }

可以使用以下命令创建 ConfigMap:

kubectl create configmap my-json-config --from-file=path/to/config.json

在 Pod 中,你可以通过挂载 ConfigMap 或使用环境变量来解析这个 JSON 数据。

4. YAML 文件

虽然 YAML 文件通常用于定义 Kubernetes 资源(如 Deployment、Service 等),但你也可以将 YAML 配置文件存储在 ConfigMap 中。然而,这样做可能不太常见,因为 YAML 文件本身已经定义了资源的结构。但如果你只是想存储一些 YAML 格式的配置数据,这也是可以的。

5. 环境变量文件

环境变量文件通常包含 key=value 格式的行,可以直接用于设置环境变量。例如,env.txt 文件:

DB_HOST=localhost  
DB_PORT=3306  
DB_USER=root  
DB_PASSWORD=secret

你可以使用这个文件来创建一个 ConfigMap,并设置环境变量:

kubectl create configmap my-env-config --from-env-file=path/to/env.txt

在 Pod 中,你可以通过环境变量来访问这些值。

创建configMap

定义configMap的几种方式

命令行方式

先准备几个配置文件放到/opt/configmap/prop目录下

# /opt/configmap/目录下
mkdir -p /opt/configmap/prop
cat > /opt/configmap/prop/color << EOF
good=purple
bad=balck
great=orange
EOF

cat > /opt/configmap/prop/monster << EOF
goblin=2
slime=1
dragon=10
cerberus=8
EOF

通过文件

将指定文件内的配置写入到configMap中

kubectl create configmap monster-conf --from-file=/opt/configmap/prop/monster

从0开始搞K8S:存储 configMap_configMap

通过目录

假定有一个目录存在,目录内有数个properties格式的配置文件

将目录内的prop格式文件加入到configMap

kubectl create configmap game-conf --from-file=/opt/configmap/prop

从0开始搞K8S:存储 configMap_configMap_02

可以看到这两种方式差异不大,只是一个指定目录,一个指定文件。

注意1,这两种方式导入的数据实际上是以文件名为key,文件内容为value。

注意2,根据这两个方式导入的configmap,在转换为yaml格式后可以看到在key后面有个一个 |,说明它是 多行字符串,通过对比,可以看下面根据字面值创建

通过字面值创建

使用-from-literal创建配置信息,

kubectl create configmap user-conf --from-literal=admin=tangotz --from-literal=user=guoguo

从0开始搞K8S:存储 configMap_configMap_03

其他数据格式

除了prop ini格式的文件,configmap还可以吧一些脚本 json文件作为配置写入configMap

在/opt/configmap/script目录创建一个简单的shell脚本

mkdir -p /opt/configmap/script
cd /opt/configmap/script
cat > /opt/configmap/script/demo.sh << EOF
#!/bin/bash
echo "Hello from startup script in ConfigMap!"
EOF
chmod +x

将这个demo.sh写入configMap

kubectl create configmap demo-conf --from-file=/opt/configmap/script/demo.sh

从0开始搞K8S:存储 configMap_configMap_04

使用

作为环境变量使用

configMap中的数据可以做为环境变量注入到容器中

apiVersion: v1
kind: Pod
metadata:
  name: env-pod
spec:
  containers:
  - image: busybox
    name: env-container
    command: ["/bin/sh", "-c", "env"]
    env:
    - name: my_env
      valueFrom:
        configMapKeyRef:
          name: game-conf
          key: color
    envFrom:
    - configMapRef:
        name: user-conf

使用 envFrom 时,Kubernetes 会将指定的 ConfigMap 中的所有键值对作为环境变量添加到容器中。

env 下的 valueFrom 和 configMapKeyRef 则允许你从 ConfigMap 中选择特定的键值对作为环境变量。


在上文中 game-conf是通过两个文件内容导入的,有两个key(color monster),这两个key的value是包含换行符的字符串。

所以期望的结果是,上述yaml会引入三个环境变量

一个是game-conf引入的my_env,其值是

good=purple

bad=balck

great=orange

这个长字符串

另两个是user-conf引入的两个admin=tangotz 和user=guoguo

从0开始搞K8S:存储 configMap_configMap_05

用configMap设置命令行参数

定义方式与上文相同

apiVersion: v1
metadata:
  name: command-pod
kind: Pod
spec:
  containers:
  - name: conmand-container
    image: busybox
    command: ["/bin/sh", "-c", "echo $(USER-CONF)"]
    
    env:
    - name: USER-CONF
      valueFrom:
        configMapKeyRef:
          name: user-conf
          key: user

这里引入了通过字面值创建的configMap user-conf(包含两个key user和admin),这里引入了user,并定义为USER-CONF。USER-CONF在command中被引用($(USER-CONF))

查看logs 能看到显示输出结果如下

从0开始搞K8S:存储 configMap_configMap_06

通过挂载数据卷方式使用configMap

创建一个内容为shell脚本的configMap

cat > /opt/configmap/script/startup.sh << EOF
echo "starting UP..."
EOF
kubectl create configmap scrip-startup --from-file=/opt/configmap/script/startup.sh

将其挂再到数据卷中使用

apiVersion: v1
kind: Pod
metadata:
  name: cm-vol-pod
spec:
  containers:
  - name: cm-vol-container
    image: busybox
    command: ["/bin/sh", "-c", "cat /tmp/startup.sh && sh /tmp/startup.sh"]
    volumeMounts:
    - name: config-volume
      mountPath: /tmp
  volumes:
  - name: config-volume
    configMap:
      name: script-startup
  

将script-startup通过数据卷形式挂载后,会在挂载目录下生成以key为文件没那个,value为内容的文件。

logs如下

从0开始搞K8S:存储 configMap_configMap_07

热更新

注意:configMap如果以ENV的方式挂载到到容器,热更不会剩下。以下演示采用挂载数据卷方式

创建三个configMap

kubectl create cm log-level-cm --from-literal=level=debug
kubectl create cm admin-count-cm --from-literal=admins=1

创建一个deployment,并采用不同的方式使用上述几个cm

apiVersion: apps/v1
kind: Deployment
metadata:
  name: cm-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: cm-app
  template:
    metadata:
      name: cm-pod
      labels: 
        app: cm-app
    spec:
      containers:
      - name: cm-container
        image: busybox
        command: ["/bin/sh", "-c", "sleep 6000"]
        env:
          - name: log-env
            valueFrom:
              configMapKeyRef:
               name:log-level-cm
               key: level
        volumeMounts:
        - name: config-volume
          mountPath: /tmp
      volumes:
      - name: config-volume
        configMap:
          name: admin-count-cm

这个yaml中使用了两种引入cm的方式

  • 环境变量方式引入,容器的环境变量中会有level=debug
  • 挂载卷方式 /tmp/admins 内容为 1

通过pod进入容器观察这两种挂载方式

kubectl exec -it cm-deployment-544df54d8-flz4q -c cm-container -- /bin/sh

注意

cm-deployment-544df54d8-flz4q 是pod名称

cm-container 是容器名称    

从0开始搞K8S:存储 configMap_configMap_08

注意: log-env 是在yaml中定义的env名称,其值是cm  log-level-cm中level定义的值。这个要理解清楚。

现在修改两个cm,通过edit进行修改。

kubectl edit cm log-level-cm

kubectl edit cm admin-count-cm

经其中值进行修改:(只是修改值)

原本log-level-cm 中 level=debug 修改为 level=pord

原本admin-count-cm 中 admins=1 修改为 admins=3

从0开始搞K8S:存储 configMap_configMap_09

可以看到,通过env挂载的cm没有变化,而通过挂载文件卷方式的cm实现了热更。

cm更新后触发滚动更新Deployment

注意:cm更新后,通过挂载文件卷方式挂载的cm会变更,但是这是文件变更,Pod内的业务不会重读这个文件。

举个例子,如果这个cm是个nginx配置文件,Pod是个nginx。热更这个cm只是把ngixn配置文件修改更新了,不会影响nginx进程。如果需要使其生效,需要reload nginx,使用K8S的方式,就是通过Deployment进行滚动更新,可以通过修改deployment的annotation来实现。

可以通过edit方式实现,也可以通过patch方式实现

edit方式:在spec.template.metadata下添加annotaions

从0开始搞K8S:存储 configMap_configMap_10

patch方式

kubectl patch deployment cm-deployment --patch '{"spec": {"template": {"metadata": {"annotations": {"version/config": "2024-05-27_10:43"}}}}}'

两种方式均可触发deployment的滚动更新。

从0开始搞K8S:存储 configMap_configMap_11