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