K8s学习笔记:04-ConfigMap配置管理

对应章节:第四章 配置与存储 / 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
# NAME DATA AGE
# kube-root-ca.crt 1 47h ← 系统自带的,别管
# my-config 2 10s

kubectl describe configmap my-config
# Name: my-config
# Namespace: default
# Data
# ====
# APP_ENV:
# ----
# production
# NGINX_PORT:
# ----
# 8080

kubectl get configmap my-config -o yaml
# 看完整的 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"
# NGINX_PORT=8080
# APP_ENV=production

用法二: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
# 1. 创建 ConfigMap
kubectl create configmap nginx-html \
--from-literal=index.html='<html><body><h1>Hello from ConfigMap!</h1></body></html>'

# 2. 起 Pod 并挂载
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
# <html><body><h1>Hello from ConfigMap!</h1></body></html>
kill %1

volumeMounts.name 必须和 volumes[].name 一致,K8s 靠这个名字把挂载点和卷对上号。


坑 1:volume mount 会覆盖整个目标目录

现象

ConfigMap 挂载后,目标目录里只剩下 ConfigMap 里的文件,原来的文件全没了:

1
2
3
kubectl exec nginx-cm -- ls /usr/share/nginx/html/
# index.html
# 只有这一个文件!nginx 镜像自带的 50x.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 后环境变量也会变

现象

envFromvalueFrom 注入的 Pod,更新 ConfigMap 后变量值不变。

真相

ConfigMap 更新后:

注入方式 是否自动更新
volume mount(文件挂载) ✅ 会自动更新(kubelet 定期同步,默认 ~1 分钟)
envFrom / valueFrom(环境变量) ❌ 不会更新(Pod 启动时只注入一次)

验证

1
2
3
4
5
6
kubectl edit configmap nginx-html
# 改成 <h1>UPDATED!</h1>,保存退出

# 等几秒
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 全量注入

1
2
3
# 1. 创建一个含三个配置项的 ConfigMap(PORT、ENV、LOG_LEVEL)
# 2. 起一个 busybox Pod,用 envFrom 全量注入
# 3. kubectl exec 进 Pod,env 确认三个变量都在

练习 2:valueFrom 挑选注入

1
2
3
# 1. 用同一个 ConfigMap,起一个新 Pod
# 2. 只用 valueFrom 挑 PORT 和 LOG_LEVEL 注入,变量名叫 MY_PORT 和 MY_LOG
# 3. 确认 ENV 没有被注入

练习 3:文件挂载 + 覆盖验证

1
2
3
4
# 1. 删除现有 nginx-cm
# 2. 重建,但加一个 subPath 只挂 index.html(不覆盖整个目录)
# 3. ls /usr/share/nginx/html/ 看 50x.html 是否还在
# 提示:volumeMounts 加 subPath: index.html

练习 4:更新同步验证

1
2
# 1. kubectl edit configmap nginx-html 改内容
# 2. 等 1-2 分钟后 kubectl exec 进去 cat,确认自动更新

清理

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

K8s学习笔记:04-ConfigMap配置管理
https://bote798.top/2026/07/14/K8s学习笔记-04-ConfigMap配置管理/
作者
bote798
发布于
2026年7月14日
更新于
2026年7月16日
许可协议