CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Kubernetes 入门/课时/ConfigMap 与 Secret
RawBlame
课时目录12 节

Kubernetes 入门

  1. 01Kubernetes 是什么
  2. 02核心概念与架构
  3. 03本地集群与 kubectl
  4. 04Pod
  5. 05Deployment 与滚动更新
  6. 06Service 与网络
  7. 07ConfigMap 与 Secret
  8. 08存储卷
  9. 09Ingress 入口
  10. 10资源配额与 HPA
  11. 11RBAC 与安全基础
  12. 12综合练习:部署 backend

ConfigMap 与 Secret

配置注入、敏感信息管理。

30 分钟

ConfigMap 与 Secret

这一课你将能做到

  1. 用清单方式创建 ConfigMap 与 Secret,并以环境变量注入到 Pod/Deployment
  2. 说清「配置烤进镜像」与「配置外置」的利弊,对照 Compose 的 environment/env_file 建立映射
  3. 知道 Secret 默认只是 Base64 编码不是加密,说出生产环境的三层加固手段

为什么要学

镜像应该「一次构建、处处运行」:本站 backend 的 SPRING_PROFILES_ACTIVE、DB_HOST、REDIS_HOST、数据库密码,如果写死在 Dockerfile 或 application.yml 里,每个环境就得打一个镜像——构建产物爆炸,泄密风险也随镜像层扩散。

K8s 的解法与 Compose 的 environment/env_file 同构:ConfigMap 放非敏感配置,Secret 放敏感数据,两者都注入到 Pod。Spring Boot 恰好天然读环境变量(SPRING_DATASOURCE_URL 这类宽松绑定),所以「本地 .env / Compose environment / K8s ConfigMap+Secret」可以共用同一套键名约定——这是本课最实际的工程价值。

先建立图像

镜像(只读配方,不含环境差异)
   +
ConfigMap(普通配置) + Secret(敏感信息)
   ↓ 注入
Pod 里的进程读到环境变量 / 配置文件

注入两种方式:
  env / envFrom  → 环境变量(Spring Boot 最友好)
  volumeMount    → 文件(适合整份 application.yml、证书)
ConfigMapSecret
用途普通配置、开关、地址口令、令牌、证书材料
etcd 中的形态明文Base64 编码(默认可解码,非加密)
大小限制约 1MiB约 1MiB
谁能读RBAC 控制RBAC 控制(应更严)

人话:Secret 是「别随手 cat 到聊天群里的类型」,不是保险箱本身。

跟着做

步骤 1:创建本站 backend 的 ConfigMap

cm-backend.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: backend-config
data:
  SPRING_PROFILES_ACTIVE: "prod"
  DB_HOST: "mysql"          # 集群内 Service 名或集群外地址
  REDIS_HOST: "redis"
kubectl apply -f cm-backend.yaml
kubectl get configmap backend-config -o yaml

命令式快捷方式(冒烟用,正式环境仍推荐清单进 Git):

kubectl create configmap quick --from-literal=KEY1=v1 --from-literal=KEY2=v2

步骤 2:创建 Secret

secret-db.yaml(用 stringData 免手算 Base64):

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
stringData:
  DB_PASSWORD: "change-me-demo"
kubectl apply -f secret-db.yaml kubectl get secret db-secret -o yaml

注意观察:apply 后 stringData 变成了 data 里的 Base64 字符串(如 Y2hhbmdlLW1lLWRlbW8=)。命令式等价:

kubectl create secret generic db-secret --from-literal=DB_PASSWORD=change-me-demo

铁律:含真实口令的 YAML 绝不进 Git;仓库只放模板或用 CI 注入。

步骤 3:注入到 Deployment

在上一课 deploy-backend.yaml 的容器段追加(本例仍用 nginx 占位演示注入):

    spec:
      containers:
        - name: api
          image: nginx:1.27-alpine
          envFrom:                      # 整表注入:ConfigMap 所有键
            - configMapRef:
                name: backend-config
          env:                          # 单键注入:更精确、可改名
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-secret
                  key: DB_PASSWORD
