本文详细介绍了 Kubernetes 中的核心存储概念,涵盖了从临时数据卷到持久化存储方案,以及如何通过 ConfigMap 和 Secret 管理应用的配置与敏感数据,旨在为数据提供一个可靠的“家”。
存储分类
[cite_start]在 Kubernetes 中,存储根据其用途和特性可以分为两大类:元数据和真实数据 [cite: 27, 31][cite_start]。理解它们的特性是高效使用 Kubernetes 存储的基础 [cite: 24]。
[cite_start]元数据 (Metadata) [cite: 27]
- [cite_start]ConfigMap: 用于保存非敏感的配置数据,以明文形式存储 [cite: 28]。
- [cite_start]Secret: 用于保存敏感数据,如密码、Token、密钥等,数据会进行 Base64 编码 [cite: 29]。
- [cite_start]Downward API: 允许容器在运行时获取关于自身或其所在环境(如 Pod 名称、命名空间、资源限制等)的信息 [cite: 30]。
[cite_start]真实数据 (Real Data) [cite: 31]
- [cite_start]Volume: Pod 级别的数据卷,生命周期与 Pod 绑定,用于存储临时或持久性数据 [cite: 32]。
- [cite_start]PersistentVolume (PV): 集群级别的持久化存储资源,独立于 Pod 的生命周期,通过申请制(PVC)供应用使用 [cite: 33]。
ConfigMap
[cite_start]ConfigMap 是 Kubernetes 中用于存储和管理应用配置的核心组件,它将配置信息与容器镜像解耦,使得应用配置更加灵活和易于管理 [cite: 35, 53]。
创建 ConfigMap
可以通过命令行从文件或字面量快速创建 ConfigMap:
1 | # 从文件创建,文件名会成为 key,文件内容成为 value |
使用 ConfigMap
ConfigMap 中的数据可以通过多种方式注入到 Pod 中:
1. 作为环境变量
这是最常见的用法,可以将 ConfigMap 的键值对直接注入为容器的环境变量。
1 | apiVersion: v1 |
2. 作为启动命令参数
[cite_start]通过将 ConfigMap 的值注入环境变量,可以在容器的启动命令中引用这些变量 [cite: 58]。
1 | apiVersion: v1 |
3. 作为文件挂载到 Volume
[cite_start]可以将 ConfigMap 的内容作为一个或多个文件挂载到容器的指定路径,这对于需要读取配置文件的应用非常有用 [cite: 59]。
1 | apiVersion: v1 |
热更新
ConfigMap 的更新机制是其核心特性之一,但不同使用方式下表现不同:
- [cite_start]环境变量: 通过
env
或envFrom
注入的环境变量不会在 ConfigMap 更新后自动更新 [cite: 65]。Pod 必须重启才能获取新的配置。 - [cite_start]Volume 挂载: 通过 Volume 挂载的 ConfigMap 文件会自动更新 [cite: 66][cite_start]。Kubelet 会定期同步,通常在几十秒内完成更新,无需重启 Pod [cite: 66]。
[cite_start]注意:仅更新 ConfigMap 不会触发 Deployment 的滚动更新。如果需要 Pod 使用新配置进行重建,可以通过修改 Pod 模板的注解来强制触发滚动更新 [cite: 62]。
1 kubectl patch deployment my-deploy --patch '{"spec": {"template": {"metadata": {"annotations": {"version/config": "v2" }}}}}'
不可变 ConfigMap (Immutable)
[cite_start]为了防止意外更新导致应用中断,并提升大规模集群的性能(通过减少 API Server 的监控负载),可以将 ConfigMap 设置为不可变 [cite: 68, 69, 70]。
1 | apiVersion: v1 |
Secret
[cite_start]Secret 用于存储和管理敏感信息,如密码、OAuth 令牌和 SSH 密钥等 [cite: 75][cite_start]。相比于明文存储的 ConfigMap,Secret 提供了基本的安全保障 [cite: 72]。
安全特性
- 数据以 Base64 编码形式存储,并非加密,但避免了明文暴露。
- [cite_start]只分发到需要使用它的 Pod 所在的节点上 [cite: 77]。
- [cite_start]在节点上,Secret 通常存储在内存中,而非持久化到磁盘 [cite: 78]。
- [cite_start]在 Etcd 中默认是加密存储的(从 K8s 1.7 开始) [cite: 79]。
创建和使用
创建 Secret 时,值必须经过 Base64 编码。
1 | # 准备数据 |
Secret 的使用方式与 ConfigMap
完全相同,可以通过环境变量或Volume
文件挂载注入到容器中,只是引用的对象从
configMapKeyRef
变为 secretKeyRef
。
热更新与不可变性
[cite_start]Secret 的热更新机制和不可变(Immutable)配置与 ConfigMap
完全一致。通过 Volume 挂载的 Secret 会自动更新 [cite:
87][cite_start],而注入为环境变量的则不会。同样可以设置
immutable: true
来锁定 Secret 的内容 [cite: 89]。
Downward API
[cite_start]Downward API 是一种特殊的机制,它不用于存储用户定义的数据,而是将 Pod 自身的元数据暴露给运行在其中的容器 [cite: 93, 96]。
使用场景
- [cite_start]获取元数据: 容器需要知道自己的 Pod 名称、IP 地址、所在命名空间等 [cite: 97]。
- [cite_start]动态配置: 应用根据其被分配的资源限制(CPU/Memory limits)来动态调整行为 [cite: 98]。
使用方式
与 ConfigMap 和 Secret 类似,Downward API 也通过环境变量和Volume 文件两种方式提供信息。
1. 环境变量
1 | env: |
2. Volume 文件
1 | volumeMounts: |
[cite_start]优势对比: 使用 Volume 挂载 Downward API 的信息支持热更新(例如 Pod 的 label 或 annotation 发生变化时,文件内容会同步更新),而环境变量则是在 Pod 启动时一次性注入,不会改变 [cite: 103]。
Volume
[cite_start]Volume 是 Kubernetes 存储体系的基石,它解决了容器文件系统是临时的这一核心问题,提供了数据持久化和容器间文件共享的能力 [cite: 127]。Volume 的生命周期与 Pod 绑定。
Kubernetes 支持多种类型的 Volume,这里介绍两种最基础的:
emptyDir
[cite_start]一个临时的空目录,当 Pod 被分配到节点时创建,只要 Pod
在该节点上运行,它就一直存在。当 Pod 被删除时,emptyDir
中的数据也会被永久删除 [cite: 130]。
- 特性:
- Pod 内所有容器都可以挂载并读写同一个
emptyDir
,实现容器间文件共享。 - [cite_start]容器崩溃不会导致
emptyDir
数据丢失,因为它的生命周期与 Pod 相同 [cite: 131]。
- Pod 内所有容器都可以挂载并读写同一个
- 用途:
- [cite_start]临时暂存空间,例如用于排序算法的中间数据 [cite: 133]。
- [cite_start]一个容器从网络下载数据,另一个容器处理这些数据 [cite: 134]。
- [cite_start]后端存储:
默认使用节点的磁盘,也可以配置使用内存(tmpfs)以获得更高性能 [cite:
137]。
1
2
3
4
5volumes:
- name: cache-volume
emptyDir:
medium: Memory
sizeLimit: 1Gi # 使用内存时建议设置大小限制
hostPath
[cite_start]将主机(Node)文件系统上的文件或目录直接挂载到 Pod 中 [cite: 139]。
警告:
hostPath
是一种强大但危险的工具。- [cite_start]它将 Pod 与特定节点绑定,如果 Pod 被调度到其他节点,数据会丢失 [cite: 147]。
- [cite_start]可能暴露节点上的敏感文件或系统目录,带来安全风险 [cite: 149]。
- 通常仅用于需要访问节点底层资源的系统级 Pod,如日志收集代理或监控组件。
示例:
1
2
3
4
5volumes:
- name: docker-sock
hostPath:
path: /var/run/docker.sock # 挂载节点的 Docker socket
type: Socket # 指定路径类型,增强可靠性
PersistentVolume (PV) 与 PersistentVolumeClaim (PVC)
[cite_start]PV 和 PVC 是 Kubernetes 持久化存储的核心,它们将存储资源的定义(PV)与存储资源的使用(PVC)解耦,实现了存储的标准化管理 [cite: 152]。
- [cite_start]PersistentVolume (PV): 由管理员创建和配置的一块网络存储。它是集群的资源,就像 CPU 和内存一样 [cite: 33]。PV 封装了底层存储的实现细节,如 NFS、Ceph、ISCSI 等。
- PersistentVolumeClaim (PVC): 用户(应用开发者)创建的存储请求。它声明了需要的存储大小、访问模式等,但不关心底层如何实现。
工作流程
- 管理员预先创建多个 PV,定义好它们的容量、访问模式和存储类别。
- 用户在部署应用时,创建一个 PVC,声明所需的存储规格。
- Kubernetes 会在现有的 PV 中寻找一个能满足该 PVC 要求的 PV,并将它们**绑定(Bind)**在一起。
- Pod 在定义 Volume 时,直接引用 PVC 的名称,即可挂载并使用这块持久化存储。
核心概念
[cite_start]访问模式 (Access Modes)[cite: 168]:
- [cite_start]
ReadWriteOnce
(RWO): 卷可以被单个节点以读写方式挂载 [cite: 169]。 - [cite_start]
ReadOnlyMany
(ROX): 卷可以被多个节点以只读方式挂载 [cite: 170]。 - [cite_start]
ReadWriteMany
(RWX): 卷可以被多个节点以读写方式挂载 [cite: 171]。
- [cite_start]
[cite_start]回收策略 (Reclaim Policy)[cite: 173]: 定义了当 PVC 被删除后,与之绑定的 PV 如何处理。
- [cite_start]
Retain
(保留): PV 不会被删除,数据保留,状态变为Released
,需要管理员手动清理和回收 [cite: 174]。 - [cite_start]
Delete
(删除): PV 会被自动删除,同时底层的存储资源(如云硬盘)也会被删除 [cite: 176]。 - [cite_start]
Recycle
(回收): (已废弃) 会清空卷上的数据(rm -rf /thevolume/*
)使其可被再次使用 [cite: 175]。
- [cite_start]
StorageClass
[cite_start]当使用静态方式(手动创建 PV)管理存储时,每次用户需要存储都得麻烦管理员。StorageClass 提供了一种动态存储供应 (Dynamic Provisioning) 的机制,彻底自动化了 PV 的创建过程 [cite: 194, 197]。
工作原理
- 管理员创建一个或多个 StorageClass
对象,每个对象定义了一种存储类型(如
fast-ssd
、slow-hdd
)和用于创建它的驱动(Provisioner)。 - 用户在创建 PVC 时,通过
storageClassName
字段指定想要的 StorageClass。 - Kubernetes 收到这个 PVC 后,会调用该 StorageClass 指定的 Provisioner。
- Provisioner 会根据 PVC 的要求,在后端存储(如 NFS、Ceph、云厂商)上自动创建一个新的存储卷,并为其创建一个对应的 PV 对象。
- 新创建的 PV 会自动与用户的 PVC 绑定。
这个过程对用户完全透明,用户只需提交一个 PVC,就能在几秒钟内得到一块可用的持久化存储。
示例: 使用 NFS 的动态供应
[cite_start]社区提供了 nfs-client-provisioner
这样的工具,可以利用现有的 NFS 服务器实现动态存储供应 [cite: 208,
209]。管理员部署好 Provisioner 和一个指向它的 StorageClass
后,用户就可以通过 PVC 自动在 NFS 服务器上创建目录并挂载使用了。
1 | # 用户提交的 PVC |