对应章节:第四章 配置与存储 / 4.1 ConfigMap:把配置从镜像里抽出来
日期:2026年7月14日
为什么不能把配置写进镜像?
回顾前三章你造的 Nginx:
1
| kubectl create deployment my-nginx-deploy --image=nginx:alpine --port=80
|
这个 nginx 用的是什么首页?镜像里自带的默认页(”Welcome to nginx!”)。端口?镜像里写死的 80。
| 需求 |
写进镜像能做到吗? |
| 换个首页文案(不改代码) |
✗ 要重新 docker build |
| 开发连 dev 数据库,生产连 prod 数据库 |
✗ 要打两个镜像 |
| 改个端口号 |
✗ 要改 Dockerfile 重新构建 |
核心矛盾:镜像 = 不变的(二进制+库),配置 = 会变的。K8s 的解法:ConfigMap。
ConfigMap 是什么
ConfigMap 就是一个存在集群里的 key-value 字典。Pod 引用它,但不拥有它。删 Pod → ConfigMap 还在。
1 2 3 4 5
| ┌──── ConfigMap ────┐ │ NGINX_PORT: 8080 │ ┌──── Pod ────┐ │ index.html: "..." │ ←── │ env / file │ └───────────────────┘ │ 注入到容器里 │ └─────────────┘
|
创建 ConfigMap 的三种方式
方式一:–from-literal(从命令行字面量)
1 2 3
| kubectl create configmap my-config \ --from-literal=NGINX_PORT=8080 \ --from-literal=APP_ENV=production
|
literal = “字面量”,值直接写在命令行里。等号左边是 KEY(你起名),右边是 VALUE(随便写)。
方式二:–from-file(从文件)
1 2 3 4
| echo '<h1>Hello from ConfigMap!</h1>' > /tmp/index.html
kubectl create configmap nginx-html --from-file=/tmp/index.html
|
文件名变成 key(index.html),文件内容变成 value。适合 HTML、nginx.conf 等长内容。
方式三:YAML 声明式
1 2 3 4 5 6 7
| apiVersion: v1 kind: ConfigMap metadata: name: my-config data: NGINX_PORT: "8080" APP_ENV: "production"
|
查看 ConfigMap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| kubectl get configmap
kubectl describe configmap my-config
kubectl get configmap my-config -o yaml
|
三种注入方式
用法一:envFrom —— 全量注入环境变量
1
| kubectl run test-cm --image=busybox:1.36 --restart=Never --dry-run=client -o yaml > /tmp/test-cm.yaml
|
编辑 /tmp/test-cm.yaml,在 containers 下加上 envFrom:
1 2 3 4 5 6 7 8
| spec: containers: - name: busybox image: busybox:1.36 command: ["sleep", "3600"] envFrom: - configMapRef: name: my-config
|
1 2 3 4
| kubectl apply -f /tmp/test-cm.yaml kubectl exec test-cm -- env | grep -E "NGINX_PORT|APP_ENV"
|
用法二:valueFrom —— 挑单个 key 注入
1 2 3 4 5 6
| env: - name: MY_PORT valueFrom: configMapKeyRef: name: my-config key: NGINX_PORT
|
效果:容器里 $MY_PORT=8080。注意变量名可以自己定(MY_PORT),不一定和 ConfigMap 的 key 同名。
用法三:volume mount —— 挂载为文件
让 Nginx 用 ConfigMap 里的 HTML 做首页:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| kubectl create configmap nginx-html \ --from-literal=index.html='<html><body><h1>Hello from ConfigMap!</h1></body></html>'
kubectl apply -f - <<EOF apiVersion: v1 kind: Pod metadata: name: nginx-cm labels: app: nginx-cm spec: containers: - name: nginx image: nginx:alpine ports: - containerPort: 80 volumeMounts: - name: html-volume mountPath: /usr/share/nginx/html volumes: - name: html-volume configMap: name: nginx-html EOF
|
1 2 3 4 5
| kubectl port-forward pod/nginx-cm 8080:80 --address 0.0.0.0 & curl localhost:8080
kill %1
|
volumeMounts.name 必须和 volumes[].name 一致,K8s 靠这个名字把挂载点和卷对上号。
坑 1:volume mount 会覆盖整个目标目录
现象
ConfigMap 挂载后,目标目录里只剩下 ConfigMap 里的文件,原来的文件全没了:
1 2 3
| kubectl exec nginx-cm -- ls /usr/share/nginx/html/
|
原因
ConfigMap 挂载是整个目录替换,不是追加。mountPath 指向的目录会被 ConfigMap 的内容完全接管。
解决:用 subPath 只挂单个文件
如果只想替换一个文件而不影响目录里其他文件,在 volumeMounts 里加 subPath:
1 2 3 4
| volumeMounts: - name: html-volume mountPath: /usr/share/nginx/html/index.html subPath: index.html
|
这样只有 index.html 被替换,50x.html 等原有文件保持不变。
坑 2:以为更新 ConfigMap 后环境变量也会变
现象
用 envFrom 或 valueFrom 注入的 Pod,更新 ConfigMap 后变量值不变。
真相
ConfigMap 更新后:
| 注入方式 |
是否自动更新 |
| volume mount(文件挂载) |
✅ 会自动更新(kubelet 定期同步,默认 ~1 分钟) |
| envFrom / valueFrom(环境变量) |
❌ 不会更新(Pod 启动时只注入一次) |
验证
1 2 3 4 5 6
| kubectl edit configmap nginx-html
kubectl exec nginx-cm -- cat /usr/share/nginx/html/index.html
|
环境变量只在 Pod 启动时注入一次,之后 ConfigMap 怎么改都不会变。需要新值 → 重建 Pod。
扩展知识:三种注入方式的选择指南
| 场景 |
推荐方式 |
理由 |
| 数据库地址、端口、环境名 |
envFrom |
一键全量注入,省事 |
| 某几个敏感/关键变量需重命名 |
valueFrom |
变量名可以和 key 不同 |
| 配置文件(nginx.conf、html) |
volume mount |
文件形式,支持热更新 |
| 只替换目录里一个文件 |
volume mount + subPath |
不覆盖目录其他文件 |
练习
练习 1:envFrom 全量注入
练习 2:valueFrom 挑选注入
练习 3:文件挂载 + 覆盖验证
练习 4:更新同步验证
清理
1 2
| kubectl delete pod nginx-cm test-cm kubectl delete configmap my-config nginx-html
|
本章核心认知回顾
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ConfigMap = 集群里的 key-value 字典,Pod 引用它但不拥有它
创建方式: --from-literal 命令行字面量(少量键值对) --from-file 从文件(长内容:HTML / nginx.conf) YAML 声明式(版本管理友好)
三种注入方式: envFrom 全量注入环境变量(省事,但不会热更新) valueFrom 挑单个 key 注入(变量名可自定义) volume mount 挂载为文件(支持热更新,但会覆盖整个目录)
两个坑: 1. volume mount 覆盖目标目录 → 用 subPath 只挂单个文件 2. 环境变量注入不会自动更新 → 需重建 Pod
|