kubectl apply -f deploy-backend.yaml
kubectl exec deploy/backend -- printenv SPRING_PROFILES_ACTIVE
kubectl exec deploy/backend -- printenv DB_HOST

(deploy/backend 是「该 Deployment 第一个 Pod」的缩写,比复制 Pod 名方便。)应打印出注入的值。习惯:日志与 printenv 输出不要贴到公开场合,环境变量里的口令会随截图泄露。

步骤 4:文件挂载方式(适合整份配置文件)

把整份 application.yml 挂进容器:

    spec:
      containers:
        - name: api
          image: your-registry/backend:1.0.0
          volumeMounts:
            - name: app-config
              mountPath: /app/config        # Spring Boot 默认会读 ./config/
              readOnly: true
      volumes:
        - name: app-config
          configMap:
            name: backend-file-config       # 该 CM 的 data 键是文件名

对应 ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: backend-file-config
data:
  application-prod.yml: |
    server:
      port: 8080
    spring:
      datasource:
        url: jdbc:mysql://mysql:3306/coderoadmap

步骤 5:体验「改配置 ≠ 生效」

改 cm-backend.yaml 里的 SPRING_PROFILES_ACTIVE 为 prod-v2 并 apply,然后:

kubectl exec deploy/backend -- printenv SPRING_PROFILES_ACTIVE

多数情况仍显示旧值——以环境变量注入的配置不会热更新,需要滚动重启加载新值:

kubectl rollout restart deployment/backend
kubectl rollout status deployment/backend

再 printenv 应看到新值。(volume 挂载的文件会由 kubelet 异步刷新,但应用是否重读取决于程序本身;入门统一按「改配置 = 发版动作」处理最安全。)

步骤 6:亲手验证「Base64 不是加密」

kubectl get secret db-secret -o jsonpath='{.data.DB_PASSWORD}'

把输出粘到 PowerShell 解码:

[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('Y2hhbmdlLW1lLWRlbW8='))

瞬间还原明文——这就是「编码 ≠ 加密」的直观证据。生产加固三层:① RBAC 收紧 get secrets 权限(第 11 课);② etcd 加密落盘(集群级配置);③ 用 Vault/External Secrets/Sealed Secrets 管理真实密钥。

讲清楚要点

  1. 镜像不可变交付,环境差异必须外置:同一个 backend 镜像从 dev 跑到 prod,变的只有 ConfigMap/Secret——这是十二要素应用(12-Factor)的配置原则。
  2. envFrom 图省事,env 图精确:envFrom 整表注入会把 CM 里所有键灌进进程环境,键名脏了会污染环境;Secret 建议逐键 env + secretKeyRef,看得清来源。
  3. 改配置对象 ≠ 改了正在跑的进程:环境变量在进程启动时定格,变更生效需要滚动重启(rollout restart),要纳入发布流程。
  4. Secret 的默认保护是「权限与习惯」:Base64 谁都能解;真正的防线是 RBAC 最小权限、审计日志、以及密钥不进 Git 的纪律。
  5. Spring Boot 与 K8s 配置天然对齐:环境变量覆盖 application.yml(如 SPRING_DATASOURCE_URL),所以本站键名表(DB_HOST/REDIS_HOST/密码)可以三环境通用。
  6. 引用必须先于使用存在:Deployment 引用了不存在的 ConfigMap/Secret 时,Pod 会卡在 CreateContainerConfigError——apply 顺序应为:配置 → 密钥 → 工作负载。

