前言
应用跑到 Kubernetes 以后,代码和镜像只是其中一部分。真正让服务能在不同环境运行起来的,还有配置、密钥和存储。
这三类东西很容易被混在一起。比如把数据库密码写进 ConfigMap,把上传文件放在容器本地目录,把所有配置都塞进环境变量。短期能跑,长期会很难维护。
这篇主要梳理 ConfigMap、Secret、Volume、PersistentVolumeClaim 这些概念,重点不是背字段,而是分清它们各自应该解决什么问题。
镜像不要绑定环境
容器镜像最好只包含应用和运行所需依赖,不要把测试环境、预发环境、生产环境的差异直接打进镜像。
同一个镜像,应该可以通过不同配置跑在不同环境里。
比如 Spring Boot 应用里,镜像只包含 jar 包和启动脚本。数据库地址、Redis 地址、日志级别、外部接口地址这些,应该由部署环境注入。
这样做有两个好处:
1.镜像可以在多个环境复用。 2.发布时更容易判断变更来自代码还是配置。
如果每个环境都重新打一个镜像,问题排查会变复杂。你以为线上和测试是同一份代码,实际镜像里可能已经混入了环境差异。
ConfigMap 放普通配置
ConfigMap 适合放非敏感配置,比如开关、URL、日志级别、线程池大小。
可以用环境变量注入:
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: order-config
key: log-level
也可以把 ConfigMap 挂载成文件:
volumes:
- name: app-config
configMap:
name: order-config
containers:
- name: order-service
volumeMounts:
- name: app-config
mountPath: /app/config
环境变量适合少量简单配置,文件挂载适合结构化配置,比如一段完整的 application.yaml。
但要注意,配置更新不一定等于应用立即重新加载。很多应用启动时读取一次配置,后面不会自动感知变化。真实项目里要么重启 Pod,要么明确做动态配置机制,不要假设 ConfigMap 改了服务就一定生效。
Secret 放敏感信息
Secret 用来放密码、token、证书这类敏感信息。
从使用方式上看,它和 ConfigMap 很像,也能作为环境变量或文件挂载。但语义完全不同。
比如数据库密码:
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: order-secret
key: db-password
Secret 至少能让敏感信息和普通配置分开管理,也能配合集群权限控制。不要因为 Base64 看起来简单,就觉得 Secret 没意义。
当然,Secret 也不是终点。生产环境如果要求更高,通常还会接专门的密钥管理系统,由平台负责加密、轮换、审计和下发。
对业务开发来说,最基本的底线是:不要把密码写进镜像,不要提交到 Git,不要放进 ConfigMap。
容器本地目录不是持久存储
容器里的文件系统是临时的。Pod 被删除后,容器本地写入的数据可能就没了。
这对无状态服务不是问题。日志可以输出到 stdout,由采集系统处理;临时文件可以放在临时目录;缓存可以重建。
但如果应用真的需要保存数据,比如用户上传文件、数据库数据、消息中间件数据,就不能依赖容器本地目录。
Kubernetes 用 Volume 把存储挂进 Pod。普通的 emptyDir 只和 Pod 生命周期绑定,Pod 删除后也会消失。需要真正持久化时,要用 PersistentVolume 和 PersistentVolumeClaim。
PVC 是应用要存储的声明
PersistentVolumeClaim 可以理解为应用对存储资源的申请。
应用不用直接关心底层是云盘、NFS、Ceph 还是其他存储,只声明自己需要多大容量、什么访问模式、什么存储类。
一个简单 PVC:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: upload-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
Deployment 里再挂载:
volumes:
- name: upload-data
persistentVolumeClaim:
claimName: upload-data
containers:
- name: file-service
volumeMounts:
- name: upload-data
mountPath: /data/upload
这样 Pod 重建后,只要 PVC 仍然存在,数据就可以继续挂载回来。
有状态服务要谨慎上 k8s
不是所有东西都适合一开始就搬进 Kubernetes。
无状态 Web 服务、后台 worker、网关、定时任务,通常比较适合。数据库、消息队列、搜索引擎这类有状态组件,要看团队是否真的具备存储、备份、恢复、升级和故障处理能力。
Kubernetes 可以跑有状态服务,但它不会替你理解 MySQL 主从、Kafka ISR、Redis 持久化、Elasticsearch 分片这些业务组件自己的规则。
如果只是为了“全部容器化”,把数据库也贸然搬进去,风险会比收益大。
我的习惯是:业务应用先容器化,基础中间件优先使用成熟托管服务或已有运维体系。等团队对 k8s 存储、调度、备份和演练都有经验后,再考虑更复杂的有状态部署。
配置变更也要可追踪
配置一旦进入 k8s,就不能再靠口口相传。
至少要知道:
1.谁改了配置。 2.改了什么 key。 3.什么时候发布到哪个环境。 4.哪些 Pod 使用了这份配置。 5.出问题时怎么回滚。
如果用 GitOps,这些配置通常会以 YAML 形式进入仓库,通过提交记录追踪。如果用平台控制台,也要有审计和版本记录。
配置问题很常见,而且经常比代码问题更隐蔽。把配置管理好,本质上也是在降低发布风险。
小结
ConfigMap、Secret、PVC 看起来都是 YAML,但它们解决的是不同问题。
ConfigMap 放普通配置,Secret 放敏感信息,PVC 声明持久化存储。镜像不要绑定环境,容器本地目录不要当持久存储,配置变更也要能追踪和回滚。
Kubernetes 能提供统一的应用运行抽象,但不会自动替我们做好配置治理和数据治理。越是核心系统,越要把配置、密钥和存储边界分清楚。
気に入ったならばコメントを残してくださいね~