概述

通常一个微服务,里面会有一堆配置:

  • 数据库地址
  • 日志级别
  • 第三方 API 密钥(先忽略安全问题)
  • 功能开关

一开始,你把它们写在代码里,或者打包进镜像。
但很快发现:

  • 想改个超时时间?得重新构建镜像、重新部署!
  • 测试环境和生产环境配置混在一起
  • 配置散落在各个服务中,难以统一管理

这就像每次换 Wi-Fi 密码,都要重装手机系统——太荒谬了!

在 Kubernetes 中,这个问题有优雅的解法:ConfigMap

什么是 ConfigMap

ConfigMap 是 Kubernetes 的一种资源对象,用于:

  • 存储非敏感的配置数据(如字符串、配置文件)
  • 将配置与容器镜像解耦
  • 支持动态更新(部分场景)

配置不是代码的一部分,而是运行时注入的参数

ConfigMap 中的数据可以以两种方式注入到 Pod:

  1. 环境变量(Environment Variables)
  2. 挂载为文件(Volume Mount)

为什么不用直接写在 YAML 里

如果直接在 Deployment 里写 env 会怎样?

env:
  - name: DB_HOST
    value: "prod-db.example.com"

这确实可行,但问题在于:

  • 配置无法复用(多个服务要重复写)
  • 修改配置需改 Deployment,触发滚动更新
  • 无法用版本控制单独管理配置

ConfigMap 让配置独立存在,像“配置中心”的轻量版

创建 ConfigMap 的三种方式

方式 1:从字面值创建(适合少量键值对)

kubectl create configmap app-config \
  --from-literal=log_level=info \
  --from-literal=db_host=mysql.default.svc.cluster.local \
  --from-literal=feature_new_ui=true

查看内容:

kubectl get configmap app-config -o yaml

输出片段:

data:
  log_level: info
  db_host: mysql.default.svc.cluster.local
  feature_new_ui: "true"

方式 2:从文件创建(适合配置文件)

假设你有一个 app.properties

# app.properties
server.port=8080
spring.datasource.url=jdbc:mysql://db:3306/mydb
logging.level.root=INFO

创建 ConfigMap:

kubectl create configmap app-config-from-file \
  --from-file=app.properties

注意:文件名会成为 ConfigMap 中的 key,内容是 value。

方式 3:从 YAML 文件定义(推荐)

创建 configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-app-config
data:
  # 键值对形式
  log_level: "debug"
  db_host: "mysql.prod.svc"
  
  # 多行配置文件(用 | 保留格式)
  nginx.conf: |
    server {
        listen 80;
        location / {
            root /usr/share/nginx/html;
        }
    }
  
  app.json: |
    {
      "timeout": 5000,
      "retry": 3
    }

应用:

kubectl apply -f configmap.yaml

这种方式支持复杂结构,且可纳入 Git 版本管理

在 Pod 中使用 ConfigMap

场景 1:作为环境变量注入

# deployment-env.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
      - name: app
        image: my-app:1.0
        envFrom:
        - configMapRef:
            name: my-app-config   # 引用上面的 ConfigMap

Pod 启动后,容器内会自动拥有这些环境变量:

echo $log_level    # 输出: debug
echo $db_host      # 输出: mysql.prod.svc

注意:如果 ConfigMap 更新,已运行的 Pod 不会自动更新环境变量!需重建 Pod。

场景 2:挂载为配置文件(推荐用于复杂配置)

# deployment-volume.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
spec:
  template:
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        volumeMounts:
        - name: config-volume
          mountPath: /etc/nginx/conf.d  # 挂载到容器目录
      volumes:
      - name: config-volume
        configMap:
          name: my-app-config
          items:
          - key: nginx.conf       # ConfigMap 中的 key
            path: default.conf    # 在挂载目录中的文件名

效果:

  • 容器内的 /etc/nginx/conf.d/default.conf 内容 = ConfigMap 中 nginx.conf 的值
  • Nginx 启动时会自动加载这个配置

优势:配置以文件形式存在,应用无需改造!

实战:部署一个带配置的 Node.js 应用

Step 1:准备配置

app-config.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: nodejs-config
data:
  PORT: "3000"
  DB_URL: "mongodb://mongo:27017/mydb"
  LOG_LEVEL: "info"

Step 2:编写 Deployment(使用环境变量)

nodejs-deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nodejs-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nodejs
  template:
    metadata:
      labels:
        app: nodejs
    spec:
      containers:
      - name: app
        image: node:18-alpine
        command: ["sh", "-c"]
        args:
          - |
            echo "Server starting on port $$PORT";
            while true; do echo "Ping DB: $$DB_URL"; sleep 10; done
        envFrom:
        - configMapRef:
            name: nodejs-config

Step 3:部署并验证

kubectl apply -f app-config.yaml
kubectl apply -f nodejs-deploy.yaml

# 查看日志
kubectl logs -l app=nodejs

输出:

Server starting on port 3000
Ping DB: mongodb://mongo:27017/mydb
...

配置成功注入

ConfigMap vs Secret:怎么选

特性 ConfigMap Secret
存储内容 非敏感配置(如端口、开关) 敏感信息(密码、密钥、Token)
存储格式 明文(Base64 可读) Base64 编码(仍需配合 RBAC)
使用方式 几乎相同(env / volume) 几乎相同
安全建议 ❌ 不要存密码! ✅ 用 Secret + 加密插件(如 Sealed Secrets)

重要:数据库密码、API Key 等绝不能放在 ConfigMap 中

ConfigMap 能热更新吗

  • 挂载为文件:✅ 是!Kubelet 会定期同步(默认每秒检查),文件内容会自动更新(但应用需支持 reload)
  • 作为环境变量:❌ 否!Pod 创建时注入,之后不会变

提示:Nginx、Spring Boot 等支持配置重载的应用,适合用 Volume 方式。

最佳实践

建议 说明
✅ 用 YAML 文件管理 ConfigMap 便于 Git 版本控制
✅ 按应用/环境命名(如 user-svc-prod-config 避免冲突
✅ 复杂配置用 Volume 挂载 比环境变量更清晰
❌ 不要存敏感信息 用 Secret 代替
✅ 配合 CI/CD 自动更新 实现配置即代码(Configuration as Code)

总结

问题 ConfigMap 解法
配置写死在镜像里? ✅ 外部化,独立管理
多环境配置混乱? ✅ 创建 dev-config / prod-config
改配置要重打包? ✅ 只需更新 ConfigMap(部分场景自动生效)
配置无法复用? ✅ 多个 Pod 引用同一个 ConfigMap
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