生产环境必须用 valueFrom 引用 ConfigMap 或 Secret,因硬编码会导致敏感信息泄露、无法热更新、跨环境复用困难;ConfigMap 用于普通配置,Secret 用于密码等敏感数据,二者需同 namespace 且 key 名严格匹配。

直接在 Deployment 的 env 字段里写死环境变量值,只适合调试或 CI/CD 中的固定开关(比如 CI=true 或 LOG_LEVEL=debug),生产环境必须用 valueFrom 引用 ConfigMap 或 Secret —— 否则敏感信息泄露、无法热更新、跨环境复用困难。
为什么不能直接写 value
硬编码进 YAML 的 value 会随镜像或配置一起暴露在 Git 仓库、CI 日志、kubectl get deploy -o yaml 输出中。哪怕只是 DB_HOST=localhost,也意味着你把开发配置混进了生产部署模板;更别说密码、密钥、API token 这类字段。Kubernetes 不做任何加密或权限隔离,所有有 get 权限的人都能读到。
- 镜像中已有的同名环境变量会被覆盖,但你无法确认基础镜像设了哪些默认值
- 值含空格或特殊字符时,YAML 解析失败(如
value: my path/with space必须写成value: "my path/with space") - 多个
name相同的env条目,后定义的会覆盖前一个,顺序极易出错
ConfigMap 和 Secret 的正确引用方式
绝大多数业务配置走 configMapKeyRef,敏感字段(密码、token、私钥)必须走 secretKeyRef。两者都要求资源与 Deployment 在同一 namespace,否则报错类似 configmap "my-config" not found,且 name 和 key 大小写、拼写必须完全一致——YAML 没有自动补全,手误极难排查。
-
Secret中的值虽是 Base64 编码,但valueFrom会自动解码,Go 应用里直接用os.Getenv("MYSQL_PASSWORD")即可,不用再调base64.b64decode() -
ConfigMap的 key 必须符合环境变量命名规范(字母/数字/下划线,不能以数字开头),否则该 key 会被静默跳过,无任何警告 - 如果
ConfigMap和Secret里有同名 key,Secret的值会覆盖ConfigMap的值
Go 应用读取时的真实坑点
别假设 os.Getenv("DB_HOST") 一定返回字符串——它可能返回 None,尤其当 ConfigMap key 不存在、引用路径写错、或 ConfigMap 尚未创建时,Pod 会卡在 Pending 状态,kubectl describe pod 却显示 Failed to pull image 这类误导信息。
- 始终提供默认值:
os.Getenv("DB_HOST", "localhost") - 数值型变量必须显式转换:
port := os.Getenv("PORT", "8080"); http.ListenAndServe(":"+port, nil)会失败,得写成":" + strconv.Itoa(int(os.Getenv("PORT", "8080")))或更稳妥地用strconv.Atoi - Secret 引用失败时,Go 进程启动后读到空字符串或
None,容易导致连接数据库超时而非立即 panic,问题定位变慢
envFrom 批量导入的风险控制
用 envFrom 可一次性把整个 ConfigMap 或 Secret 转成环境变量,省得逐个写 valueFrom,但代价是失控:
- ConfigMap 里任意一个 key 不合法(比如含短横线
db-host),整条 key 就被跳过,且无日志提示 - ConfigMap 和 Secret 同时用
envFrom时,Secret 优先级更高,但你无法控制哪个 key 被覆盖、哪个没生效 - 不建议在生产 Deployment 中直接
envFrom引用由外部工具生成的 ConfigMap(比如 Helm 自动生成的),除非你人工校验过所有 key 名
最易被忽略的是:ConfigMap 或 Secret 创建顺序必须早于 Deployment;如果先 apply Deployment,再 apply ConfigMap,Pod 会因找不到引用而卡住——这个依赖关系不会被 Kubernetes 自动检查或等待。


















