讲解

把配置硬编码进镜像的坏处显而易见:换个环境改个参数都要重新构建镜像。ConfigMap 是 Kubernetes 的配置容器:一个键值对集合(值可以是短字符串,也可以是整份配置文件文本),以「数据」的形式独立于 Pod 存在,Pod 通过环境变量或文件挂载的方式消费它。同一份镜像 + 不同 ConfigMap = 同一应用在不同环境的不同形态,这就是「镜像与环境解耦」。

消费 ConfigMap 有两条路,行为差异要记住。环境变量方式(env 里的 valueFrom.configMapKeyRef 取单个键,或 envFrom.configMapRef 整体导入):简单,但环境变量在容器启动时定格,ConfigMap 更新不会反映到已运行的容器。卷挂载方式(volumes 里声明 configMap,mount 进容器路径):ConfigMap 里每个键变成挂载目录下的一个文件,内容是值;这种方式 kubelet 会周期性同步更新(有几十秒延迟),但应用要重新读文件才能感知,且用 subPath 挂载的单个文件不会自动更新。

ConfigMap 的边界也要清楚:它存明文,任何能读它的人都看得到内容——敏感信息(密码、密钥)属于下一章的 Secret;它有 1MB 大小上限,放的是配置不是数据文件;它属于命名空间,只能被同命名空间的 Pod 使用。更新 ConfigMap 想让应用生效,可靠的做法是触发一次滚动更新(比如改 Deployment 模板里的一个注解),让新 Pod 读到新配置。

示例

一个 ConfigMap 同时承载「键值配置」和「整份文件」,Pod 分别用环境变量和卷挂载消费:

# wait: pod/ohmydocs-verify-configured
apiVersion: v1
kind: ConfigMap
metadata:
  name: ohmydocs-verify-config
data:
  APP_MODE: "development"
  APP_REGION: "cn-hangzhou"
  index.html: |
    <h1>来自 ConfigMap 的页面</h1>
---
apiVersion: v1
kind: Pod
metadata:
  name: ohmydocs-verify-configured
  labels:
    app: ohmydocs-verify-configured
spec:
  containers:
    - name: nginx
      image: nginx:1.27-alpine
      ports:
        - containerPort: 80
      env:
        - name: APP_MODE
          valueFrom:
            configMapKeyRef:
              name: ohmydocs-verify-config
              key: APP_MODE
      volumeMounts:
        - name: pages
          mountPath: /usr/share/nginx/html
  volumes:
    - name: pages
      configMap:
        name: ohmydocs-verify-config

验证两条消费路径都生效:环境变量在容器里可读,挂载目录下出现了以键为名的文件:

kubectl exec ohmydocs-verify-configured -- printenv APP_MODE
kubectl exec ohmydocs-verify-configured -- ls /usr/share/nginx/html
kubectl exec ohmydocs-verify-configured -- cat /usr/share/nginx/html/index.html

更新 ConfigMap 后观察差异:挂载的文件会被 kubelet 同步更新(有延迟),而环境变量定格在启动时刻:

kubectl patch configmap ohmydocs-verify-config --type=merge -p '{"data":{"APP_MODE":"production"}}'
sleep 3
kubectl exec ohmydocs-verify-configured -- printenv APP_MODE
kubectl get configmap ohmydocs-verify-config -o jsonpath='ConfigMap 里的最新值: {.data.APP_MODE}'
echo

常见坑

  • 改了 ConfigMap 应用没变:环境变量方式永远定格在启动时;卷挂载方式有同步延迟且应用要重读文件;想立刻生效就滚动重启(kubectl rollout restart)。
  • 把敏感信息放进 ConfigMap:ConfigMap 是明文,etcd 里、任何有读权限的人都能看到——密码密钥一律用 Secret。
  • subPath 挂载的坑:mountPath 用 subPath 挂单个文件时,ConfigMap 更新不会同步进来,这是最常见的「文件不更新」原因。
  • ConfigMap 还没建就起 Pod:env 引用不存在的 ConfigMap 会让容器启动失败(CreateContainerConfigError);可选引用要显式标 optional: true。

小结

ConfigMap = 明文键值配置,环境变量(启动定格)或卷挂载(延迟同步)两种方式消费;敏感信息别放这里;配置更新靠滚动重启生效。下一章讲它的敏感信息版本:Secret。