ConfigMap实战:Pod挂载ConfigMap作为环境变量、作为卷挂载、热更新机制

说实话,ConfigMap 这东西刚出来的时候,我第一反应是:这不就是个键值对存储吗?有啥好学的?直到我在一个生产环境里,因为配置改完忘了重建 Pod,导致线上服务挂了半小时……嗯,从那以后我再也不敢小看它了。

今天咱们就把它掰开揉碎,讲清楚三种核心用法:环境变量挂载、卷挂载、还有那个让人又爱又恨的热更新机制。

一、ConfigMap 是什么?

说白了,ConfigMap 就是 Kubernetes 里专门用来存配置的“小仓库”。它把配置和镜像解耦,你改配置不用重新打包镜像,也不用重启整个集群。

我个人习惯,所有非敏感配置都扔进 ConfigMap。比如:

  • 应用的环境变量(APP_ENV=production
  • 日志级别(LOG_LEVEL=info
  • 数据库连接地址(非密码部分)
  • Nginx 配置文件、Prometheus 告警规则等
小提示:敏感信息(密码、密钥、Token)别放 ConfigMap,那是 Secret 的活儿。我曾经见过有人把数据库密码明文写在 ConfigMap 里……嗯,后果你懂的。

二、创建 ConfigMap 的几种姿势

创建 ConfigMap 其实很简单,我一般用这三种方式:

1. 直接写 YAML 文件

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  APP_ENV: production
  LOG_LEVEL: info
  DB_HOST: db.example.com
  DB_PORT: "3306"

2. 从文件创建

你有个 nginx.conf 文件?直接导入:

kubectl create configmap nginx-config --from-file=nginx.conf

3. 从 .env 文件创建

我特别喜欢这个方式,因为本地开发用的 .env 文件可以直接复用:

kubectl create configmap app-env --from-env-file=.env

三、Pod 挂载 ConfigMap 作为环境变量

这是最常用的方式。你想想看,应用启动时读环境变量,多自然。

apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
  - name: app
    image: my-app:latest
    envFrom:
    - configMapRef:
        name: app-config

这样 Pod 启动后,APP_ENVLOG_LEVEL 这些变量就自动注入进去了。

注意:环境变量方式不支持热更新!Pod 启动后,你改了 ConfigMap,环境变量不会自动刷新。这是很多人踩过的坑。

四、Pod 挂载 ConfigMap 作为卷

这种方式就灵活多了。你可以把整个配置文件挂载进去,也可以只挂载某个 key。

完整挂载示例

apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
  - name: app
    image: my-app:latest
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
  volumes:
  - name: config-volume
    configMap:
      name: app-config

这样 /etc/config 目录下就会有 APP_ENVLOG_LEVEL 等文件,每个 key 对应一个文件。

只挂载某个 key

有时候你只想挂载某个配置文件,比如 nginx.conf

volumes:
- name: nginx-config-volume
  configMap:
    name: nginx-config
    items:
    - key: nginx.conf
      path: nginx.conf

五、热更新机制——这个才是重点

好,终于到热更新了。为什么我要单独拿出来讲?因为这里坑最多。

卷挂载方式支持热更新。你改了 ConfigMap,Pod 里的文件会自动同步。但注意,是“文件”同步,不是“进程”同步。

什么意思呢?举个例子:

  • 你挂载了一个 nginx.conf/etc/nginx/nginx.conf
  • ConfigMap 更新后,文件内容变了
  • 但 Nginx 进程不会自动 reload
  • 你需要手动执行 nginx -s reload 或者发 SIGHUP 信号

我曾经遇到过一个场景:改了日志级别配置,以为热更新会自动生效,结果排查了半天才发现应用没有监听文件变化。嗯,从那以后我养成了一个习惯——热更新只保证文件更新,不保证进程感知。

避坑指南:
  • 热更新有延迟,通常几秒到几分钟不等(取决于 kubelet 同步周期)
  • 如果应用不监听文件变化,热更新等于没用
  • 环境变量方式不支持热更新,别指望它
  • SubPath 挂载也不支持热更新,这个坑我踩过两次

六、实战:一个完整的例子

咱们来个完整的,从创建 ConfigMap 到 Pod 挂载,再到热更新验证。

1. 创建 ConfigMap

kubectl create configmap game-config --from-literal=game.properties=level=3 --from-literal=ui.properties=color=blue

2. 创建 Pod 挂载卷

apiVersion: v1
kind: Pod
metadata:
  name: configmap-demo
spec:
  containers:
  - name: test
    image: busybox
    command: ["/bin/sh", "-c", "while true; do cat /etc/config/game.properties; sleep 10; done"]
    volumeMounts:
    - name: config
      mountPath: /etc/config
  volumes:
  - name: config
    configMap:
      name: game-config

3. 验证热更新

# 查看当前内容
kubectl logs configmap-demo

# 修改 ConfigMap
kubectl edit configmap game-config
# 把 level=3 改成 level=5

# 等一会儿,再看日志
kubectl logs configmap-demo
# 你会发现内容已经变了

七、总结一下

挂载方式 是否支持热更新 适用场景
环境变量 ❌ 不支持 启动时固定的配置
卷挂载(完整) ✅ 支持 需要动态更新的配置文件
卷挂载(SubPath) ❌ 不支持 挂载单个文件且不需要更新

我个人建议:

  • 如果配置基本不变,用环境变量,简单粗暴
  • 如果需要动态更新,用卷挂载,但应用要支持监听文件变化
  • 千万别把敏感信息放 ConfigMap,那是 Secret 的活

好了,ConfigMap 实战就讲到这里。下一章咱们聊聊 Secret,那个比 ConfigMap 更敏感、也更容易踩坑的东西。

课后思考:如果你的应用不支持监听文件变化,但又需要热更新配置,你会怎么处理?提示:可以试试 Sidecar 模式或者 Reloader 工具。