K8s中的数据管理:ConfigMap、Secret与Volume

引言:让“有状态”的应用在 K8s 中安家

在之前的文章中,我们已经学会了用 Deployment 和 Service 来管理“无状态应用”(Stateless Applications)。这类应用不保存任何需要持久化的数据,可以随意销毁和重建,就像快餐店的厨师,任何人都可以随时替换,因为他们都遵循同一份标准菜单,不需要记住顾客的个人口味。

但现实中还有大量“有状态应用”(Stateful Applications),比如数据库、需要保存用户上传文件的网站、需要加载外部配置文件的应用。它们有“记忆”,有“个性”,不能随意被替换。这就引出了一系列新的问题:

  • 配置管理:应用的配置(比如数据库地址、主题名称)应该如何管理?硬编码在镜像里吗?显然不行,每次修改配置都得重新构建镜像,太笨拙了!
  • 敏感数据:敏感数据(比如数据库密码、API密钥)应该如何安全地存储和注入到应用中?直接写在代码或配置文件里吗?绝对不行,这是严重的安全隐患!
  • 数据持久化:应用产生的数据(比如数据库文件、用户上传的图片)如何保证在 Pod 重启或迁移后不丢失?

为了解决这些问题,K8s 提供了三件法宝:ConfigMap 就像一个“外置的配置文件架”,Secret 就像一个“加密的保险箱”,而 Volume 则像一个“可挂载的持久化硬盘”。本篇将带你逐一掌握它们,完成 K8s 学习的最后一块拼图。

第一章:ConfigMap —— 应用配置的解耦大师

1.1 为什么需要 ConfigMap?

痛点:将配置信息硬编码在 Docker 镜像中,是反模式的。这会导致每次修改配置(哪怕只是改一个主题颜色)都需要重新构建和部署整个镜像,效率低下且不灵活。

解决方案:ConfigMap 将非敏感的配置数据与应用代码解耦。它允许你将配置信息作为 K8s 对象进行管理,应用在运行时动态加载这些配置。这样,当配置变更时,你通常只需要更新 ConfigMap 并重启应用 Pod 即可,无需重新构建镜像。

1.2 如何创建 ConfigMap?

你可以通过多种方式创建 ConfigMap,但推荐使用 YAML 文件进行声明式管理。

我们已经为你准备好了一个 configmap.yaml 示例:

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-app-config
data:
  # 键值对形式的配置
  app.theme: "dark"
  app.language: "zh-CN"

  # 也可以嵌入整个文件内容
  config.json: |
    {
      "apiServer": "https://api.example.com/v1",
      "featureFlags": {
        "enableBeta": true,
        "darkModeDefault": true
      }
    }

使用 kubectl apply -f configmap.yaml 即可创建。

1.3 如何在 Pod 中使用 ConfigMap?

方式一:作为环境变量注入

你可以在 deployment.yaml 中,通过 envFromvalueFrom 将 ConfigMap 的键值对注入为容器的环境变量。

# In deployment.yaml
spec:
  containers:
  - name: my-container
    image: my-app
    env:
      - name: APP_THEME # 将指定的 key 注入为环境变量
        valueFrom:
          configMapKeyRef:
            name: my-app-config # ConfigMap 的名字
            key: app.theme      # ConfigMap 中的 key
    # 或者,将所有 key 都注入为环境变量
    # envFrom:
    #   - configMapRef:
    #       name: my-app-config

方式二:作为文件挂载到容器中(更常用)

这是加载整个配置文件的常用方式。你可以将 ConfigMap 中的每个条目都作为一个文件挂载到容器的指定路径。

# In deployment.yaml
spec:
  containers:
  - name: my-container
    image: my-app
    volumeMounts: # 定义容器内的挂载点
    - name: config-volume
      mountPath: /etc/config # 挂载到容器的 /etc/config 目录
  volumes: # 定义 Pod 级别的卷
  - name: config-volume
    configMap:
      name: my-app-config # 使用名为 my-app-config 的 ConfigMap 作为卷的内容

挂载后,容器内的 /etc/config 目录下会出现 app.theme, app.language, config.json 三个文件。

第二章:Secret —— 敏感数据的“保险箱”

2.1 Secret vs ConfigMap

核心区别:Secret 用于存储敏感数据,如密码、OAuth令牌、SSH密钥等。它在存储和使用上与 ConfigMap 非常类似,但 K8s 会对其进行特殊处理以增加安全性。

安全性:Secret 的数据在 etcd 中默认是以 Base64 编码存储的(注意:Base64 只是编码,不是加密!任何人都可以解码)。但 K8s 提供了更严格的访问控制(RBAC),并支持与外部 KMS(密钥管理服务)集成对 Secret 进行加密,同时避免在 kubectl describe 等命令中直接显示其内容。

2.2 如何创建 Secret?

创建 Secret 的方式与 ConfigMap 类似,但数据值必须是 Base64 编码的。

生成 Base64 编码

# -n 参数表示不输出末尾的换行符
echo -n 'S3cr3tP@ssw0rd' | base64
# 输出: UzNjcjN0UEBzc3cwcmQ=

通过 YAML 文件创建(推荐)

apiVersion: v1
kind: Secret
metadata:
  name: my-db-secret
type: Opaque # 最常见的 Secret 类型
data:
  # key 必须是 Base64 编码后的值
  db.password: UzNjcjN0UEBzc3cwcmQ=
  db.username: YWRtaW4= # "admin" 的 Base64 编码

2.3 如何在 Pod 中使用 Secret?

