一、K8s 持久化存储相关概念引入

在 Kubernetes(K8s)的世界里,应用程序的数据存储是一个很关键的问题。在传统的部署模式中,数据存储相对简单,因为服务器和存储是绑定在一起的。但在 K8s 这种容器编排的环境下,容器的生命周期是短暂的,数据需要一种方式能够持久保存,不会因为容器的销毁而丢失,这就引入了持久化存储的概念。

PV 和 PVC

PV(PersistentVolume),也就是持久卷,它是集群层面的存储资源,就像是预先准备好的一个个“仓库”。这些“仓库”是由系统管理员创建的,与具体的存储后端绑定,比如 NFS(网络文件系统)、iSCSI 等。

PVC(PersistentVolumeClaim),持久卷声明,它是用户对 PV 的请求。就好比你是一个租客,PVC 就是你向房东提出的租房申请,描述了你需要多大的存储空间、访问模式等需求。

StorageClass

StorageClass 是用来动态供应 PV 的一种机制。在没有 StorageClass 之前,创建 PV 需要管理员手动去设置,过程比较繁琐。有了 StorageClass 之后,当用户创建 PVC 时,K8s 可以根据 StorageClass 的配置自动创建合适的 PV,实现了存储资源的动态分配。

NFS 存储

NFS 是一种网络文件系统,它允许不同的计算机通过网络共享文件。在 K8s 中,NFS 可以作为 PV 的存储后端,多个 Pod 可以通过 NFS 共享数据,这样就为数据的持久化和共享提供了一个很好的解决方案。

二、详细示例演示

环境准备

假设我们有一个 K8s 集群,并且已经有一台 NFS 服务器,其 IP 地址为 192.168.1.100,共享目录为 /data/nfs。

安装 NFS 客户端

在 K8s 节点上安装 NFS 客户端,以 CentOS 为例:

# 更新系统软件包
yum update -y
# 安装 nfs-utils 包
yum install nfs-utils -y

创建 NFS 存储的 PV 和 PVC

1. 创建 PV

首先,我们创建一个 PV 的 YAML 文件,命名为 nfs-pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 10Gi  # 存储容量为 10GB
  accessModes:
    - ReadWriteMany  # 支持多个 Pod 读写
  persistentVolumeReclaimPolicy: Retain  # 当 PVC 删除时,PV 保留数据
  nfs:
    path: /data/nfs  # NFS 共享目录
    server: 192.168.1.100  # NFS 服务器 IP

解释:

  • apiVersionkind 定义了资源的 API 版本和类型,这里是 PersistentVolume。
  • metadata 中的 name 是 PV 的名称。
  • spec.capacity 定义了存储容量。
  • spec.accessModes 定义了访问模式,ReadWriteMany 表示多个 Pod 可以同时读写。
  • persistentVolumeReclaimPolicy 定义了 PV 的回收策略,Retain 表示保留数据。
  • spec.nfs 部分指定了 NFS 存储的相关信息。

使用以下命令创建 PV:

kubectl apply -f nfs-pv.yaml

2. 创建 PVC

接着,创建一个 PVC 的 YAML 文件,命名为 nfs-pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  accessModes:
    - ReadWriteMany  # 访问模式与 PV 一致
  resources:
    requests:
      storage: 5Gi  # 请求 5GB 的存储空间

解释:

  • apiVersionkind 定义了资源类型为 PersistentVolumeClaim。
  • metadata 中的 name 是 PVC 的名称。
  • spec.accessModes 要和 PV 的访问模式匹配。
  • spec.resources.requests.storage 表示请求的存储容量。

使用以下命令创建 PVC:

kubectl apply -f nfs-pvc.yaml

使用 StorageClass 实现动态供应

1. 创建 StorageClass

创建一个 StorageClass 的 YAML 文件,命名为 nfs-storageclass.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-storageclass
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner  # 存储供应者
parameters:
  pathPattern: "${.PVC.namespace}-${.PVC.name}"  # 存储路径模式
  server: 192.168.1.100  # NFS 服务器 IP
  share: /data/nfs  # NFS 共享目录
  archiveOnDelete: "false"  # 删除 PVC 时不归档数据

解释:

  • apiVersionkind 定义了这是一个 StorageClass 资源。
  • metadata 中的 name 是 StorageClass 的名称。
  • provisioner 指定了存储供应者,这里使用 k8s-sigs.io/nfs-subdir-external-provisioner
  • parameters 部分配置了存储的相关参数,如路径模式、NFS 服务器信息等。

使用以下命令创建 StorageClass:

kubectl apply -f nfs-storageclass.yaml

2. 创建 PVC 使用 StorageClass

