Kubernetes学习笔记03:配置、密钥和存储

发表于 2024-02-06 21:52 1566 字 8 min read

Spring AI学习笔记(四)工具调用和MCPSpring AI学习笔记(三)RAG从文档入库到回答Spring AI学习笔记(二)ChatClient从怎么调到怎么封装Spring AI学习笔记(一)它到底解决什么问题java新版本-java25学习笔记(四)用JFR和GC日志做一次体检java新版本-java25学习笔记(三)虚拟线程要和资源边界一起看java新版本-java25学习笔记(二)运行时基线先统一java新版本-java25学习笔记(一)LTS版本对比和学习路线主流AI Agent能力对比与工程选型我用Kiro做了个自己的工具站盘一盘虚拟线程我用Trae做了个AstrBot的AI角色扮演插件Python初学笔记(六)常用标准库先学这几个Python初学笔记(五)读写文件和处理异常Python初学笔记(四)函数让代码开始有结构Python初学笔记(三)条件、循环和推导式Python初学笔记(二)变量和基础类型比想象中重要Python初学笔记(一)先把环境和运行方式弄明白主流AI大模型能力对比Java 21和Spring Boot 3升级笔记(五)日志指标与可观测性Java 21和Spring Boot 3升级笔记(四)数据访问层适配Java 21和Spring Boot 3升级笔记(三)虚拟线程使用边界Java 21和Spring Boot 3升级笔记(二)Jakarta迁移要点Java 21和Spring Boot 3升级笔记(一)工程基线整理How Can We Tolerate Magic Values! Major Overhaul of JPA Specification!处理生僻字乱码:JPA框架对于Oracle的NVarchar2,NChar,NClob类型支持Redis Stream能不能当轻量消息队列用RocketMQ 5学习笔记:普通消息之外要看什么事件流不是换个消息队列这么简单Kubernetes学习笔记04:发布、排障和观测Kubernetes学习笔记03:配置、密钥和存储Kubernetes学习笔记02:Deployment、Service和IngressKubernetes学习笔记01:Pod和控制器mysql索引原理02--存储引擎索引的实现mysql索引原理01--索引的数据结构
This post is not yet available in English. Showing the original.
  应用跑到 Kubernetes 以后,代码和镜像只是其中一部分。真正让服务能在不同环境运行起来的,还有配置、密钥和存储。   这三类东西很容易被混在一起。比如把数据库密码写进 ConfigMap,把上传文件放在容器本地目录,把所有配置都塞进环境变量。短期能跑,长期会很难维护。   这篇主要梳理...

前言

  应用跑到 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 能提供统一的应用运行抽象,但不会自动替我们做好配置治理和数据治理。越是核心系统,越要把配置、密钥和存储边界分清楚。

If you enjoyed this, leave a comment~

© 2019 - 2026 VincentHo @VincentHo
Powered by theme astro-koharu · Inspired by Shoka