Kubernetes ConfigMap 与 Secret 的正确用法:别再把密码写进镜像
Kubernetes ConfigMap 与 Secret 的正确用法:别再把密码写进镜像刚上手 K8s 的人常犯一个错:把数据库密码、API key 直接写进 Dockerfile 或代码里,镜像一推仓库就全世界可见了。ConfigMap 和 Secret 就是来解决「配置和代码分离」的。今天把这俩讲透:怎么创建、怎么挂载、Secret 到底安不安全、改了配置要不要重启。ConfigMap:存非敏感配置ConfigMap 装的是明文配置:日志级别、功能开关、第三方服务地址等。创建方式有三种。命令行直接给键值:kubectl create configmap app-config\--from-literalLOG_LEVELinfo\--from-literalMAX_CONN100从文件创建(整个文件作为一个 value):kubectl create configmap nginx-config --from-filenginx.conf或者直接写 YAML,推荐这种,能进 Git 版本管理:apiVersion:v1kind:ConfigMapmetadata:name:app-configdata:LOG_LEVEL:infoMAX_CONN:100app.properties:|# 也能存整段配置文件server.port8080 server.timeout30sSecret:存敏感数据Secret 的用法和 ConfigMap 几乎一样,专门装密码、token、证书。创建时 kubectl 会帮你 base64 编码:kubectl create secret generic db-secret\--from-literalDB_PASSWORDmy-super-secret写 YAML 时要注意,data字段的值必须是已经 base64 编码过的:apiVersion:v1kind:Secretmetadata:name:db-secrettype:Opaquedata:DB_PASSWORD:bXktc3VwZXItc2VjcmV0# echo -n my-super-secret | base64嫌手动编码麻烦,可以用stringData字段直接写明文,K8s 会自动编码:apiVersion:v1kind:Secretmetadata:name:db-secrettype:OpaquestringData:DB_PASSWORD:my-super-secret# 用 stringData 就不用自己 base64关键认知:base64 不是加密!这是新手最大的误区。base64 是编码,不是加密,谁都能一秒解开:echobXktc3VwZXItc2VjcmV0|base64-d# 输出:my-super-secret所以 Secret 默认状态下,只是比 ConfigMap 多了「不直接明文显示」这层遮羞布。真正要保证安全,你得做三件事:开启 etcd 静态加密(EncryptionConfiguration),让 Secret 在 etcd 里落盘时是加密的;用 RBAC 限制谁能读 Secret,别给所有 ServiceAccount 开 get secrets 权限;生产环境考虑外部方案,如Vault、云厂商的 Secrets Manager,配合 External Secrets Operator 同步。别把 Secret 的 YAML(哪怕是 base64 的)提交到公开 Git 仓库,那和明文没区别。两种挂载方式:环境变量 vs 卷挂给 Pod 有两种方式,各有取舍。方式一:注入成环境变量,适合少量配置:spec:containers:-name:appimage:myapp:1.0envFrom:-configMapRef:name:app-config# 把整个 ConfigMap 灌成环境变量env:-name:DB_PASSWORDvalueFrom:secretKeyRef:# 单独引用 Secret 的某个 keyname:db-secretkey:DB_PASSWORD方式二:挂载成文件(卷),适合配置文件、证书:spec:containers:-name:appimage:myapp:1.0volumeMounts:-name:config-volmountPath:/etc/config# 每个 key 变成该目录下一个文件volumes:-name:config-volconfigMap:name:app-config挂载后/etc/config/LOG_LEVEL就是一个内容为info的文件。大坑:改了 ConfigMap,Pod 不会自动感知这是运维最容易栽的地方,分两种情况:环境变量方式:环境变量在容器启动时就固定了,之后改 ConfigMap永远不会生效,必须重建 Pod(kubectl rollout restart deployment/xxx)。卷挂载方式:kubelet 会定期同步(默认约 1 分钟),文件内容会自动更新——但你的应用得自己监听文件变化重新加载,否则进程里的旧配置照样不变。想让配置变更强制滚动更新,常见做法是给 Pod 模板加一个基于 ConfigMap 内容的注解(如 checksum),内容一变注解就变,触发 Deployment 滚动:spec:template:metadata:annotations:# 用 configmap 的 hash 当注解,内容变则触发滚动更新checksum/config:{{ sha256sum(configmap.data) }}Helm 用户可以直接{{ include (print $.Template.BasePath /configmap.yaml) . | sha256sum }},这是社区标准套路。小结ConfigMap 存非敏感配置,Secret 存密码/证书,用法几乎一样。base64 不是加密,Secret 默认不安全:必须配 etcd 静态加密 RBAC,生产上外接 Vault/云 Secrets Manager。挂载分环境变量和卷两种:少量配置用 env,配置文件/证书用卷。环境变量方式改配置必须重启 Pod;卷方式文件会自动更新,但应用要自己 reload。想强制滚动就用 configmap hash 注解。记忆点:Secret 的 base64 是遮羞布不是保险箱;环境变量注入的配置改了不重启永远不生效。