在 Kubernetes 里,ConfigMap 是专门用来保存非敏感配置的 API 对象。它的设计目标很明确:把配置从镜像里拿出来,放到集群层面统一管理。这样做的直接好处是,开发、测试、生产三个环境可以共用同一个镜像,只通过不同的 ConfigMap 注入不同的数据库地址、日志级别或超时时间。镜像构建次数大幅减少,配置变更也不再依赖 CI/CD 流水线重新走一遍。

一、ConfigMap 的创建与查看
创建 ConfigMap 有两种主流方式:命令行直接指定键值对,或者用 YAML 文件声明。命令行适合临时测试和简单场景,例如把单个配置项快速塞进集群;YAML 文件则更适合纳入 Git 版本管理,方便审计和回滚。两种方式最终生成的资源完全等价,选择哪一种更多取决于团队的工作流。
# 命令行创建,直接指定两个键值对 kubectl create configmap app-config \ --from-literal=database.host=mysql.default.svc.cluster.local \ --from-literal=log.level=info
上面这种方式会在 default 命名空间生成一个名为 app-config 的 ConfigMap。如果需要从文件读取配置,可以使用 --from-file 参数,文件名会作为键名。YAML 方式则更直观,适合包含多行配置或需要注释的场景。下面是一个典型的 ConfigMap 定义,data 字段下的键值对会被完整保存。
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
database.host: "mysql.default.svc.cluster.local"
database.port: "3306"
log.level: "info"
app.properties: |
timeout=30
retries=3
创建完成后,可以通过 kubectl get configmap app-config -o yaml 查看完整内容,或者用 kubectl describe configmap app-config 查看摘要。需要注意的是,ConfigMap 中的值始终是字符串,即使写成 3306 也会被当作文本处理,容器读取时需要自己做类型转换。这个细节在端口号、线程数等数值型配置上尤其容易踩坑。
二、在 Pod 中读取 ConfigMap 的三种方式
把 ConfigMap 创建好之后,Pod 可以通过三种常见方式读取里面的数据。第一种是环境变量注入,用 valueFrom 引用指定键;第二种是 envFrom 一次性导入整个 ConfigMap;第三种是挂载为 Volume,让容器以文件形式读取。三种方式各有适用场景,不能简单说哪一种最好。
环境变量注入适合配置项数量较少且需要精确控制的场景。比如只把数据库地址暴露给容器,而不希望它看到其他无关配置。下面这个 Pod 定义展示了用 valueFrom 读取单个键的写法。
apiVersion: v1
kind: Pod
metadata:
name: demo-pod
spec:
containers:
- name: app
image: nginx:1.25
env:
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: database.host
如果配置项很多,一个个写 valueFrom 会很啰嗦,这时可以用 envFrom 把整个 ConfigMap 自动映射成环境变量。它的键名会原样成为环境变量名,因此 ConfigMap 中的键必须符合环境变量命名规范,比如不能包含点号或横线。不过实际使用中数据库地址这种键名常写成 database.host,用 envFrom 就会失败,所以很多团队会改用前缀加下划线的命名,或者在 YAML 里对键名做适配。
apiVersion: v1
kind: Pod
metadata:
name: demo-pod-envfrom
spec:
containers:
- name: app
image: nginx:1.25
envFrom:
- configMapRef:
name: app-config
第三种方式是把 ConfigMap 挂载成文件。这种方法最大的优势是支持热更新,并且可以注入多行配置文件。Pod 中每个键会变成挂载目录下的一个文件,文件名就是键名。比如 app.properties 会以文件形式出现在 /etc/config 目录下。它特别适合读取 .properties、.ini 或 .conf 这类传统配置文件的应用。下面是挂载示例。
apiVersion: v1
kind: Pod
metadata:
name: demo-pod-volume
spec:
containers:
- name: app
image: nginx:1.25
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: app-config
这三种方式可以混合使用,但要注意环境变量注入的配置在容器启动后不会随 ConfigMap 更新而变化;挂载文件则会在一定时间内同步更新。理解这个差异对后续做配置变更方案非常关键。
三、ConfigMap 更新机制与不可变模式
很多人以为 ConfigMap 更新后容器会立刻感知,实际情况远没有这么理想。对于通过 Volume 挂载的 ConfigMap,kubelet 会周期性检查变化并更新挂载文件,默认同步间隔大约一分钟左右。即使文件被更新,正在运行的进程也不会自动重新加载配置,除非应用本身实现了文件监听或者收到 SIGHUP 信号。对于环境变量注入的场景,Pod 一旦创建,环境变量就固定了,更新 ConfigMap 不会影响已存在的 Pod。
这就引出一个常见的坑:你修改了 ConfigMap,但旧的 Pod 还在用旧配置。要解决这个问题,要么滚动重启 Deployment,要么借助 Reloader 这类工具自动触发滚动更新。如果业务对配置一致性要求很高,建议把 ConfigMap 的版本号或哈希写入 Pod 模板注解,这样每次配置变更都会触发新的 ReplicaSet。
如果配置本身很少变动,可以启用不可变模式。从 Kubernetes 1.21 开始,ConfigMap 支持 immutable 字段。设为 true 后,kubelet 不再轮询该 ConfigMap 的变化,能减少 API Server 压力,也避免了意外修改带来的不确定性。需要改配置时,就新建一个 ConfigMap,再更新 Deployment 引用。示例如下。
apiVersion: v1 kind: ConfigMap metadata: name: app-config-immutable immutable: true data: database.host: "mysql.default.svc.cluster.local" log.level: "info"
不可变模式尤其适合生产环境中的稳定配置。它牺牲了灵活性,换来了可预测性和性能。不过启用后 kubectl apply 修改 data 会被 API 拒绝,需要删除重建。
四、实践建议与常见问题
虽然 ConfigMap 很方便,但它不适合存放大块数据。单个 ConfigMap 的 data 部分总大小默认限制为 1MB,这是 API Server 的存储限制。如果你的配置文件超过这个尺寸,应该考虑拆分成多个 ConfigMap,或者把大文件放到持久卷或对象存储中。不要把二进制文件塞进 ConfigMap,它只适合文本类配置。
另一个容易混淆的点是敏感信息。ConfigMap 不加密,任何有权限读取 ConfigMap 的用户都能看到明文内容。数据库密码、API Token、证书私钥等必须使用 Secret,而不是 ConfigMap。很多初学者会把所有配置无脑放进 ConfigMap,等权限审计时才发现问题。正确的做法是按敏感级别拆分:非敏感配置用 ConfigMap,敏感配置用 Secret,然后在 Pod 中分别引用。
还有一个小技巧:如果挂载 ConfigMap 到某个目录,默认会覆盖该目录下已有的文件。比如挂载到 /etc/nginx 可能会把 nginx.conf 覆盖掉。可以用 subPath 挂载单个文件来避免目录覆盖。下面是一个只挂载单个键的示例。
apiVersion: v1
kind: Pod
metadata:
name: demo-pod-subpath
spec:
containers:
- name: app
image: nginx:1.25
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: config-volume
configMap:
name: app-config
这里 subPath 指定的 nginx.conf 必须与 ConfigMap 中的键名保持一致。使用 subPath 后,ConfigMap 更新也不会同步到已挂载的文件,这是它的一个副作用。
ConfigMap容器配置Kubernetes修改时间:2026-10-01 09:36:29