用 ConfigMap 与 Secret 注入配置
目标
区分并使用让同一镜像在不同环境中以不同方式运行的四种注入路径(全部环境变量、单个环境变量、文件卷、subPath 文件),并能在字段层面处理 Secret 与 ConfigMap 的差异。
为什么重要
配置注入在实际工作中最容易引发事故的问题通常是“更新是否会生效”。通过环境变量注入的值只在进程启动时读取一次,因此即使修改 ConfigMap,在重新创建 Pod 之前也绝不会改变。通过卷注入的文件会由 kubelet 定期更新,但使用 subPath 挂载的单个文件是例外,不会更新。如果不了解这三种行为差异,就会把时间全耗在“配置明明改了,为什么没有生效”上。
defaultMode 也常在实际工作中出问题。挂载 Secret 时默认权限为 0644,同一节点上的其他进程也可能读取。对于 TLS 密钥等敏感文件,应将权限收紧到 0400。在 YAML 中,不加引号写 0400 会按八进制解释;但如果只写 400,就会按十进制 400 读取,最终得到不正确的权限。
immutable: true 不是安全功能,而是性能功能。为了监视已挂载 ConfigMap/Secret 的变化,kubelet 会不断访问 API 服务器;设为 immutable 后便会停止监视。在数千个 Pod 的规模下,可以显著降低 apiserver 负载。
步骤
- 创建命名空间
ckad-config,并在其中通过字面量创建 ConfigMapapp-config。键值为APP_MODE=production、LOG_LEVEL=info。 - 创建目录
/root/ckad-config,在文件/root/ckad-config/app.properties中写入一行timeout=30,然后用该文件创建 ConfigMapapp-props(键名为app.properties)。 - 创建 Pod
cfg-env。镜像为busybox:1.36,command: ["/bin/sh","-c","sleep 3600"]。通过envFrom注入整个app-config,并另外在env中以LOG为变量名引用app-config的LOG_LEVEL键。 - 创建 Secret
db-secret。类型为generic(Opaque),键值为DB_USER=appuser、DB_PASSWORD=s3cr3t。 - 创建 Pod
secret-consumer。镜像为busybox:1.36,command: ["/bin/sh","-c","sleep 3600"]。让环境变量DB_PASSWORD从db-secret的DB_PASSWORD键获取值;同时将同一个 Secret 作为卷dbcreds挂载到/etc/db,并将defaultMode设为0400。 - 创建 Pod
cfg-vol。镜像为nginx:1.27。将 ConfigMapapp-props作为卷props挂载两次:一次把整个目录挂载到/etc/app,另一次使用subPath: app.properties挂载到/opt/app/app.properties。 - 创建 ConfigMap
feature-flags,键为NEW_UI=on,并设置immutable: true。创建 Podoptional-cm(镜像busybox:1.36,command: ["/bin/sh","-c","sleep 3600"]),引用不存在的 ConfigMapmaybe-config作为envFrom,并设置optional: true。 - 创建 Deployment
web-config。副本数 2,标签app=web-config,镜像nginx:1.27。在envFrom中同时加入app-config(configMapRef)和db-secret(secretRef),并将 ConfigMapapp-props作为卷props挂载到/etc/app。
参考
kubectl create configmap app-config -n ckad-config --from-literal=APP_MODE=production --from-literal=LOG_LEVEL=infokubectl create secret generic db-secret -n ckad-config --from-literal=DB_USER=appuser --from-literal=DB_PASSWORD=s3cr3t- 直接编写 YAML 时,如需填入明文,请不要使用
data,而应使用stringData。保存后它会自动转换为data。 - 常见错误 1:把
defaultMode写在容器的volumeMounts下。它应位于卷定义(spec.volumes[].secret.defaultMode)一侧。 - 常见错误 2:把
immutable放进data中。它是 ConfigMap 的顶层字段。 - 验证:
kubectl get secret db-secret -n ckad-config -o jsonpath='{.data.DB_USER}' | base64 -d
通过字面量创建 ConfigMap
创建命名空间 ckad-config,并在其中通过字面量创建 ConfigMap app-config。键值为 APP_MODE=production、LOG_LEVEL=info。
可以为 kubectl create configmap 多次提供 --from-literal=키=값。先创建命名空间,并且不要漏掉 -n。
从文件创建 ConfigMap
创建目录 /root/ckad-config,在文件 /root/ckad-config/app.properties 中写入一行 timeout=30,然后用该文件创建 ConfigMap app-props(键名为 app.properties)。
使用 --from-file=경로 时,文件名会成为键,文件的全部内容会成为值。如需更改键名,请使用 --from-file=키이름=경로 形式。
同时使用 envFrom 和 configMapKeyRef
创建 Pod cfg-env。镜像为 busybox:1.36,command: ["/bin/sh","-c","sleep 3600"]。通过 envFrom 注入整个 app-config,并另外在 env 中以 LOG 为变量名引用 app-config 的 LOG_LEVEL 键。
envFrom[].configMapRef 会将所有键原样作为变量名,而 env[].valueFrom.configMapKeyRef 会选取一个键,并以不同的名称注入。两种方式可以在同一个容器中同时使用。
创建 Secret 并检查编码
创建 Secret db-secret。类型为 generic(Opaque),键值为 DB_USER=appuser、DB_PASSWORD=s3cr3t。
kubectl create secret generic 的 --from-literal 值会自动进行 base64 编码。直接编写 YAML 时,如需填入明文,请不要使用 data,而应使用 stringData。
同时将 Secret 注入环境变量和文件
创建 Pod secret-consumer。镜像为 busybox:1.36,command: ["/bin/sh","-c","sleep 3600"]。让环境变量 DB_PASSWORD 从 db-secret 的 DB_PASSWORD 键获取值;同时将同一个 Secret 作为卷 dbcreds 挂载到 /etc/db,并将 defaultMode 设为 0400。
环境变量使用 env[].valueFrom.secretKeyRef,文件使用 volumes[].secret.secretName 加卷挂载。文件权限通过卷一侧的 defaultMode 指定;在 YAML 中很容易漏掉八进制数前面的 0,请注意。
ConfigMap 卷与 subPath
创建 Pod cfg-vol。镜像为 nginx:1.27。将 ConfigMap app-props 作为卷 props 挂载两次:一次把整个目录挂载到 /etc/app,另一次使用 subPath: app.properties 挂载到 /opt/app/app.properties。
挂载整个目录会遮蔽该目录原有的内容。如果只想覆盖一个文件,请在 volumeMounts[].subPath 中填写键名。通过 subPath 挂载的文件不会随 ConfigMap 的修改而更新。
optional 引用与 immutable ConfigMap
创建 ConfigMap feature-flags,键为 NEW_UI=on,并设置 immutable: true。创建 Pod optional-cm(镜像 busybox:1.36,command: ["/bin/sh","-c","sleep 3600"]),引用不存在的 ConfigMap maybe-config 作为 envFrom,并设置 optional: true。
immutable: true 是 ConfigMap 规范的顶层字段(不在数据内部)。若要让 Pod 在引用不存在的 ConfigMap 时仍能启动,请在引用一侧设置 optional: true。
综合:在 Deployment 中同时使用三种配置
创建 Deployment web-config。副本数 2,标签 app=web-config,镜像 nginx:1.27。在 envFrom 中同时加入 app-config(configMapRef)和 db-secret(secretRef),并将 ConfigMap app-props 作为卷 props 挂载到 /etc/app。
在一个 Deployment 中使用前面创建的两个 ConfigMap 和一个 Secret。envFrom 数组可以并列放入 configMapRef 和 secretRef。也不要忘记卷挂载。