第32篇 k8s 之 配置管理:ConfigMap 详解

IT策士 10余年一线大厂经验,专注 IT 思维、架构、职场进阶。我会在各个平台持续发布最新文章,助你少走弯路。


在之前的文章中,我们通过环境变量向容器传递配置------REDIS_HOST=redis-serviceFLASK_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 diffkubectl 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.configMapRefflask-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 思维 !

相关推荐
人道领域1 小时前
Windows 保姆级 Docker 安装教程(WSL2 版),一篇入门docker
windows·docker·容器
lbb 小魔仙1 小时前
Docker一键部署 EasyNode 面板,随时随地可视化管理服务器
服务器·docker·容器
能摆一天是一天2 小时前
windows docker 部署openfire
运维·docker·容器
IT策士2 小时前
第33篇 k8s 之 敏感信息管理:Secret 与安全实践
安全·容器·kubernetes
阿里云云原生2 小时前
告别 30 分钟故障演练!ChaosBlade AI 让混沌工程像“聊天”一样简单
人工智能·阿里云·云原生·chaosblade
IT策士2 小时前
第30篇 k8s之Ingress 基础:域名路由与 Ingress Controller
云原生·容器·kubernetes
Lumbrologist10 小时前
【零基础部署】Docker 部署 CrewAI 多 Agent 编排框架保姆级教程
运维·docker·容器
Dongwoo Jeong15 小时前
微服务架构(MSA)是如何诞生的?
微服务·云原生·架构
半旧夜夏15 小时前
【保姆级】微服务组件环境搭建(Docker Compose版)
java·linux·spring cloud·微服务·云原生·容器