应用程序通常需要配置信息(环境变量、配置文件)以及敏感数据(数据库密码、API 密钥)。Kubernetes 提供了 ConfigMap 和 Secret 两种资源来解耦配置与镜像,让应用配置可以动态更新,同时避免敏感信息泄露。本文将详细讲解两种资源的创建方式、如何挂载到 Pod、更新策略以及安全注意事项。
一、ConfigMap:非敏感配置存储
ConfigMap 用于存储键值对或配置文件,适合环境变量、命令行参数、非加密的配置文件等。
1.1 创建 ConfigMap
方式一:命令行创建
# 从字面值创建kubectl create configmap app-config --from-literal=db.host=mysql --from-literal=db.port=3306# 从文件创建(文件内容作为 value,文件名作为 key)kubectl create configmap app-config --from-file=./app.properties# 从目录创建(目录下每个文件作为一个 key)kubectl create configmap app-config --from-file=./configs/方式二:YAML 文件定义
apiVersion:v1kind:ConfigMapmetadata:name:app-configdata:db.host:mysqldb.port:"3306"app.properties:|key1=value1 key2=value21.2 在 Pod 中使用 ConfigMap
作为环境变量注入
apiVersion:v1kind:Podmetadata:name:test-podspec:containers:-name:appimage:busyboxcommand:["/bin/sh","-c","env && sleep 3600"]env:-name:DB_HOSTvalueFrom:configMapKeyRef:name:app-configkey:db.host-name:DB_PORTvalueFrom:configMapKeyRef:name:app-configkey:db.portenvFrom:-configMapRef:name:app-config# 将 ConfigMap 中所有键值对作为环境变量作为文件挂载(Volume)apiVersion:v1kind:Podmetadata:name:test-podspec:containers:-name:appimage:nginxvolumeMounts:-name:config-volmountPath:/etc/configvolumes:-name:config-volconfigMap:name:app-config挂载后,/etc/config 目录下会生成文件:db.host、db.port、app.properties,内容即对应值。
注意:挂载的 ConfigMap 更新后,Pod 内的文件也会更新(但有些应用需要重启才能加载新配置)。
二、Secret:敏感数据存储
Secret 类似 ConfigMap,但用于存储 base64 编码的敏感数据(默认非加密,只是编码)。Kubernetes 可以对 etcd 中的 Secret 启用加密(需配置)。
2.1 创建 Secret
方式一:命令行创建
# 从字面值kubectl create secret generic db-secret--from-literal=password=123456# 从文件kubectl create secret generic db-secret--from-file=./password.txt# 创建 TLS Secret(用于 Ingress)kubectl create secret tls example-tls--cert=path/to/tls.crt--key=path/to/tls.key方式二:YAML 定义
apiVersion:v1kind:Secretmetadata:name:db-secrettype:Opaquedata:password:MTIzNDU2# base64 编码后的值(echo -n "123456" | base64)2.2 在 Pod 中使用 Secret
作为环境变量注入
apiVersion:v1kind:Podmetadata:name:test-podspec:containers:-name:appimage:busyboxcommand:["/bin/sh","-c","echo $DB_PASSWORD && sleep 3600"]env:-name:DB_PASSWORDvalueFrom:secretKeyRef:name:db-secretkey:password作为文件挂载(Volume)
apiVersion:v1kind:Podmetadata:name:test-podspec:containers:-name:appimage:nginxvolumeMounts:-name:secret-volmountPath:/etc/secretsreadOnly:truevolumes:-name:secret-volsecret:secretName:db-secret挂载后,Secret 中的每个 key 成为一个文件,文件内容为解码后的值(而非 base64)。默认权限 0644,可指定 defaultMode。
三、ConfigMap/Secret 更新与 Pod 热加载
通过环境变量注入的配置:Pod 启动后,修改 ConfigMap/Secret 不会影响已有的 Pod,需要重启 Pod。
通过 Volume 挂载的配置:kubelet 会定期同步(默认约 60 秒),文件内容会更新。但应用是否自动加载新配置取决于应用自身(如 Nginx 需要 reload,Spring Boot 的 @RefreshScope)。
强制重启 Pod 的方式:
手动删除并重建 Pod(对 Deployment 可通过滚动更新:kubectl rollout restart deployment )。
使用工具如 reloader(自动检测 ConfigMap 变更并触发滚动更新)。
四、SubPath 与部分挂载
如果只想挂载 ConfigMap/Secret 中的某个文件,而不是整个目录,可以使用 subPath:
volumeMounts:-name:config-volmountPath:/etc/nginx/conf.d/nginx.confsubPath:nginx.conf此时卷必须只包含该文件(通常创建 ConfigMap 时只放一个 key)。
五、安全最佳实践
避免将 Secret 直接硬编码在 YAML 中:使用 kubectl create secret 或 Sealed Secrets。
启用 etcd 加密:编辑 apiserver 启动参数 --encryption-provider-config。
限制 Secret 访问权限:通过 RBAC 控制谁可以 get/delete Secret。
使用外部 Secret 管理工具:如 HashiCorp Vault、AWS Secrets Manager,通过 CSI 驱动或 sidecar 注入。
避免将 Secret 导出到日志:不要在应用代码中打印环境变量或文件内容。
六、实战:配置与密码注入示例
apiVersion:v1kind:ConfigMapmetadata:name:app-cfgdata:app.conf:|server.port=8080 logging.level=INFO---apiVersion:v1kind:Secretmetadata:name:app-secrettype:Opaquedata:api-key:dGVzdC1rZXk=# 假设值 test-key---apiVersion:apps/v1kind:Deploymentmetadata:name:myappspec:replicas:1selector:matchLabels:app:myapptemplate:metadata:labels:app:myappspec:containers:-name:appimage:myapp:latestenv:-name:API_KEYvalueFrom:secretKeyRef:name:app-secretkey:api-keyvolumeMounts:-name:cfg-volmountPath:/etc/appvolumes:-name:cfg-volconfigMap:name:app-cfg七、小结
ConfigMap 和 Secret 让配置与镜像分离,提高了应用的可移植性和安全性。环境变量适合简单配置,volume 挂载适合配置文件。注意 Secret 默认只编码不加密,生产环境应启用 etcd 加密或使用外部密钥管理。