你可能会懵的地方

  • Secret 到底加密吗? 默认只是 Base64 编码(防止「手滑看到明文」,不是密码学保护)。加密要靠集群启用 etcd encryption at rest,或直接引入 Vault 类系统。

  • 整个 application.yml 放 ConfigMap 合适吗? 放文件挂载可以,注意 1MiB 限制与变更流程;实践中更推荐「敏感/环境相关走环境变量,结构化大配置走挂载文件」的混合模式。

  • 和 Docker 的 --env-file / secrets 有什么区别? 问题域相同(配置与镜像分离),K8s 把配置升级为集群级对象:有版本化、有 RBAC、能挂载成文件、能被多个 Deployment 共享引用。

  • kubectl create secret 和 YAML 选哪个? 演示用命令式;生产用「脱敏模板 YAML + CI 注入真实值」,保证流程可审计且密钥不落仓库。

  • 配置变了但行为没变,怎么证明? 进容器 printenv 对账(步骤 5 的方法);再不行 kubectl get cm <名> -o yaml 看对象当前值。三个层面(对象值、进程环境、应用行为)逐层对齐。

错法对照

错法问题正解
Dockerfile ENV 写死数据库密码镜像即泄密,且换环境要重建Secret 注入,镜像保持中性
含真口令的 Secret YAML 推进 Git历史记录永久泄漏仓库只放模板,值由 CI/密管系统注入
改完 ConfigMap 等它自动生效env 注入不会热更新rollout restart 或重新发布
所有配置一律塞 Secret管理噪音、审查困难非敏感进 ConfigMap,敏感才 Secret
日志/printenv 全量输出口令随日志外泄脱敏日志,口令只进密管

卡点急救

  1. Pod 卡在 CreateContainerConfigError:引用的 ConfigMap/Secret 名或 key 不存在。kubectl describe pod 会点名缺谁;先建配置对象再重建工作负载。
  2. 改了配置「没生效」:先确认对象值已更新(get cm -o yaml),再执行 kubectl rollout restart deployment/<名>;volume 挂载场景还要确认应用自身会重读文件。
  3. Base64 解码结果带乱码/换行:可能复制丢了字符或混入了换行符;用 -o jsonpath='{.data.KEY}' 精确取值,解码后比对长度。

面试常问

  • ConfigMap 和 Secret 怎么选?Secret 加密吗? 非敏感、可公开的配置进 ConfigMap(地址、开关、profile);口令、令牌、证书私钥进 Secret。Secret 默认只是 Base64 编码,不是加密——任何人拿到读权限即可解码。生产要叠加:RBAC 收敛 get secrets、etcd 加密落盘、优先接入 Vault / External Secrets / Sealed Secrets 等密管方案。

  • 环境变量注入和 volume 挂载注入有什么区别? 环境变量:进程启动时定格,ConfigMap 更新后不会热生效,必须滚动重启;适合开关类键值,Spring Boot 直接识别。volume 挂载:kubelet 会把文件更新同步到容器(默认有约一分钟的同步周期),但应用要不要重读取决于程序;适合整份配置文件与证书。工程约定:改配置一律走发布流程,不依赖热更新。

  • 如何防止密钥进 Git 泄漏? 仓库只放脱敏模板(值用占位符);真实值通过 CI 变量、密管系统在部署时注入;本地调试用不进版本库的 .env;再配一层 pre-commit 扫描(gitleaks 等)兜底。泄漏后的标准动作是立即轮换密钥,而不是删除提交历史。

自测三问

  1. 本站 backend 的哪些键进 ConfigMap、哪些进 Secret?边界怎么画?
  2. 为什么说「Base64 不是加密」?请给出生产环境的三层加固。
  3. DB_HOST=mysql 在 Compose 和 K8s 里分别指向什么?

小结一句话

配置与密钥和镜像分离:ConfigMap/Secret 注入环境变量或文件,变更通过滚动发布生效——下一课处理「磁盘上的数据」如何跨 Pod 重建而存活。

延伸

  • ConfigMaps
  • Secrets
  • 下一课预告:存储卷——emptyDir 的临时性、PV/PVC/StorageClass 的分工,以及 MySQL 数据目录的持久化实验。
加载本节练习…
← 上一课Service 与网络下一课 →存储卷