IT策士 10余年一线大厂经验,专注 IT 思维、架构、职场进阶。我会在各个平台持续发布最新文章,助你少走弯路。
在之前的文章中,我们通过环境变量向容器传递配置------REDIS_HOST=redis-service、FLASK_ENV=production。这种方式在第 13 篇 Compose 环境变量管理中已经熟悉了。但当配置项越来越多(几十个甚至上百个)、需要挂载整个配置文件、或者需要在多个 Pod 之间共享同一份配置时,环境变量就显得力不从心了。
Kubernetes 为此提供了专门的配置管理对象------ConfigMap 。它用来存储非敏感的键值对配置,可以注入为环境变量、挂载为文件,或者作为命令行参数。与之对应的是 Secret(第 33 篇主题),用于存储密码、密钥等敏感信息。今天这篇,我们就把 ConfigMap 的创建、注入、更新策略彻底搞清楚,并把它应用到贯穿案例的 Flask + Redis 应用中,将之前硬编码的配置迁移出来。
一、ConfigMap 是什么?解决什么痛点?
ConfigMap 是 K8s 中用来存储非敏感配置的 API 对象。它本质上是一个键值对集合,键是配置项名称,值可以是简单的字符串,也可以是一整个配置文件的内容。
它的核心价值是将配置与镜像解耦 ------镜像只包含应用代码和运行时,不同环境(开发、测试、生产)的差异化配置通过 ConfigMap 在运行时注入,无需为每个环境重新构建镜像。这和 Compose 中的 env_file + .env 文件的组合用法思想一致,但 ConfigMap 更进一步:它不依赖文件位置,可以在多个 Pod 之间共享,可以作为独立资源进行版本管理,并且可以与 Deployment、Service 等 K8s 对象协同使用。
先明确一个概念:ConfigMap vs Secret。ConfigMap 用于非敏感配置(如日志级别、服务端口、功能开关),Secret 用于敏感信息(密码、API 密钥、TLS 证书)。两者在创建和使用方式上高度相似------Secret 也支持以环境变量或文件挂载的方式注入 Pod。本篇聚焦 ConfigMap,第 33 篇将专门讲解 Secret 的安全实践。
二、创建 ConfigMap 的四种方式
2.1 从字面量创建
最直接的方式,适合少量配置项:
bash
kubectl create configmap flask-config \
--from-literal=FLASK_ENV=production \
--from-literal=LOG_LEVEL=warn \
--from-literal=REDIS_HOST=redis-service
输出:
bash
configmap/flask-config created
bash
kubectl get configmap flask-config
bash
NAME DATA AGE
flask-config 3 10s
DATA=3 表示这个 ConfigMap 包含 3 个键值对。查看详细内容:
bash
kubectl describe configmap flask-config
bash
Name: flask-config
Namespace: default
Data
====
FLASK_ENV:
----
production
LOG_LEVEL:
----
warn
REDIS_HOST:
----
redis-service
2.2 从文件创建
如果配置以文件形式存在,比如一个 JSON 配置文件 app-config.json:
bash
{
"flask_env": "production",
"log_level": "warn",
"redis_host": "redis-service"
}
bash
kubectl create configmap flask-config-file \
--from-file=app-config.json
K8s 会用文件名作为键(app-config.json),文件内容作为值。也可以指定自定义键名:
bash
kubectl create configmap flask-config-custom \
--from-file=config=app-config.json
这样键名就是 config。
2.3 从目录创建
如果一个目录下有多个配置文件:
bash
mkdir config-dir
echo "production" > config-dir/FLASK_ENV
echo "redis-service" > config-dir/REDIS_HOST
kubectl create configmap flask-config-dir \
--from-file=config-dir/
每个文件名成为一个键,文件内容成为对应的值。
2.4 声明式 YAML(推荐)
命令行创建适合快速测试。生产环境中,推荐使用声明式 YAML,便于纳入 Git 管理和 CI/CD 流程:
bash
apiVersion: v1
kind: ConfigMap
metadata:
name: flask-config-yaml
data:
FLASK_ENV: "production"
LOG_LEVEL: "warn"
REDIS_HOST: "redis-service"
REDIS_PORT: "6379"
bash
kubectl apply -f flask-configmap.yaml
YAML 方式支持 kubectl diff(kubectl diff -f flask-configmap.yaml),在实际修改 ConfigMap 之前预览变更差异,避免意外覆盖。
三、将 ConfigMap 注入 Pod
创建好 ConfigMap 后,有三种方式将其注入容器:环境变量、文件挂载、命令行参数。
3.1 注入为环境变量
这是最接近第 13 篇 Compose environment 的方式。可以将 ConfigMap 中的一个键注入为一个环境变量:
bash
env:
- name: FLASK_ENV
valueFrom:
configMapKeyRef:
name: flask-config-yaml
key: FLASK_ENV
也可以将整个 ConfigMap 的所有键值对一次性注入为环境变量(键名自动转为环境变量名):
bash
envFrom:
- configMapRef:
name: flask-config-yaml
3.2 挂载为文件
这是 ConfigMap 最强大的用法------将一个或多个配置项作为文件挂载到容器内指定路径。容器内的应用可以直接读取文件来获取配置:
bash
volumes:
- name: config-volume
configMap:
name: flask-config-yaml
containers:
- name: flask
volumeMounts:
- name: config-volume
mountPath: /app/config
挂载后,/app/config/ 目录下会为每个键生成一个同名文件。验证:
bash
kubectl exec <pod-name> -- ls /app/config
# FLASK_ENV LOG_LEVEL REDIS_HOST REDIS_PORT
kubectl exec <pod-name> -- cat /app/config/FLASK_ENV
# production
3.3 作为命令行参数
ConfigMap 的值也可以注入为容器的启动参数:
bash
command: ["python", "app.py"]
args:
- "--log-level=$(LOG_LEVEL)"
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: flask-config-yaml
key: LOG_LEVEL
四、实战:为 Flask + Redis 迁移配置
现在把贯穿案例中的硬编码配置迁移到 ConfigMap。
4.1 创建 ConfigMap
bash
apiVersion: v1
kind: ConfigMap
metadata:
name: flask-counter-config
data:
FLASK_ENV: "production"
LOG_LEVEL: "info"
REDIS_HOST: "redis-service"
REDIS_PORT: "6379"
bash
kubectl apply -f flask-config.yaml
4.2 更新 Deployment 使用 ConfigMap
bash
apiVersion: apps/v1
kind: Deployment
metadata:
name: flask-deployment
spec:
replicas: 3
selector:
matchLabels:
app: flask-counter
template:
spec:
containers:
- name: flask
image: flask-redis-counter:2.0
ports:
- containerPort: 5000
envFrom:
- configMapRef:
name: flask-counter-config
startupProbe:
httpGet:
path: /health
port: 5000
periodSeconds: 5
failureThreshold: 12
livenessProbe:
httpGet:
path: /health
port: 5000
periodSeconds: 15
failureThreshold: 3
readinessProbe:
httpGet:
path: /health
port: 5000
periodSeconds: 5
failureThreshold: 2
envFrom.configMapRef 将 flask-counter-config 中的所有键值对作为环境变量注入容器。Flask 应用通过 os.environ.get('FLASK_ENV') 读取这些变量------完全不需要修改 app.py。
bash
kubectl apply -f flask-deployment.yaml
验证环境变量注入:
bash
kubectl exec deploy/flask-deployment -- env | grep -E "FLASK_ENV|LOG_LEVEL|REDIS_HOST"
# FLASK_ENV=production
# LOG_LEVEL=info
# REDIS_HOST=redis-service
# REDIS_PORT=6379
验证服务正常运行:
bash
curl http://$(minikube ip)/counter
# Hello World! I have been seen 1 times.
4.3 注入 Nginx 配置文件(文件挂载示例)
如果你的 Flask 应用前端有一个 Nginx Sidecar,可以通过 ConfigMap 注入 Nginx 配置:
bash
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
nginx.conf: |
server {
listen 80;
location / {
proxy_pass http://127.0.0.1:5000;
}
location /health {
return 200 '{"status":"ok"}';
}
}
在 Pod 中挂载:
bash
containers:
- name: nginx
image: nginx:alpine
volumeMounts:
- name: nginx-config-volume
mountPath: /etc/nginx/conf.d
volumes:
- name: nginx-config-volume
configMap:
name: nginx-config
Nginx 容器启动时会读取 /etc/nginx/conf.d/nginx.conf,使用 ConfigMap 中的配置。修改 ConfigMap 中的配置,Nginx 需要 reload 才能生效(关于热更新,见下文)。
五、ConfigMap 的更新与热重载
ConfigMap 更新后,通过不同方式注入的配置有不同的生效行为:
5.1 触发滚动更新
如果修改了作为环境变量注入的 ConfigMap,需要触发 Deployment 滚动更新让 Pod 重建并获取新值:
bash
kubectl rollout restart deployment/flask-deployment
rollout restart 会触发一次滚动更新(第 26 篇学过的机制),所有 Pod 逐步重建,新 Pod 读取最新的 ConfigMap 值。生产环境中,通常将 ConfigMap 版本号作为 Pod 注解,配合 CI/CD 自动触发更新。
5.2 Immutable ConfigMap
从 K8s v1.21 起,可以将 ConfigMap 设置为不可变(immutable),这对于大规模集群有显著的性能优势------kubelet 不需要持续监控 ConfigMap 的变化:
bash
apiVersion: v1
kind: ConfigMap
metadata:
name: immutable-config
immutable: true
data:
KEY: "value"
一旦创建为 immutable,就不能再修改其内容。如果需要变更,只能删除旧 ConfigMap 并创建新的。
六、ConfigMap vs Docker Compose 配置管理
回顾第 13 篇,Compose 通过 .env 文件和环境变量实现配置管理。对比一下:
七、命令速查表
八、本篇总结
-
ConfigMap 的本质:K8s 原生的非敏感配置管理 API 对象,实现配置与镜像的解耦。
-
创建方式:字面量、文件、目录、YAML。YAML 是生产环境的推荐方式。
-
注入方式:环境变量(适合简单配置)、文件挂载(适合复杂配置文件,支持热更新)、命令行参数(适合启动参数)。
-
更新策略:环境变量注入需重启 Pod,文件挂载支持自动同步(kubelet 定期刷新),不可变 ConfigMap 可提升集群性能。
-
与 Compose 的区别:ConfigMap 是 K8s 的独立资源对象,支持多 Pod 共享、版本追踪、热更新,是配置管理从"文件驱动"到"API 驱动"的升级。
本篇解决了非敏感配置的管理问题。但对于密码、API 密钥、TLS 证书等敏感信息,明文 ConfigMap 显然不够安全。下一篇------第 33 篇:敏感信息管理:Secret 与安全实践,我们将学习 K8s 的 Secret 对象,以及如何使用 Sealed Secrets 实现 GitOps 安全的密钥管理。
想了解更多还可以去各个平台搜索「IT策士」,一起升级 IT 思维 !