K8S - ConfigMap 与 Secret - 应用配置与敏感信息管理
一、引言
在 Kubernetes 集群中,应用通常需要依赖外部配置或敏感信息(如数据库连接字符串、API 密钥等)。直接将这些信息硬编码在容器镜像中既不灵活,也存在安全风险。为了解决这一问题,Kubernetes 提供了 ConfigMap和 Secret机制,实现配置与敏感信息的解耦管理。
二、原理
2.1 ConfigMap
ConfigMap 用于存储非敏感的配置信息,例如应用的环境变量、配置文件等。它支持多种数据格式,如键值对、完整的配置文件等。
核心能力:
• 以键值对方式存储配置信息。
• 可通过环境变量、命令参数、挂载文件等方式提供给 Pod。
• 允许动态更新,减少容器重启需求。
数据结构示例:
apiVersion: v1
kind: ConfigMap
metadata:name: app-confignamespace: default
data:APP_MODE: "production"LOG_LEVEL: "info"config.json: |{"cacheSize": 100,"retry": true}
2.2 Secret
Secret 用于存储敏感信息,例如密码、密钥和证书等。它与 ConfigMap 类似,但数据默认以 Base64 编码存储,并支持更严格的访问控制策略。
核心能力:
• 以 Base64 编码存储敏感信息。
• 通过环境变量或挂载文件的方式提供给 Pod。
• 支持 RBAC 访问控制,提升安全性。
数据结构示例:
apiVersion: v1
kind: Secret
metadata:name: db-credentialsnamespace: default
type: Opaque
data:username: dXNlcm5hbWU= # "username" 的 Base64 编码password: cGFzc3dvcmQ= # "password" 的 Base64 编码
三、实战示例
3.1 ConfigMap 管理环境变量
步骤 1:创建 ConfigMap,提供配置数据
方法1:直接创建 ConfigMap 资源
kubectl create configmap app-config \--namespace=config-demo \--from-literal=APP_ENV=production \--from-literal=APP_LOG_LEVEL=info \--from-file=config.json=config.json
方法2: 创建 app-config.yaml 并 通过apply 创建 ConfigMap 资源。
# app-config.yaml
apiVersion: v1 # API 版本
kind: ConfigMap # 声明资源类型为 ConfigMap
metadata:name: app-config # ConfigMap 的名称namespace: config-demo # 所属命名空间,确保与使用方一致
data:APP_ENV: "production" # 配置项:表示运行环境APP_LOG_LEVEL: "info" # 配置项:日志级别config.json: | # 复杂数据:完整 JSON 配置文件{"cache_size": "100MB","max_connections": 500}
• data字段支持键值对或多行文本(如配置文件)。
• 每个键在挂载时可以单独指定,也可以整体注入为文件。
kubectl apply -f app-config.yaml # 创建 ConfigMap 资源
步骤 2:在pod 中使用 ConfigMap
通过环境变量和文件挂载使用 ConfigMap
# app-pod.yamlapiVersion: v1
kind: Pod
metadata:name: app-podnamespace: config-demo
spec:containers:- name: app-containerimage: nginx:alpine # 使用轻量级 nginx 镜像env: # 通过环境变量使用 ConfigMap- name: ENVIRONMENT # 容器环境变量名 ENVIRONMENTvalueFrom: # 从 ConfigMap 中注入值configMapKeyRef:name: app-config # 引用名为 app-config 的 ConfigMapkey: APP_ENV # 取其中的 APP_ENV 键对应的值optional: true # 若 APP_ENV 不存在,Pod 不报错,值为空- name: LOG_LEVEL # 容器环境变量名 LOG_LEVELvalueFrom:configMapKeyRef:name: app-configkey: APP_LOG_LEVELoptional: true # 若 APP_LOG_LEVEL 不存在,Pod 不报错,值为空volumeMounts: # 通过挂载文件使用ConfigMap- name: config-volume # 挂载名为 config-volume 的 VolumemountPath: /etc/app-config # 挂载路径,作为配置文件目录volumes: # 定义卷 - name: config-volume # 定义一个名为 config-volume 的 VolumeconfigMap:name: app-config # 引用的 ConfigMap 名称items:- key: config.json # 仅挂载 configMap 中的 config.json 键path: config.json # 文件名为 config.json
参数关系说明:
• env.valueFrom.configMapKeyRef:单个键值注入为环境变量。
• volumes.configMap.items+ volumeMounts:以文件形式挂载部分或全部键。上例只挂载 key:config.json
• optional: true 提升部署容错性,避免因 ConfigMap 键缺失导致 Pod 启动失败。
提交pod 应用到集群
kubectl apply -f app-pod.yaml # 提交 Pod 定义到集群
步骤 3:验证 ConfigMap 注入效果
1.验证环境变量注入
kubectl exec -n config-demo app-pod -- env | grep -E 'ENVIRONMENT|LOG_LEVEL'
# 输出:
# ENVIRONMENT=production
# LOG_LEVEL=info
验证目标:
• 确认 APP_ENV和 APP_LOG_LEVEL从 ConfigMap 成功注入为容器环境变量。
• 环境变量 ENVIRONMENT和 LOG_LEVEL的值与 ConfigMap 中定义的 APP_ENV和 APP_LOG_LEVEL一致。
2.验证配置文件挂载
# 查看挂载的配置文件内容kubectl exec -n config-demo app-pod -- cat /etc/app-config/config.json# 预期输出 config.json 内容:
# {
# "cache_size": "100MB",
# "max_connections": 500
# }
验证目标:
• 确认 config.json文件从 ConfigMap 挂载到容器路径 /etc/app-config/config.json。
• 文件内容与 ConfigMap 中定义的 JSON 完全一致(包括格式和缩进)。
总结:
1.ConfigMap → Volume → Pod 挂载路径的映射关系:
┌──────────────────────────────┐
│ ConfigMap │
│ 名称:app-config │
│ 键值: │
│ - config.json │
└────────────┬─────────────────┘│ 引用▼
┌──────────────────────────────┐
│ Volume │
│ 名称:config-volume │
│ 来源:ConfigMap: app-config │
│ items: │
│ - key: config.json │
│ path: config.json │
└────────────┬─────────────────┘│ 挂载▼
┌──────────────────────────────┐
│ Pod │
│ 容器挂载目录: │
│ /etc/app-config/config.json ←─ 映射到容器内的路径
└──────────────────────────────┘
说明:
• ConfigMap提供配置数据(如 config.json)。
• Volume引用 ConfigMap,并指定要挂载的键和目标文件名。
• Pod中的容器通过 volumeMounts把这个文件挂载到指定路径 /etc/app-config/config.json。
2.ConfigMap 到 Pod 的挂载映射关系
ConfigMap (app-config) Pod (app-pod)
├── data ├── env
│ ├── APP_ENV → ENVIRONMENT │ ├── ENVIRONMENT=production
│ └── APP_LOG_LEVEL → LOG_LEVEL │ └── LOG_LEVEL=info
└── config.json └── volumeMounts└── /etc/app-config/config.json
3.关键参数对比表
3.2 Secret 管理敏感信息
步骤 1:创建 Secret
echo -n "db-password-123" | base64
# 输出:ZGItcGFzc3dvcmQtMTIz
# db-secret.yaml
apiVersion: v1
kind: Secret
metadata:name: db-secretnamespace: config-demo
type: Opaque # 通用类型
data:password: ZGItcGFzc3dvcmQtMTIz # Base64 编码后的密码
注意:
• data字段中的值必须是 Base64 编码后的字符串。
• Secret 在 Kubernetes 中并不会进行加密,而是防止明文暴露(如命令行显示),但仍建议结合 Kubernetes 的加密功能进一步增强安全性。
步骤 2:在 Pod 中使用 Secret
配置 db-pod.yaml文件,使 Pod 使用 Secret 数据,注入环境变量并将 Secret 挂载为文件:
apiVersion: v1
kind: Pod
metadata:name: db-podnamespace: config-demo
spec:containers:- name: db-clientimage: busyboxcommand: ["sh", "-c", "sleep 3600"] # 保持容器运行env:- name: DB_PASSWORD # 设置环境变量valueFrom:secretKeyRef:name: db-secret # 引用 Secret 名称key: password # 指定 Secret 中的密码字段volumeMounts:- name: secret-volumemountPath: /etc/secrets # 将 Secret 挂载到指定路径readOnly: true # 只读挂载,增强安全性volumes:- name: secret-volumesecret:secretName: db-secret # 引用 Secret 名称
参数关系说明:
• env.valueFrom.secretKeyRef:将 Secret 中的值注入为环境变量,Kubernetes 会自动解码 Base64 值。
• volumes.secret.secretName:将 Secret 挂载到容器文件系统中作为文件。
步骤 3:验证
1.验证环境变量:
kubectl exec -n config-demo db-pod -- env | grep DB_PASSWORD
# 输出:DB_PASSWORD=db-password-123
2.验证文件挂载:
kubectl exec -n config-demo db-pod -- cat /etc/secrets/password
# 输出:db-password-123
3.验证 Secret 的内容:
kubectl get secret -n config-demo db-secret -o jsonpath='{.data.password}' | base64 -d# 输出:db-password-123
总结:
1.Secret → Volume → Pod 挂载路径的映射关系
┌──────────────────────────────┐
│ Secret │
│ 名称:db-secret │
│ 键值: │
│ - password │
└────────────┬─────────────────┘│ 引用▼
┌──────────────────────────────┐
│ Volume │
│ 名称:secret-volume │
│ 来源:Secret: db-secret │
└────────────┬─────────────────┘│ 挂载▼
┌──────────────────────────────┐
│ Pod │
│ 容器挂载目录: │
│ /etc/secrets/password ←─ 映射到容器内的路径
└──────────────────────────────┘
说明:
• Secret:提供敏感信息(如密码)存储在 Secret中。
• Volume:将 Secret挂载为文件,确保 Secret的值以文件形式提供给容器。
• Pod:通过 volumeMounts将文件挂载到容器内的指定路径,容器可以读取该文件来获取敏感数据。
2.Secret 到 Pod 的映射关系
Secret (db-secret) Pod (db-pod)
├── data ├── env
│ ├── password → DB_PASSWORD │ ├── DB_PASSWORD=db-password-123
└── secret └── volumeMounts└── /etc/secrets/password
总结:
1.通过环境变量传递:
• 通过 env.valueFrom.secretKeyRef把 Secret的内容注入到容器的环境变量中。这样,容器可以像普通环境变量一样使用 DB_PASSWORD(从 db-secret中提取)作为密码进行访问。
2.通过文件挂载传递:
• 使用 volumes.secret.secretName把 Secret的内容挂载为文件,并通过 volumeMounts将其挂载到容器的文件系统中。容器可以读取 /etc/secrets/password文件中的内容来获取密码。
3.比较 Secret 与 ConfigMap:
• ConfigMap:主要用于配置数据,通常是非敏感的文本数据(如 JSON、YAML 配置文件)。你可以选择将其通过环境变量传递或挂载文件的方式传递。
• Secret:用于存储敏感信息(如密码、密钥)。可以通过环境变量或文件的形式传递,但需要注意安全性,尤其是避免泄漏。
3.3 动态更新 ConfigMap
步骤 1:编辑 ConfigMap 内容
使用 kubectl edit命令修改 ConfigMap 的内容。这里,我们将 APP_LOG_LEVEL更新为 debug:
kubectl edit configmap -n config-demo app-config
在编辑器中,将 APP_LOG_LEVEL的值更改为 debug:data:APP_ENV: "production"APP_LOG_LEVEL: "debug" # 修改后的值config.json: |{"cache_size": "100MB","max_connections": 500}
步骤 2:使变更生效
ConfigMap 更新后,需要使其变更生效。可以通过以下两种方法:
1.方法 1:重启 Pod
通过删除并重新创建 Pod,使其重新加载新的 ConfigMap:
kubectl delete pod -n config-demo app-pod && kubectl apply -f app-pod.yaml
2.方法 2:应用自身支持热加载
如果应用支持热加载(例如 nginx),则可以通过发送信号使应用重新加载配置:
kubectl exec -n config-demo app-pod -- nginx -s reload
步骤 3:验证更新
1.验证环境变量:
通过检查容器环境变量,确保新的日志级别已经生效:
kubectl exec -n config-demo app-pod -- env | grep LOG_LEVEL
# 输出:LOG_LEVEL=debug
这样,通过动态更新 ConfigMap,我们能够无缝地修改配置,并且通过 Pod 的重启或应用的热加载特性使变更生效。
四、结论
4.1 核心重点
1.ConfigMap 的核心价值
• 非敏感配置管理:支持环境变量注入、配置文件挂载,适用于动态配置(如日志级别、功能开关)。
• 动态更新能力:通过 Pod 重启或应用热加载实现配置更新,无需重建镜像。
最佳实践:
• 使用 optional: true避免因键缺失导致 Pod 启动失败。
• 通过 subPath挂载单个文件,防止目录覆盖。
2.Secret 的安全管理
敏感信息保护:默认 Base64 编码(非加密),需结合 Kubernetes 静态加密与 RBAC 策略。
生产级建议:
• 避免通过环境变量传递 Secret(可能被日志记录),优先使用文件挂载。
• 定期轮换敏感数据(如密码、Token)。
3.ConfigMap 与 Secret 的差异