K8s 配置与密钥:ConfigMap/Secret 实战

在做 Kubernetes 落地时,最容易被低估、却又最容易踩坑的就是配置与密钥管理。ConfigMap 负责把业务配置从容器镜像里剥离出来,Secret 则专门存放密码、Token、证书等敏感信息。把两者用对,既能让同一份镜像跑在开发、测试、生产多个环境,又能避免把密钥硬编码进代码仓库引发泄漏。本文用可复用的命令与清单,带你把 ConfigMap 与 Secret 真正用稳。

一、ConfigMap:把配置从镜像里拆出来

容器镜像应当只承载程序与默认配置,环境相关的参数(日志级别、连接地址、特性开关)交给 ConfigMap 注入。这样镜像一次构建、处处运行,配置变更也无需重新打镜像。

1.1 用 –from-literal 快速创建

kubectl create configmap app-config \
  --from-literal=LOG_LEVEL=info \
  --from-literal=MAX_CONNECTIONS=200

1.2 用文件或目录批量导入

# 目录结构:configs/application.yaml、configs/logback.xml
kubectl create configmap app-config --from-file=configs/
kubectl get configmap app-config -o yaml

1.3 用 YAML 清单声明(推荐,可进 Git)

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  LOG_LEVEL: "info"
  application.yaml: |
    server:
      port: 8080
    spring:
      datasource:
        url: jdbc:mysql://db:3306/demo

二、把 ConfigMap 注入到 Pod

2.1 作为环境变量注入

env:
- name: LOG_LEVEL
  valueFrom:
    configMapKeyRef:
      name: app-config
      key: LOG_LEVEL

2.2 作为 Volume 挂载(支持热更新的关键)

volumes:
- name: config
  configMap:
    name: app-config
containers:
- name: app
  volumeMounts:
  - name: config
    mountPath: /etc/app/config

2.3 配置热更新:哪些会生效、哪些不会

注入方式修改 ConfigMap 后是否需重启
环境变量Pod 内不会自动更新是(需重建 Pod)
Volume 挂载kubelet 约 1 分钟内更新文件否(应用需自行 reload)
subPath 挂载不更新是

经验法则:会随时调整的配置(如日志级别、特性开关)优先用 Volume 挂载;应用要监听文件变化并重新加载,才能真正做到不停机生效。

三、Secret:敏感信息的正确存放

3.1 Opaque 类型与 base64 编解码

# 明文不要进 Git,创建时直接由 kubectl 编码
kubectl create secret generic db-secret \
  --from-literal=username=admin \
  --from-literal=password='S3cr3t!P@ss'

# 取出时只是 base64 解码,并非“解密”
kubectl get secret db-secret -o jsonpath='{.data.password}' | base64 -d
echo

注意:Secret 默认只是 base64 编码,任何能读 Etcd 或 Pod 的人都能解码。它解决的是“不把密钥写进镜像和 Git”,而不是“加密存储”——加密要见第五节。

3.2 环境变量还是挂载文件?安全对比

维度环境变量挂载文件
进程列表可见是(ps 可见)否
子进程继承是否
应用改造量小需读文件路径
推荐场景非极度敏感配置密码 / 证书等敏感信息

3.3 dockerconfigjson、tls 等内置类型

kubectl create secret docker-registry regcred \
  --docker-server=registry.example.com \
  --docker-username=admin \
  --docker-password='...' \
  --docker-email=dev@example.com

# Pod 中引用私有仓库镜像
# imagePullSecrets:
# - name: regcred

四、与 Helm、Kustomize、GitOps 的配合

在真实工程里,ConfigMap/Secret 通常不直接手写,而是由渲染工具生成。Kustomize 声明式配置 可以用 configMapGenerator 自动生成带哈希后缀的 ConfigMap,配置一变就触发滚动更新;Helm 打包发布 则把配置收口到 values.yaml。

# values.yaml
config:
  logLevel: info
  maxConnections: 200

# templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: { "{ .Release.Name }" }-config
data:
  LOG_LEVEL: { "{ .Values.config.logLevel | quote }" }

五、安全红线:Secret 不是加密存储

5.1 启用 Secret 静态加密(EncryptionConfiguration)

# kube-apiserver 启动参数
--encryption-provider-config=/etc/kubernetes/encryption-config.yaml

# encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources: ["secrets"]
  providers:
  - aescbc:
      keys:
      - name: key1
        secret: <base64 编码的 32 字节密钥>

5.2 用 External Secrets 同步云厂商密钥

不要把云厂商的密钥手动 copy 进集群。External Secrets Operator 能把 AWS Secrets Manager、阿里云 KMS、Vault 等的密钥自动同步为 K8s Secret,密钥轮换也由平台侧驱动,更安全也更省心。

5.3 RBAC 最小权限

谁能 get secret,谁就能拿到全部敏感信息。务必用 Kubernetes RBAC 最小权限 收敛到只给真正需要的 ServiceAccount,并配合审计日志定期检查。

六、常见排错清单

现象可能原因排查命令
Pod 启动报 InvalidArgumentconfigMapKeyRef.key 不存在kubectl describe cm app-config
配置改了不生效用了环境变量注入重启 Pod 或改 Volume 挂载
Secret 取不到值key 名称大小写 / 空格kubectl get secret -o yaml
挂载后目录被整体覆盖mountPath 指向已有目录用 subPath 或独立子目录
kubectl describe configmap app-config
kubectl get configmap app-config -o yaml
kubectl exec app-pod -- env | grep LOG_LEVEL
kubectl rollout restart deployment app   # 环境变量方式需重启才生效

