在 Kubernetes 的世界里,有一条非常经典的原则:镜像只负责承载代码,配置与密钥必须与镜像解耦。如果每次修改一个数据库地址、一个环境变量都要重新构建镜像、重新推送仓库、再滚动发布,那这套流程会变得极其低效,也让运维工程师疲于奔命。本篇文章将带你深入理解 K8s 配置管理的两大核心对象:ConfigMap 与 Secret,并通过完整的实战步骤,掌握如何将配置优雅地注入到容器中,让应用真正做到「一次构建、处处运行」。

为什么需要 ConfigMap 与 Secret
在传统部署方式里,配置文件往往和应用程序打包在一起,或者被硬编码在代码中。这种方式带来三大痛点:
- 耦合严重:环境一旦变化(如测试环境切到生产环境),就要重新打包发布。
- 安全隐患:数据库密码、API 密钥等敏感信息被明文写进代码或镜像,极易泄露。
- 难以追踪:配置散落在多个地方,没有统一的版本管理和变更记录。
Kubernetes 通过 ConfigMap 和 Secret 将「配置数据」从「应用镜像」中剥离出来,作为独立的第一等对象进行管理。ConfigMap 用于存放非敏感的普通配置,如日志级别、超时时间、环境变量等;Secret 则专门用来存放敏感数据,如密码、令牌、TLS 证书等。两者都通过 kubectl 命令管理,可以方便地挂载到 Pod 中或注入为环境变量。
ConfigMap 的核心概念与使用方式
什么是 ConfigMap
ConfigMap 本质上是一个键值对(key-value)集合,用于保存配置数据。它不关心数据的内容是什么,只负责存储和传递。你可以把它理解成一张「配置表」,里面每一行都是一个配置项。
ConfigMap 支持四种典型的使用方式:
- 环境变量注入:将某个键的值作为容器内的环境变量。
- 命令行参数传递:配合环境变量使用,作为启动命令的参数。
- 文件挂载:将 ConfigMap 作为 Volume 挂载到容器的指定路径。
- 容器启动命令读取:通过脚本在启动时读取挂载的文件。
创建 ConfigMap
最常见的创建方式是使用 kubectl create configmap 命令,可以直接从字面量创建:
# 通过字面量创建 ConfigMap
kubectl create configmap app-config
--from-literal=LOG_LEVEL=info
--from-literal=DB_HOST=mysql.default.svc.cluster.local
--from-literal=DB_PORT=3306
-n default
也可以从文件创建,适合配置项较多的场景:
# 先准备一个 properties 文件
cat > app.properties <<EOF
server.port=8080
server.timeout=30
feature.toggle=true
EOF
# 从文件创建 ConfigMap
kubectl create configmap app-file-config
--from-file=app.properties
-n default
查看创建好的 ConfigMap:
kubectl get configmap app-config -o yaml
输出结果大致如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: default
data:
LOG_LEVEL: info
DB_HOST: mysql.default.svc.cluster.local
DB_PORT: "3306"
注意,ConfigMap 中的值都是字符串类型,即便你写的是数字 3306,它也会被当作字符串 "3306" 存储,这一点在注入环境变量时需要特别留意。
将 ConfigMap 注入到 Pod
下面演示如何在 Pod 中使用 ConfigMap。第一种方式是把 ConfigMap 的键作为环境变量注入:
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: nginx:1.25
envFrom:
- configMapRef:
name: app-config
env:
- name: DB_PORT
valueFrom:
configMapKeyRef:
name: app-config
key: DB_PORT
第二种方式是把 ConfigMap 挂载为文件,让应用直接读取文件内容:
apiVersion: v1
kind: Pod
metadata:
name: app-pod-mount
spec:
containers:
- name: app
image: nginx:1.25
volumeMounts:
- name: config-volume
mountPath: /etc/app/config
readOnly: true
volumes:
- name: config-volume
configMap:
name: app-config
挂载后,/etc/app/config 目录下会为每个键生成一个同名文件,文件内容就是对应键的值。
Secret 的核心概念与使用方式
什么是 Secret
Secret 与 ConfigMap 结构类似,都是键值对集合,但 Secret 专门用于存储敏感信息。Kubernetes 会对 Secret 进行 base64 编码存储(注意:base64 只是编码而非加密,本质上仍可被轻易解码),并支持通过 RBAC 权限控制谁能访问。
Secret 常见的类型包括:
- Opaque:通用密钥类型,最常用,默认类型。
- kubernetes.io/dockerconfigjson:用于私有镜像仓库的认证信息。
- kubernetes.io/tls:用于存储 TLS 证书和私钥。
- kubernetes.io/service-account-token:ServiceAccount 的令牌。
创建 Secret
创建 Secret 时,敏感数据需要先经过 base64 编码,也可以让 kubectl 帮你自动编码:
# 方式一:从字面量创建(kubectl 会自动 base64 编码)
kubectl create secret generic db-secret
--from-literal=DB_USER=admin
--from-literal=DB_PASSWORD=Sup3rS3cret!
-n default
# 方式二:从文件创建(常用于证书、密钥文件)
kubectl create secret tls my-tls-secret
--cert=tls.crt
--key=tls.key
-n default
查看 Secret 的内容,可以看到数据是 base64 编码的:
kubectl get secret db-secret -o yaml
输出示例:
apiVersion: v1
kind: Secret
metadata:
name: db-secret
namespace: default
type: Opaque
data:
DB_USER: YWRtaW4=
DB_PASSWORD: U3VwM3JTZWNyZXQh
你可以用下面的命令解码验证:
echo "U3VwM3JTZWNyZXQh" | base64 -d
将 Secret 注入到 Pod
Secret 的用法与 ConfigMap 几乎一致,只是引用对象换成了 secretRef / secretKeyRef:
apiVersion: v1
kind: Pod
metadata:
name: db-pod
spec:
containers:
- name: db
image: mysql:8.0
env:
- name: MYSQL_USER
valueFrom:
secretKeyRef:
name: db-secret
key: DB_USER
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: DB_PASSWORD
完整实战:为 Nginx 应用注入配置与密钥
下面通过一个完整示例,演示如何将 ConfigMap 和 Secret 同时应用到一个 Web 应用上。
第一步,创建 ConfigMap 存放 Nginx 的日志级别和首页欢迎语:
kubectl create configmap web-config
--from-literal=NGINX_LOG_LEVEL=warn
--from-literal=WELCOME_MSG="Welcome to K8s Config Management"
第二步,创建 Secret 存放应用的访问令牌:
kubectl create secret generic web-secret
--from-literal=APP_TOKEN=my-super-token-2026
第三步,创建 Deployment,同时使用 ConfigMap 和 Secret:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.25
env:
- name: NGINX_LOG_LEVEL
valueFrom:
configMapKeyRef:
name: web-config
key: NGINX_LOG_LEVEL
- name: APP_TOKEN
valueFrom:
secretKeyRef:
name: web-secret
key: APP_TOKEN
ports:
- containerPort: 80
第四步,验证 Pod 运行状态,并进入容器确认环境变量已生效:
kubectl apply -f web-app.yaml
kubectl get pods -l app=web
kubectl exec -it web-app-<pod-id> -- env | grep -E "NGINX_LOG_LEVEL|APP_TOKEN"
如果配置正确,你会看到 NGINX_LOG_LEVEL=warn 和 APP_TOKEN=my-super-token-2026 两个环境变量已经被成功注入。
配置热更新与不可变配置
默认情况下,挂载到容器中的 ConfigMap 会定期同步更新,Pod 内的文件内容会在一定延迟后自动刷新。这意味着你可以修改 ConfigMap 而无需重启 Pod。但要注意:通过环境变量注入的配置不会热更新,因为环境变量在进程启动时就已经固定下来,必须重启 Pod 才能生效。
如果希望配置真正可控,推荐的做法是:
- 修改 ConfigMap 时,使用
kubectl rollout restart deployment/<name>主动触发滚动重启。 - 对于版本敏感的应用,可以在 Deployment 中给 ConfigMap 加一个版本注解(如
configVersion),每次变更时同步修改,利用滚动更新机制实现配置发布。 - 对于不需要热更新的场景,可将 ConfigMap 声明为
immutable: true,提升性能并避免意外修改。
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
immutable: true
data:
LOG_LEVEL: info
常见问题排查
问题一:环境变量注入后为空。
检查 ConfigMap/Secret 的键名是否与 configMapKeyRef.key 完全一致(区分大小写)。可以用 kubectl describe pod <name> 查看事件,或 kubectl get configmap <name> -o yaml 确认键是否存在。
问题二:挂载文件后应用读取不到。
确认 mountPath 与应用的预期路径一致;检查是否挂载到了正确容器;如果是子路径挂载,注意 subPath 不会热更新。
问题三:Secret 被 base64 解码后乱码。
多半是创建时对数据进行了二次编码。建议直接使用 --from-literal 或 --from-file,让 kubectl 自动处理编码,避免手动 echo | base64 的重复编码问题。
问题四:修改 ConfigMap 后应用行为没变化。
如果配置是通过环境变量注入的,需要重启 Pod;如果是文件挂载,确认应用本身是否支持动态读取文件,很多应用只在启动时加载一次配置。
总结
ConfigMap 与 Secret 是 Kubernetes 配置管理的基石,它们让「配置与代码分离」这一现代云原生理念真正落地。掌握它们之后,你就能轻松应对不同环境的差异化配置,同时保证敏感信息的安全性。记住几个关键点:ConfigMap 管普通配置、Secret 管敏感数据;环境变量注入不支持热更新,文件挂载支持但应用需主动重读;敏感数据在集群中仍是 base64 编码而非加密,生产环境建议配合密钥管理服务(KMS)或外部密钥仓库使用。
下一篇文章我们将进入 Kubernetes 的存储体系,深入讲解 PV、PVC 与持久化存储,看看容器如何在重启、漂移之后依然保留关键数据,敬请期待「K8s 运维系列 | 第 7 天:存储管理——PV、PVC 与持久化存储」。
下期预告
K8s 运维系列 | 第 7 天:存储管理——PV、PVC 与持久化存储。我们将学习持久卷(PersistentVolume)、持久卷声明(PersistentVolumeClaim)以及 StorageClass 动态供给机制,解决容器数据持久化的核心难题。


















暂无评论内容