创建一个新的 PVC YAML 文件,命名为 nfs-pvc-dynamic.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc-dynamic
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 3Gi
  storageClassName: nfs-storageclass  # 指定使用的 StorageClass

解释:

  • 与之前的 PVC 类似,只是多了 storageClassName 字段,指定使用我们创建的 nfs-storageclass

使用以下命令创建 PVC:

kubectl apply -f nfs-pvc-dynamic.yaml

创建 Pod 使用 PVC

创建一个 Pod 的 YAML 文件,命名为 nfs-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nfs-pod
spec:
  containers:
    - name: nginx-container
      image: nginx:latest
      volumeMounts:
        - name: nfs-volume
          mountPath: /usr/share/nginx/html  # 将 PVC 挂载到容器的指定路径
  volumes:
    - name: nfs-volume
      persistentVolumeClaim:
        claimName: nfs-pvc-dynamic  # 使用之前创建的 PVC

解释:

  • apiVersionkind 定义了这是一个 Pod 资源。
  • spec.containers 部分定义了容器的信息,这里使用 nginx 镜像。
  • volumeMounts 定义了将 PVC 挂载到容器的路径。
  • volumes 部分指定了使用的 PVC。

使用以下命令创建 Pod:

kubectl apply -f nfs-pod.yaml

三、应用场景

数据库存储

对于像 MySQL、PostgreSQL 这样的数据库应用,数据的持久化是至关重要的。使用 K8s 的持久化存储配置,可以确保数据库在容器重启、迁移等情况下数据不会丢失。通过 NFS 存储,还可以实现多个数据库节点之间的数据共享和同步。

日志存储

应用程序产生的日志需要长期保存,以便进行故障排查和性能分析。将日志文件存储在持久化存储中,即使应用程序容器被销毁,日志数据也能保留下来。多个应用程序的 Pod 可以共享同一个 NFS 存储,方便集中管理日志。

文件共享

在一些企业应用中,多个服务可能需要共享一些文件,如配置文件、静态资源等。使用 NFS 作为 K8s 的持久化存储后端,可以轻松实现文件的共享,提高开发和运维的效率。

四、技术优缺点

优点

1. 数据持久化

确保应用程序的数据不会因为容器的生命周期结束而丢失,提高了数据的可靠性。

2. 动态供应

通过 StorageClass 可以实现 PV 的动态创建,减少了管理员手动配置的工作量,提高了资源的分配效率。

3. 数据共享

NFS 存储支持多个 Pod 同时读写,方便实现数据的共享和同步。

4. 灵活性

可以根据不同的应用场景选择不同的存储后端和访问模式,满足多样化的需求。

缺点

1. 性能问题

NFS 是基于网络的存储,网络延迟和带宽可能会影响存储性能,尤其是在高并发读写的场景下。

2. 管理复杂度

虽然 StorageClass 实现了动态供应,但整个持久化存储的配置和管理仍然需要一定的技术知识,对于初学者来说可能有一定的难度。

3. 单点故障

如果 NFS 服务器出现故障,所有依赖该 NFS 存储的 Pod 都将受到影响,存在单点故障的风险。

五、注意事项

1. 权限问题

在使用 NFS 存储时,需要确保 NFS 服务器上的共享目录有正确的权限设置,否则 Pod 可能无法正常读写数据。可以通过修改 NFS 服务器上的 /etc/exports 文件来设置权限。

2. 网络问题

由于 NFS 是基于网络的存储,网络的稳定性和带宽对性能有很大影响。需要确保 K8s 节点和 NFS 服务器之间的网络连接正常,并且有足够的带宽。

3. StorageClass 配置

在使用 StorageClass 时,需要正确配置存储供应者和参数。不同的存储供应者可能有不同的配置要求,需要仔细阅读文档。

4. PV 和 PVC 匹配

PV 和 PVC 的访问模式和存储容量需要匹配,否则 PVC 可能无法绑定到合适的 PV。

六、文章总结

K8s 的持久化存储配置,特别是 PV/PVC 动态供应、StorageClass 与 NFS 存储的集成,为 K8s 集群中的应用程序提供了可靠的数据存储解决方案。通过 PV 和 PVC 的分离,实现了存储资源的抽象和用户请求的解耦;StorageClass 则实现了 PV 的动态供应,提高了资源分配的效率;NFS 存储作为一种常见的存储后端,支持多个 Pod 共享数据,方便实现数据的持久化和共享。

然而,在使用过程中也需要注意一些问题,如权限设置、网络稳定性、StorageClass 配置等。只有正确配置和管理,才能充分发挥 K8s 持久化存储的优势,为企业的容器化应用提供稳定、可靠的数据存储服务。