使用方式与 ConfigMap 完全相同:可以作为环境变量注入,也可以作为文件挂载。K8s 会在注入或挂载前自动为你进行 Base64 解码。

# 作为环境变量注入
env:
- name: DB_PASSWORD
  valueFrom:
    secretKeyRef:
      name: my-db-secret
      key: db.password

# 作为文件挂载
volumeMounts:
- name: secret-volume
  mountPath: /etc/secrets
volumes:
- name: secret-volume
  secret:
    secretName: my-db-secret

第三章:Volume —— Pod 的“持久化硬盘”

3.1 为什么需要 Volume?—— Pod 文件系统的“短暂性”

问题:容器的文件系统是临时的。当 Pod 因任何原因(崩溃、更新、节点迁移)被销毁时,容器内部的所有数据都会丢失。这对于数据库、文件服务器等需要持久化数据的应用是致命的。

解决方案:Volume 为 Pod 提供了一个独立于容器生命周期的存储。即使 Pod 被销毁,Volume 中的数据依然可以保留。

3.2 深入理解持久化存储:PV, PVC 和 StorageClass

K8s 的持久化存储设计非常灵活,它通过三个核心概念将“存储需求”与“存储实现”解耦。

生动类比:将这三者比作“去云服务商申请和使用云硬盘”的过程。

  • PersistentVolume (PV)持久卷。由集群管理员预先创建好的一块网络存储,就像是“机房里已经准备好的、可供分配的硬盘”。它定义了存储的大小、访问模式(如是否支持多节点同时读写)、存储类型(如 NFS、Ceph)等物理属性。它是一个集群级别的资源。

  • PersistentVolumeClaim (PVC)持久卷声明。由开发者(用户)创建的“存储申请单”。用户在 PVC 中声明需要多大的存储、需要什么样的访问模式,而无需关心底层存储的具体实现。它是一个命名空间级别的资源。当用户创建 PVC 后,K8s 会在已有的 PV 中寻找一个满足其要求的并与之绑定 (Bound)

  • StorageClass存储类。一个“存储模板”,用于动态地创建 PV。在现代 K8s 集群中,管理员通常不会手动创建大量 PV,而是创建几个 StorageClass(例如 fast-ssd, slow-hdd)。当用户提交一个 PVC 申请时,如果 PVC 指定了某个 StorageClass,该 StorageClass 就会自动地根据 PVC 的要求去云服务商那里(或在本地存储系统上)创建一块新的 PV,并与该 PVC 绑定。这被称为动态卷供应 (Dynamic Provisioning),是目前最常用、最便捷的方式。

3.3 实战:为应用挂载一个持久卷

  1. 创建 PVC (存储申请单)
    我们已经为你准备好了 pvc.yaml 文件:

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: my-app-pvc
    spec:
      accessModes:
        - ReadWriteOnce # 表示这个卷可以被单个节点以读写模式挂载
      resources:
        requests:
          storage: 1Gi # 申请 1GB 的存储空间
    

    执行 kubectl apply -f pvc.yaml 创建 PVC。

  2. 在 Deployment 中使用 PVC
    修改 deployment.yaml,通过 volumesvolumeMounts 将这个 PVC 挂载到 Pod 的某个路径下(例如 /data)。

    # In deployment.yaml
    spec:
      template:
        spec:
          containers:
          - name: my-container
            image: my-app
            volumeMounts:
            - name: my-persistent-storage
              mountPath: /data # 将卷挂载到容器的 /data 目录
          volumes:
          - name: my-persistent-storage
            persistentVolumeClaim:
              claimName: my-app-pvc # 引用我们刚刚创建的 PVC
    
  3. 验证持久化

    • kubectl apply -f deployment.yaml 部署应用。
    • kubectl exec -it <pod-name> -- sh 进入 Pod。
    • 在 Pod 内部执行 echo "hello persistent world" > /data/test.txt
    • 退出 Pod,然后删除它 kubectl delete pod <pod-name>
    • 等待 Deployment 自动创建一个新的 Pod。
    • kubectl exec -it <new-pod-name> -- sh 进入新的 Pod。
    • 执行 cat /data/test.txt,你会发现 “hello persistent world” 这个文件依然存在!数据成功地持久化了。

系列总结与未来展望

至此,我们已经完成了从 Docker 基础到 Kubernetes 核心概念和实践的完整旅程。回顾一下我们的足迹:

  1. Docker 基础:理解了容器化,学会了 docker run
  2. Dockerfile:学会了为自己的应用打包镜像。
  3. Docker Compose:学会了在单机上编排多容器应用。
  4. Kubernetes 登场:理解了 K8s 的价值和宏伟架构。
  5. 本地 K8s 集群:使用 Minikube 搭建了实践环境。
  6. Deployment & Service:掌握了 K8s 实现应用高可用的核心武器。
  7. 数据管理:学会了使用 ConfigMap、Secret 和 Volume 管理应用的配置和数据。

你已经掌握了云原生领域最核心、最基础的知识,足以应对大部分应用的容器化和编排需求。

然而,云原生的世界远不止于此。这扇大门之后,还有更广阔的生态系统等待你去探索:

  • Helm:Kubernetes 的包管理器,让你能像 aptyum 一样管理 K8s 应用。
  • Prometheus & Grafana:云原生监控和告警领域的王者组合。
  • Istio & Linkerd:服务网格(Service Mesh),为微服务提供流量管理、安全和可观察性。
  • ArgoCD & Flux:基于 GitOps 的持续交付工具。

希望这个系列能为你打开一扇通往新世界的大门,激励你继续探索这个充满活力和挑战的领域。你的云原生之旅,才刚刚开始!

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