数据是企业发展的核心,尤其在生产过程中至关重要,存储数据文件是一个普遍需求。例如存储用户上传的头像、文件以及数据库数据。然而,Pod 中的容器是基于只读镜像创建的,在容器运行期间,数据文件是临时的。当 Pod 停止或崩溃时,Kubelet 会重新启动 Pod,但此时容器生成的数据将会丢失,容器将以最干净的状态重新启动。
为确保数据在 Pod 被销毁后仍能持久存在,我们需要找到解决方案,使 Pod 生成的数据能够实现持久化存储。
8.1 Volume
8.1.1 Volume 是什么
在 Kubernetes 中,Volume(卷)是用于持久化和管理容器数据的一种抽象。它们解决了容器数据的临时性问题,使得数据能够在容器的生命周期之外存储和访问。
本质上,挂载到容器中的卷与虚拟机或物理机中的目录没有区别,可能包含一些数据。Pod 中的容器可以对其进行增、删、改、查等操作,使用方式与直接在裸机上挂载几乎相同。
关键特性:
- 持久性: Volume 可以在容器重启和重建时保持数据的持久性。
- 生命周期:Volume 的生命周期与 Pod 相关联,当 Pod 被删除时,Volume 也会随之删除(除非使用了持久化卷)。
- 数据共享:多个容器可以共享同一个 Volume,从而实现数据的共享。
8.1.2 Volume 的类型
Kubernetes 支持多种类型的 Volume,以下是一些常用的卷类型:
Kubernetes 支持多种类型的 Volume,以下是一些常见的卷类型:
常见的 Volume 类型
- CephFS:用于挂载 Ceph 文件系统,适合分布式存储。
- GlusterFS:提供共享存储,支持高可用性和数据冗余。
- iSCSI:通过 iSCSI 协议连接块存储设备。
- Cinder:与 OpenStack 集成的块存储卷,提供持久化存储。
- NFS:网络文件系统卷,支持多个 Pod 共享数据(注意:存在单点故障,生产环境中不建议使用)。
- RBD:RADOS 块设备,适用于 Kubernetes 集成的 Ceph 存储。
- HostPath:将主机文件系统路径挂载到 Pod,适合访问主机文件系统的场景。
Kubernetes 特有的 Volume 类型
- ConfigMap:存储配置信息,可以挂载配置文件到容器。
- Secret:安全存储敏感数据(如密码和 API 密钥),可挂载为文件。
- EmptyDir:在 Pod 生命周期内创建的临时存储,Pod 删除时数据会丢失。
- PersistentVolumeClaim (PVC):用户请求的持久化存储,支持动态或静态绑定到 PersistentVolume (PV)。
以上是一些常用的 Volume 类型,更多信息请查阅 Kubernetes 官方文档。
8.1.3 Volume 使用案例
1. 通过 emptyDir 共享数据
emptyDir 是一种特殊的 Volume 类型,与其他卷的不同之处在于,当 Pod 被删除时,emptyDir 卷中的数据也会被清除。因此,emptyDir 通常用于不同容器之间共享数据。
假设我们有一个 Kubernetes Pod,其中包含两个容器:一个用于生成日志数据的应用程序,另一个用于处理和分析这些日志的工具。我们可以使用 EmptyDir 来实现这两个容器之间的数据共享。
apiVersion: v1
kind: Pod
metadata:
name: log-processor
spec:
containers:
- name: log-generator
image: log-generator-image
volumeMounts:
- mountPath: /var/log
name: log-volume
- name: log-analyzer
image: log-analyzer-image
volumeMounts:
- mountPath: /var/log
name: log-volume
volumes:
- name: log-volume
emptyDir: {}
工作流程
- 数据生成: log-generator 容器不断生成日志数据,并将其写入挂载的 /var/log 目录。
- Volume: log-volume 是一个 EmptyDir 类型的卷,挂载到两个容器的 /var/log 路径,实现数据共享。
- 数据分析: 同时,log-analyzer 容器可以实时读取这些日志进行分析。
- 数据生命周期: 当 Pod 被删除时,EmptyDir 中的数据也会被清除,这样在不需要保留日志的情况下,可以有效管理存储资源。
2. 使用 HostPath 挂载宿主机文件
HostPath 是 Kubernetes 中的一种 Volume 类型,它允许将主机节点的文件系统路径挂载到 Pod 中。用于实现 Pod 和宿主机之间的数据共享。
以下是一个使用 HostPath 的 Pod 示例:
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: my-container
image: my-app-image
volumeMounts:
- mountPath: /data
name: my-hostpath-volume
volumes:
- name: my-hostpath-volume
hostPath:
path: /path/on/host
type: Directory # 可选,指定类型,比如 Directory、File、Socket 等
my-hostpath-volume 是一个 HostPath 类型的卷,指向主机上的 /path/on/host 目录。
注意事项:
- 安全性: 使用 HostPath 可能会导致安全隐患,因为它允许容器访问主机文件系统,需谨慎使用。
- 可移植性: 因为 HostPath 依赖于特定节点的文件路径,Pod 的可移植性受到限制,难以在不同节点间迁移。
- 生产环境: 通常不建议在生产环境中使用 HostPath,除非确实需要访问主机文件系统。
5. 挂载 NFS 至 Pod
在生产环境中,由于数据的高可用性,建议避免使用 NFS 作为后端存储。NFS 存在单点故障的问题,许多企业对其高可用性并没有实现保障。因此,建议在生产环境中采用分布式存储,而在公有云环境中,则应优先考虑云服务提供的 NAS 存储替代 NFS,因为 NAS 的性能和可用性更高。
虽然 NFS 是一种流行的远程存储解决方案,但在非生产环境中,它仍然是一个不错的选择,能够快速搭建和使用。
以下是一个使用 NFS 的 Pod 示例:
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: my-container
image: my-app-image
volumeMounts:
- mountPath: /mnt/data # Pod 内部挂载路径
name: nfs-storage
volumes:
- name: nfs-storage
nfs:
server: nfs-server-ip # NFS 服务器的 IP 地址
path: /path/on/nfs/server # NFS 服务器上共享的路径
注意事项:Kubernetes 所有的节点都需要安装上 nfs-utils 才可以正常挂载使用。
8.2 PersistentVolume
8.2.1 什么是 PV
尽管 Volume 在一定程度上解决了大部分存储后端的问题,但在实际使用中仍面临诸多挑战,尤其是存储卷生命周期的管理。因此,Kubernetes 引入了两个新的 API 资源:PersistentVolume(PV)和 PersistentVolumeClaim(PVC)。PV 代表 Kubernetes 管理的存储资源,而 PVC 是对 PV 的请求,指明所需的 PV 类型。
在 Kubernetes 中,PV 是一种用于管理持久化存储的资源对象。它将存储资源(如 NFS、iSCSI、云存储等)抽象为 Kubernetes 中的可用资源,使应用程序能够更灵活、可扩展地使用存储。
PV 属于集群的系统资源,与 Node 平级,Pod 仅具备使用权,而无管理权。
8.2.2 PV 的访问模式
PV 的访问模式定义了一个 PV 可以被多大程度上挂载,以及在这些挂载期间,如何访问这些存储资源。Kubernetes 中主要有三种访问模式:
1. ReadWriteOnce (RWO)
-
描述:PV 可以被单个节点以读写模式挂载。
-
适用场景: 适用于需要独占访问的应用,例如数据库等。
2. ReadOnlyMany (ROX)
-
描述: PV 可以被多个节点以只读模式挂载。
-
适用场景: 适用于共享数据的场景,如静态文件服务器。
3. ReadWriteMany (RWX)
-
描述: PV 可以被多个节点以读写模式挂载。
-
适用场景: 适用于需要并发写入的应用,例如某些分布式文件系统。
4. ReadWriteOncePod (RWOP)
-
描述: PV 可以被单个 Pod 以读写模式挂载,防止同一 PV 被多个 Pod 同时挂载。
-
适用场景: 适用于需要限制同一时间内访问的场景,确保只有一个 Pod 能够对存储进行写入。
虽然 PV 在创建时可以指定不同的访问策略,但是也要后端的存储支持才行。比如一般情况下大部分块存储时不支持 RWM 的。
8.2.3 PV 的回收策略
在 Kubernetes 中,PV 的回收策略(Reclaim Policy)决定了当 PVC 被删除后,PV 的处理方式。PV 的回收策略有助于管理和控制存储资源的生命周期。以下是 Kubernetes 支持的主要回收策略:
1. Retain
- 描述: PV 在 PVC 被删除后仍然保留。
- 行为: PV 的状态变为“Released”,但不会被自动回收。管理员需要手动清理 PV,决定是否重用或删除它。
- 适用场景: 适用于需要数据保留的场景,比如需要手动检查和备份数据的情况。
2. Recycle (已弃用)
- 描述: 当 PVC 被删除时,PV 将被自动清理并重新用于新 PVC。
- 行为: 通过简单的清理操作(如格式化)将 PV 清理为可用状态。
- 注意: 该策略在 Kubernetes 1.14 版本后已被弃用,不推荐使用。
3. Delete
- 描述: PV 在 PVC 被删除时,后端存储也会被删除。
- 行为: 此策略会自动删除与 PV 关联的实际存储资源(例如,删除 AWS EBS 卷或 GCE PD)。
- 适用场景: 适用于临时数据存储,或者不需要保留数据的场景。
8.2.4 PV 的状态
在 Kubernetes 中,使用 kubectl get pv 命令可以查看已创建的 Persistent Volumes (PV) 的状态。STATUS 字段表示 PV 的当前状态,通常有以下几种状态:
- Available: PV 处于可用状态,尚未被任何 PVC 绑定。这意味着它可以被新的 PVC 请求使用。
- Bound:PV 已成功绑定到 PVC。这表示该 PV 目前正在被一个 PVC 使用,且已经被分配给相应的 Pod。
- Released:PVC 已被删除,但 PV 仍然存在且未被回收。此状态表明 PV 仍然保留着数据,管理员需要手动处理此 PV,决定是否重用或删除它。
- Failed:PV 在创建或绑定过程中出现错误,无法正常使用。这种状态通常会伴随错误信息,指示为何 PV 无法被使用。
- Terminating: PV 正在被删除。在 Kubernetes 中,删除 PV 的过程可能需要一些时间,这个状态表示系统正在进行删除操作。
8.2.5 PV 的提供方式
在 Kubernetes 中,Persistent Volume (PV) 的提供方式主要有两种:静态提供和动态提供。下面是对这两种方式的详细介绍。
1. 静态提供
描述:静态提供是在 Kubernetes 集群中手动创建和管理 PV 的方式。管理员在集群中预先定义好 PV 资源,通常是在集群部署期间通过 YAML 文件进行配置。
步骤:
- 创建 PV: 管理员使用 YAML 文件定义 PV 的规格,包括存储容量、访问模式、存储类等。
- 绑定 PVC: 用户创建 Persistent Volume Claim (PVC) 请求所需的存储。Kubernetes 根据 PVC 的请求查找符合条件的 PV,并进行绑定。
优缺点:
-
管理员可以对 PV 进行细粒度的控制,优化资源配置。
-
适合对存储资源需求较为稳定的应用场景。
-
管理和维护工作量较大,特别是在需要管理大量 PV 时。
-
不够灵活,不能根据需求自动调整存储资源。
2. 动态提供
动态提供是 Kubernetes 通过 Storage Class 自动创建 PV 的机制。用户只需定义 PVC,Kubernetes 就会根据 PVC 的请求和指定的存储类自动创建和绑定 PV。这种灵活性和便利性使动态提供 PV 在现代云原生环境中备受欢迎,但其实现依赖于底层存储提供商。因此,需要在集群中部署相应的提供商组件。
步骤:
- 创建 Storage Class: 管理员定义存储类,指定动态提供 PV 的存储类型和参数(如使用的存储提供商、卷类型等)。
- 创建 PVC: 用户根据所需的存储需求创建 PVC,并指定相应的 Storage Class。
- 自动创建 PV: Kubernetes 根据 PVC 的请求和 Storage Class 自动创建 PV,并完成绑定。
优缺点:
-
提供了更高的灵活性,用户可以根据需要动态请求存储资源。
-
降低了管理员的维护负担,减少了静态 PV 的管理工作。
-
对于存储类的配置需要一定的知识和经验,可能会引入复杂性。
-
依赖于存储提供商的实现,某些功能可能受到限制。
8.3 PersistentVolumeClaim
在 Kubernetes 中,PVC(Persistent Volume Claim)是对存储资源的请求,用户可以通过它指定所需的存储类型、空间大小和访问模式。这与 Pod 的 QoS 配置相似:Pod 消耗节点资源,而 PVC 则消耗 PV 资源。Pod 可以请求特定级别的资源(如 CPU 和内存),而 PVC 则可以请求特定大小和访问模式的 PV。当 PV 和 PVC 的参数匹配时,它们将会绑定。
PV 和 PVC 绑定的前提是一些参数必须一致,包括 accessModes、StorageClassName 和 volumeMode,此外 PVC 的 storage 必须小于等于 PV 的 storage。
PVC 与 PV 不同,它是一个命名空间级别的资源。
8.4 PV 的使用
8.4.1 基于 NFS 的使用
基于 NFS 的 Persistent Volume (PV) 在 Kubernetes 中非常实用,特别是在需要多个 Pod 共享同一存储的情况下。
1. 准备 NFS 服务器
确保您有一个配置好的 NFS 服务器,并且您知道它的 IP 地址和共享路径。
2. 创建 Persistent Volume
首先,创建一个 YAML 文件:
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
storage: 10Gi # 指定存储大小
accessModes:
- ReadWriteMany # 允许多个节点读取和写入
nfs:
path: /path/to/nfs # NFS 服务器上共享的路径
server: nfs-server-ip # NFS 服务器的 IP 地址
3. 创建 Persistent Volume Claim
接下来,创建一个 PVC 文件来请求这个 PV:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc
spec:
accessModes:
- ReadWriteMany # 访问模式
resources:
requests:
storage: 10Gi # 请求的存储大小
4. 应用 YAML 文件
使用以下命令应用 PV 和 PVC 的配置:
kubectl apply -f nfs-pv.yaml
kubectl apply -f nfs-pvc.yaml
5. 验证 PV 和 PVC 的状态
可以使用以下命令检查 PV 和 PVC 的状态,确保它们正确绑定:
kubectl get pv
kubectl get pvc
PV 和 PVC 的状态应该是 Bound,表示它们成功绑定。
6. 在 Pod 中使用 PVC
创建一个 Pod 的 YAML 文件来使用 PVC:
apiVersion: v1
kind: Pod
metadata:
name: nfs-pod
spec:
containers:
- name: nfs-container
image: busybox
command: ["sh", "-c", "sleep 3600"] # 仅保持 Pod 运行
volumeMounts:
- mountPath: /mnt/nfs # 容器中挂载的路径
name: nfs-storage
volumes:
- name: nfs-storage
persistentVolumeClaim:
claimName: nfs-pvc # 使用的 PVC 名称
7. 应用 Pod 配置
使用以下命令创建 Pod:
kubectl apply -f nfs-pod.yaml
8. 验证 Pod 和 NFS 挂载
通过以下命令检查 Pod 的状态:
kubectl get pods
如果 Pod 正常运行,可以进入容器并检查 NFS 挂载是否成功:
kubectl exec -it nfs-pod -- sh
在容器内,您可以检查 /mnt/nfs 路径,以确认 NFS 存储已正确挂载。
8.4.2 基于 Ceph 的使用
Ceph 是一个开源的分布式存储系统,支持块存储、文件存储和对象存储。在 Kubernetes 中,使用 Ceph 作为 Persistent Volume (PV) 的解决方案可以提供高可用性、可扩展性和容错能力。
1. 准备 Ceph 集群
确保你已经有一个运行中的 Ceph 集群。可以通过以下步骤来安装和配置 Ceph:
- 安装 Ceph:可以使用 Ceph 部署工具(如 ceph-deploy 或手动安装)来设置集群。
- 创建池(Pool):在 Ceph 中创建一个存储池,用于存储数据。
ceph osd pool create mypool 128
2. 安装 Ceph CSI 驱动
Kubernetes 使用 Container Storage Interface (CSI) 驱动来与存储系统进行交互。你需要安装 Ceph 的 CSI 驱动:
- 使用 Helm 安装 Ceph CSI:
helm repo add ceph-csi https://ceph.github.io/csi-charts
helm repo update
helm install ceph-csi ceph-csi/ceph-csi --namespace kube-system
- 安装前确保已经配置好 Kubernetes 集群和 kubectl 工具。
3. 创建 StorageClass
StorageClass 用于定义存储的类型和参数。创建一个 StorageClass 来指定使用 Ceph RBD(RADOS Block Device):
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ceph-rbd
provisioner: rbd.csi.ceph.com
parameters:
clusterID: <ceph-cluster-id>
pool: mypool
imageFormat: "2"
imageFeatures: "layering"
reclaimPolicy: Delete
volumeBindingMode: Immediate
4. 创建 PersistentVolumeClaim (PVC)
接下来,创建一个 PVC,以请求所需的存储:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: ceph-rbd
5. 创建 Pod 使用 PVC
一旦 PVC 被绑定,你可以创建 Pod 来使用这个 PVC:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: nginx
volumeMounts:
- mountPath: "/mnt/data"
name: my-storage
volumes:
- name: my-storage
persistentVolumeClaim:
claimName: my-pvc
6. 验证
- 查看 PVC 和 PV 状态:
kubectl get pvc
kubectl get pv
- 查看 Pod 状态:
kubectl get pods
确保 Pod 正常运行,并且能够访问 Ceph 存储。
7. 监控和管理
使用 Ceph 提供的管理工具(如 ceph status)来监控集群的状态和性能。
8.5 动态存储 StorageClass
8.5.1 什么是 StorageClass
在 Kubernetes 中,StorageClass(简称 SC)是一种资源对象,类似于 IngressClass,它抽象了特定类型的存储系统(如 Ceph、NFS),并充当 PVC 和 PV 之间的“协调者”,帮助 PVC 找到合适的 PV。
管理员只需创建一个 StorageClass,并将其链接到不同的后端存储(如 Ceph、GlusterFS、NFS 或其他云存储)。在满足存储需求时,只需创建一个指向该 StorageClass 的 PVC,StorageClass 将自动为 Pod 创建 PV。对于 StatefulSet,volumeClaimTemplate 可以为每个 Pod 自动申请一个 PVC。要实现 PV 的自动创建,还需要在集群中部署相应存储提供商的 Provisioner。
8.5.2 使用 StorageClass
下面是一个使用 NFS(网络文件系统)作为后端存储的 Kubernetes StorageClass(SC)示例,包括 YAML 配置和使用案例。
使用前确保您已经有了一个可以使用的 NFS 服务器。
1. 创建 StorageClass
首先,您需要创建一个 StorageClass,以下是一个简单的 StorageClass YAML 配置示例:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-sc
provisioner: example.com/nfs # 使用的 NFS provisioner
reclaimPolicy: Delete # 回收策略,删除 PVC 时删除 PV
volumeBindingMode: Immediate # 立即绑定
这里的 provisioner 值取决于您使用的 NFS provisioner,可能需要根据实际情况进行调整。
2. 创建 PVC
创建一个 PVC,使用前面定义的 StorageClass。以下是一个示例 PVC 配置:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc
namespace: default
spec:
accessModes:
- ReadWriteMany # 访问模式
resources:
requests:
storage: 5Gi # 申请 5Gi 的存储
storageClassName: nfs-sc # 使用的 StorageClass 名称
3. 在 Pod 中使用 PVC
您可以将 PVC 挂载到 Pod 中,以使用 NFS 存储。以下是一个示例 Pod 配置:
apiVersion: v1
kind: Pod
metadata:
name: nfs-pod
namespace: default
spec:
containers:
- name: myapp
image: myapp:latest
volumeMounts:
- mountPath: /data # 容器中的挂载路径
name: nfs-storage
volumes:
- name: nfs-storage
persistentVolumeClaim:
claimName: nfs-pvc # 使用之前创建的 PVC
8.6 CSI:使用 Ceph 为 K8S 提供持久存储
CSI(Container Storage Interface)是一个用于容器编排系统(如 Kubernetes)与存储系统之间的标准接口。该标准相当于在容器编排平台和存储之间提供了一个 "桥梁",只要存储平台实现了这个接口,就能为编排平台提供存储功能。
CSI 标准将存储代码下沉到存储厂商,使得 Kubernetes 维护人员无需关注存储细节,可以专注于 Kubernetes 的核心代码。这种开发方式被称为 out-of-tree,意指在 Kubernetes 核心代码外维护各种存储接入实现。而之前的 Volume、PV 和 StorageClass 则属于 in-tree 开发方式,意味着这些存储接入是在 Kubernetes 内部维护的。相比之下,out-of-tree 方法被认为是更优的实现方式,因此许多 in-tree 的实现正在逐渐向 out-of-tree 迁移。
配置存储厂商的 provisioner 就是 out-of-tree 的实现方式。在 CSI(Container Storage Interface)中,provisioner 是负责动态创建和管理存储卷的组件。它通过 CSI 插件与存储后端进行交互。
K8S 集群配置 Ceph 待补充。
评论区