configMap
许多应用程序会从命令行参数、配置文件或环境变联众读取配置信息。configMap API个我们提供了向容器中注入配置信息的机制,configMap可以用来保存单个属性,也可以用来保存整个配置文件或者JSON二进制大对象。
它的主要目的是解决一下问题:
- 代码与配置分离:ConfigMap允许将应用的配置信息从容器镜像中分离出来,这样可以更轻松地管理配置,而不必重新构建和部署容器镜像。
- 统一的集群配置管理:ConfigMap提供了一个统一的机制,用于在K8s集群中存储、管理和传递配置信息。这使得配置数据可以在多个Pod、容器或服务之间共享和重用。
- 提高可移植性:通过将配置信息与容器镜像分离,ConfigMap使得容器镜像更加通用和可移植。同一个容器镜像可以在不同的环境中使用,只需通过ConfigMap提供不同的配置即可。
- 简化配置管理:ConfigMap支持以key-value对的形式存储配置数据,可以方便地通过kubectl命令行工具或YAML文件进行创建、查询、更新和删除。此外,ConfigMap还支持存储整个配置文件或JSON二进制对象,为复杂的配置管理提供了更大的灵活性。
- 支持多种使用场景:ConfigMap可以用于多种使用场景,如外部配置文件的管理、环境变量的设置、应用启动参数的动态传递等。这使得ConfigMap成为K8s集群中不可或缺的配置管理工具。
- 版本控制:由于ConfigMap是K8s的API资源对象,因此可以使用K8s的版本控制机制对其进行版本管理。这有助于跟踪和审计配置更改,确保集群的稳定性和可维护性。
- 注意事项:虽然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
通过目录
假定有一个目录存在,目录内有数个properties格式的配置文件
将目录内的prop格式文件加入到configMap
kubectl create configmap game-conf --from-file=/opt/configmap/prop
可以看到这两种方式差异不大,只是一个指定目录,一个指定文件。
注意1,这两种方式导入的数据实际上是以文件名为key,文件内容为value。
注意2,根据这两个方式导入的configmap,在转换为yaml格式后可以看到在key后面有个一个 |
,说明它是 多行字符串
,通过对比,可以看下面根据字面值创建
通过字面值创建
使用-from-literal创建配置信息,
kubectl create configmap user-conf --from-literal=admin=tangotz --from-literal=user=guoguo
其他数据格式
除了prop ini格式的文件,configmap还可以吧一些脚本 json文件作为配置写入configMap
在/opt/configmap/script目录创建一个简单的shell脚本
mkdir -p /opt/configmap/script
cd /opt/configmap/script
cat > /opt/configmap/script/ << EOF
#!/bin/bash
echo "Hello from startup script in ConfigMap!"
EOF
chmod +x
将这个写入configMap
kubectl create configmap demo-conf --from-file=/opt/configmap/script/
使用
作为环境变量使用
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
用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 能看到显示输出结果如下
通过挂载数据卷方式使用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如下
热更新
注意: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
是容器名称
注意: 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
可以看到,通过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
patch方式
kubectl patch deployment cm-deployment --patch '{"spec": {"template": {"metadata": {"annotations": {"version/config": "2024-05-27_10:43"}}}}}'
两种方式均可触发deployment的滚动更新。