七、落地检查清单

检查项是否做到
密钥不进 Git、不进镜像✅
启用 Secret 静态加密✅
RBAC 收敛到最小权限✅
用 External Secrets 管理云密钥✅
配置变更走 GitOps 评审✅

把 ConfigMap 与 Secret 用顺手之后,配合 GitHub Actions 流水线、Docker 编排 与 VS Code 远程开发,你的 Kubernetes 交付链路就既有弹性又足够安全。存储侧若需要持久化配置与有状态服务,可以参考 Longhorn 分布式存储 的方案。

八、ConfigMap 与 Secret 的选型决策

很多团队一开始会把所有配置都塞进 ConfigMap,或反过来把数据库地址写死在代码里。一个实用的判断标准是:会变且非敏感的放 ConfigMap,会变且敏感的放 Secret,构建期就确定、几乎不变的编译参数才进镜像。这样镜像保持纯净,环境差异完全由配置驱动。

内容放哪里理由
日志级别、功能开关ConfigMap常变、非敏感,适合热更新
数据库密码、API TokenSecret敏感,需加密与权限隔离
镜像内默认配置镜像构建期确定,少变动
跨集群共享的密钥External Secrets统一来源,避免手工同步

8.1 什么时候该上配置中心(Nacos / Apollo)

ConfigMap 适合“部署时确定”的配置;如果你的场景需要“运行时动态推送、灰度发布、监听回调”,配置中心更合适。业界常见组合是:基础环境配置用 ConfigMap 注入,业务动态参数走 Nacos/Apollo,二者分层,互不打架,既保证了不可变基础设施的纯粹,又保留了运行时灵活性。

九、一个完整可运行的 Spring Boot 例子

下面这个最小例子把数据库地址放 ConfigMap(环境变量),把密码放 Secret(挂载文件)。Spring Boot 通过标准环境变量与文件读取,无需改代码即可在不同环境间切换,真正做到了“一套镜像、多环境运行”。

# application.yaml 只写占位,真实值来自环境变量
spring:
  datasource:
    url: ${DB_URL}
    username: ${DB_USER}
    password: ${DB_PASSWORD}

# Secret 挂载为文件后,用文件内容作为密码
# spring.datasource.password=$(cat /etc/secret/db/password)

挂载 Secret 文件后,应用读取 /etc/secret/db/password 的内容即可,密码不出现在环境变量里,ps 和 /proc 都看不到,安全性明显高于环境变量注入。

十、不可变 Secret 与多环境隔离

10.1 把 Secret 设为 immutable

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
immutable: true
type: Opaque
data:
  password: UzNjcjN0IVBAc3M=

immutable: true 之后 Secret 不能再被原地修改,只能删除重建。这能防止运维手滑覆盖线上密钥,也减少了 API Server 的 watch 压力;配合 GitOps,任何密钥变更都会留下可追溯的提交记录。

10.2 多环境用 namespace 与 overlay 隔离

开发、测试、生产应当放在不同 namespace,配合 Kustomize 的 overlay 为每个环境生成独立的 ConfigMap/Secret,避免一套配置误用到生产环境。再结合 ArgoCD / GitOps 流水线,配置变更可评审、可回滚,安全与效率兼得。

十一、四个常见反模式

最后提醒几个高频踩坑:一是把 Secret 当成“加密存储”,其实它默认只是 base64 编码;二是把几百 KB 的证书或模型配置塞进 ConfigMap(单条 data 上限约 1MB,且会放大 Etcd 压力);三是在 CI 日志里明文打印 Secret 用于调试,结果密钥直接进了日志系统;四是所有应用都堆在 default namespace,彼此无任何隔离。避开这四点,配置管理就稳了一大半。

十二、ConfigMap 的体积与 Etcd 注意事项

单个 ConfigMap 的 data 总大小建议控制在 1MB 以内,过大的配置会放大 Etcd 的存储与 watch 负担,也可能拖慢 kube-apiserver 的响应。大文件(如模型权重、超大证书链、整库 SQL)应当改走对象存储或专用存储卷,而不是塞进 ConfigMap。当配置确实很大时,优先考虑把内容放到对象存储,再用 Init Container 下载到本地空目录卷,既绕开体积限制,也避免了把大对象常驻 Etcd。

上一篇 CSS 层叠上下文与 z-index 实战:搞懂元素层级
下一篇 Java 动态代理实战:JDK 与 CGLIB 对比
最新评论
Docker 网络模式详解:bridge/host 生产选型 - FSData
Docker 网络模式详解:bridge/host 生产选型 - FSData
8月20日
[…] 注意最后那条:把端口绑定到 127.0.0.1,再由宿主机上的 Nginx 反代进来,比直接 -p 80:80 暴露安全得多,也方便统一做
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
8月20日
[…] Pinia 的工程化用法,可以参考我们之前的实战文章 《Vue3 组合式 API + Pinia:状态管理从入门到实战》,那里覆盖了 Sto
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
8月19日
[…] 状态,点一下就能起停容器,配合我们讲过的 Docker Compose 编排 […]
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
8月19日
[…] 缓存三大坑的本质都是”缓存失效导致请求穿透到数据库”。记住口诀:穿透用布隆、击穿用锁、雪崩用错峰。配合合理的过期策略
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
8月19日
[…] Docker 镜像部署。结合我们之前写的 Docker Compose 一键编排实战,可以在 CI […]