简介
在软件中,将数据库 URL 或密码等设置硬编码到应用代码中是一种不好的做法。这样不仅会增加修改难度,还会带来安全风险。
Kubernetes 通过以下两个对象解决这个问题:
- ConfigMap:你可以把它理解为一块公告栏。你可以在这里张贴信息,例如「背景颜色是蓝色」或「数据库地址是 10.0.0.1」。办公室中的任何人(Pod)都可以读取这些信息。
- Secret:用于存储密码或令牌等敏感值。
将应用代码与运行时配置分离,是平台设计中的重要原则,而不只是 Kubernetes 的一项功能。
在本实验中,你将:
- 在公告栏(ConfigMap)上写一条配置。
- 将密码放入保险箱(Secret)。
- 让 Pod 学会读取这两类数据。
创建 ConfigMap
先为 Web 服务器创建一个配置文件。我们不把配置文件打包进镜像,而是将它存储在 ConfigMap 中。
这种方式体现了更广泛的容器设计原则:构建一个可复用的镜像,然后在运行时提供特定环境的配置。这样可以提高镜像的可移植性,因为开发、预发布和生产环境可以使用同一个容器,只需提供不同的设置。
首先,创建一个名为 nginx.conf 的简单 Nginx 配置文件:
echo 'events {} http { server { listen 80; location / { return 200 "Hello from ConfigMap!"; } } }' > nginx.conf
接下来,根据这个文件创建名为 nginx-config 的 ConfigMap。这个操作相当于把文件「张贴」到 Kubernetes 集群的公告栏上。
kubectl create configmap nginx-config --from-file=nginx.conf
确认 ConfigMap 已创建:
kubectl describe configmap nginx-config
你应该会在「Data」部分看到 nginx.conf 的内容。
创建 Secret
现在存储一项敏感数据。Secret 的使用方式与 ConfigMap 类似,但 Kubernetes 会对它进行额外保护(在存储时会对数据进行混淆处理)。
这里需要准确理解:Secret 比将密码硬编码到清单或镜像中更安全,但 base64 编码并不是真正的加密。在生产环境中,Secret 通常还会结合静态数据加密、更严格的 RBAC 以及外部 Secret 管理系统一起使用。
创建名为 app-secret 的 Secret,并在其中存储一个虚拟密码:
kubectl create secret generic app-secret --from-literal=password=SuperSecretPass123
确认 Secret 已创建:
kubectl get secret app-secret
查看详细信息时,你不会直接看到密码。密码会以隐藏的编码形式显示。
kubectl get secret app-secret -o yaml
注意,password 字段是一串看似杂乱的字符。这是 base64 编码,用于避免他人从旁窥视,或避免密码意外出现在日志中。
将 ConfigMap 挂载为文件
现在,让 Pod 学会读取公告栏中的内容。
使用 ConfigMap 最常见的方式是将它挂载为文件。挂载后,它会像容器磁盘上的普通文件一样出现。
当应用已经要求在某个固定路径读取配置文件时,这种基于文件的方式非常有用。Kubernetes 会将 ConfigMap 中的数据映射到容器文件系统中,因此应用仍然可以按照原来的方式读取文件。
创建名为 pod-config.yaml 的文件:
nano pod-config.yaml
粘贴以下内容。这个 Pod 会将 nginx-config ConfigMap 挂载到 /etc/nginx/nginx.conf。
apiVersion: v1
kind: Pod
metadata:
name: config-pod
spec:
containers:
- name: nginx
image: nginx:alpine
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: config-volume
configMap:
name: nginx-config
保存并退出(Ctrl+X、Y、Enter)。
应用该配置:
kubectl apply -f pod-config.yaml
等待几秒钟,让 Pod 启动。然后进入容器,检查文件是否存在:
kubectl exec config-pod -- cat /etc/nginx/nginx.conf
你应该会看到自定义配置。也就是说,这个 Pod 读取了公告栏中的内容,并使用了其中的文件。
将 Secret 注入环境变量
接下来处理 Secret。传递密码的一种常见方式是使用环境变量。
这种方式使用方便,但也需要了解其中的权衡。应用很容易读取环境变量,但诊断命令或进程检查也可能暴露这些变量。Kubernetes 同时支持基于文件和基于环境变量的注入,因为不同的应用和风险状况需要不同的处理方式。
创建名为 pod-secret.yaml 的文件:
nano pod-secret.yaml
粘贴以下内容。这个 Pod 会从 app-secret 中读取 password,并将其赋值给名为 APP_PASSWORD 的环境变量。
apiVersion: v1
kind: Pod
metadata:
name: secret-pod
spec:
containers:
- name: busybox
image: busybox
command: ["sleep", "3600"]
env:
- name: APP_PASSWORD
valueFrom:
secretKeyRef:
name: app-secret
key: password
保存并退出(Ctrl+X、Y、Enter)。
应用该配置:
kubectl apply -f pod-secret.yaml
Pod 运行后,检查容器中的环境变量:
kubectl exec secret-pod -- env | grep APP_PASSWORD
你应该会看到 APP_PASSWORD=SuperSecretPass123。
这里的关键是,Pod 定义中并不包含密码。密码存放在「保险箱」(Secret)中,Pod 只在运行时使用一个键来打开保险箱并读取密码。
总结
在本实验中,你练习了如何将代码与配置分离。
你已经成功完成以下操作:
- 使用 ConfigMap(公告栏)将配置文件注入服务器。
- 使用 Secret(保险箱)将隐藏的密码注入应用。
这样,你就可以更新配置或轮换密码,而无需重新构建 Docker 镜像!


