接着k8s实战开始讲,之前讲到k8s集群Deployment的pod高可用的时候有说到我设置对应的副本数以后,当 Pod 因节点故障或手动删除而终止时,Deployment 会自动创建新的 Pod 替换。那这个替换后的这个pod里面的数据还是之前的数据么?怎么做到数据不丢失?

Kubernetes集群中存储数据通常涉及以下几个关键步骤和概念

1. Volume

Volume指的是存储卷,包含可被Pod中容器访问的数据目录,容器中的文件在磁盘上是临时存放的,当容器崩溃时文件会丢失,同时无法在多个Pod中共享文件,通过使用存储卷可以解决这两个问题。

Kubernetes支持很多类型的卷。Pod 可以同时使用任意数目的卷类型。临时卷类型的生命周期与Pod相同,但持久卷可以比Pod 的存活期长。当Pod不再存在时,Kubemetes 也会销毁临时卷;不过Kubemetes不会销毁持久卷。对于给定 Pod 中任何类型的卷,在容器重启期间数据都不会丢失。

卷的核心是一个目录,其中可能存有数据,Pod 中的容器可以访问该目录中的数据。所采用的不同卷的类型将决定该目录如何形的、使用何种介质保存数据以及目录中存放的内容。常用的卷类型有configMap、emptyDir、local、nfs、secret等。

2. PV和PVC

  • PV:集群级别的存储资源,由管理员创建,定义了存储的容量、访问模式(如ReadWriteOnce、ReadOnlyMany、ReadWriteMany)和存储类等。
  • PVC:用户通过PVC向集群请求存储资源,类似于资源配额。PVC会绑定到一个PV,提供存储空间供Pod使用。

3. 存储类型

Kubernetes支持多种存储类型,包括:
NFS:网络文件系统,适合共享存储需求。
iSCSI:基于IP的SAN存储,提供块存储。
Ceph:分布式存储系统,提供高可用性和可扩展性。
GlusterFS:分布式文件系统,适合大规模存储需求。
云存储:如AWS EFS、EBS,Azure File Storage,GCP Filestore等,利用云服务提供商的存储解决方案。

4. 配置存储

  • 根据选择的存储类型,配置相应的存储后端。例如,使用NFS时,需要配置NFS服务器并确保K8s节点能够访问该服务器。
  • 对于云存储,可能需要配置云提供商的特定驱动或插件,以支持动态存储供应。

5. 创建PV和PVC

  • PV配置:编写YAML文件定义PV,指定存储类型、容量、访问模式等。
  • PVC配置:编写YAML文件定义PVC,请求特定的存储容量和访问模式。

6. 挂载存储到Pod

在Pod的YAML文件中,指定要使用的PVC,并挂载到Pod的指定路径。

7. 数据持久化

  • 使用网络存储(如NFS、云存储)可以实现数据的持久化,即使Pod被重新调度到其他节点,数据仍然存在。
  • 本地存储适合临时数据,但不保证数据持久性。

8. StorageClasses

StorageClass用于动态供应存储卷,根据存储需求自动创建PV。
示例:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: my-storage-class
provisioner: example.com/nfs
parameters:
  nfsServer: nfs.example.com
  nfsPath: /exports/data

9. 云存储集成

对于云平台,如AWS,需要配置云存储驱动(如aws-ebs-csi-driver)以支持EBS卷的动态供应。
示例配置:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: aws-ebs
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
  zone: us-west-2a

10. 性能和可靠性

  • 选择合适的存储类型和配置,以满足应用的性能需求。例如,高性能应用可能需要使用块存储或高端云存储解决方案。
  • 监控存储性能,确保存储I/O不会成为瓶颈

    11. 实际操作示例

  • 创建PV:

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: my-pv
    spec:
      storageClassName: nfs
      capacity:
          storage: 10Gi
      accessModes:
          - ReadWriteOnce
      nfs:
        server: 10.10.2.242
        path: /home/nfs
    #配置文件详解
    apiVersion: v1                  # 使用 Kubernetes 核心 API 版本
    kind: PersistentVolume          # 定义资源类型为 PersistentVolume (PV)
    metadata:
    name: my-pv                   # PV 名称,集群内唯一标识
    spec:
    storageClassName: nfs         # 指定 StorageClass 名称(需与 PVC 匹配)
    capacity:
      storage: 10Gi               # PV 的存储容量(PVC 请求不可超过此值)
    accessModes:
      - ReadWriteOnce             # 访问模式:单节点读写,ReadOnlyMany表示多节点只读,ReadWriteMany表示多节点读写
    nfs:                          # 存储后端类型为 NFS
      server: 10.10.2.242         # NFS 服务器 IP 地址
      path: /home/nfs             # NFS 共享路径

    image.png

  • 创建PVC

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: my-pvc
    spec:
      accessModes:
          - ReadWriteOnce
      resources:
          requests:
              storage: 5Gi
      storageClassName: nfs
    apiVersion: v1                  # 使用 Kubernetes 核心 API 版本
    kind: PersistentVolumeClaim     # 定义资源类型为 PersistentVolumeClaim (PVC)
    metadata:
    name: my-pvc                  # PVC 名称,集群内唯一标识
    spec:
    accessModes:
      - ReadWriteOnce             # 访问模式:单节点读写,ReadOnlyMany表示多节点只读,ReadWriteMany表示多节点读写
    resources:
      requests:
        storage: 5Gi              # 请求的存储容量为 5Gi
    storageClassName: nfs         # 指定关联的 StorageClass 名称

    image.png

  • 创建Pod

    apiVersion: v1
    kind: Pod
    metadata:
    name: my-pod
    spec:
    containers:
    - name: my-container
      image: my-image
      volumeMounts:
      - mountPath: "/usr/share/nginx/"
        name: my-storage
    volumes:
    - name: my-storage
      persistentVolumeClaim:
        claimName: my-pvc
    
    #配置文件详解
    apiVersion: v1                # 指定 Kubernetes API 版本
    kind: Pod                     # 定义资源类型为 Pod
    metadata:                     # 元数据部分
    name: mynginx               # Pod 的名称为 `mynginx`
    spec:                         # Pod 的详细配置
    containers:                 # 定义容器列表
    - name: nginx               # 第一个容器的名称是 `nginx`
      image: nginx:1.20         # 容器使用的镜像为 `nginx:1.20`
      volumeMounts:             # 容器挂载的卷配置
      - mountPath: "/usr/share/nginx/"      # 将卷挂载到容器内的 `/usr/share/nginx/` 目录
        name: my-storage        # 挂载的卷名称是 `my-storage`
    volumes:                    # 定义 Pod 级别的卷列表
    - name: my-storage          # 卷名称是 `my-storage`
      persistentVolumeClaim:    # 卷类型为持久化存储(PVC)
        claimName: my-pvc       # 使用的 PVC 名称是 `my-pvc`

    image.png
    image.png
    挂载到Pod:
    如上文所示,Pod配置中挂载PVC到指定路径。

    12. 注意事项

  • 确保存储后端的网络配置正确,允许K8s节点访问存储资源。
  • 监控存储资源的使用情况,避免超出容量限制。
  • 备份和恢复策略,确保数据安全。
    通过以上步骤,你可以在Kubernetes集群中有效地管理和存储数据,满足不同应用的需求

思考:k8s创建存储好麻烦啊,直接挂载NFS对应目录就行了,为啥还要创建pv和pvc呢?
理论上可以直接在Pod中挂载NFS目录(如下示例),但这种方式有以下缺点:

apiVersion: v1
kind: Pod
metadata:
    name: my-pod
spec:
    containers:
    - name: my-container
      image: nginx:1.20
      volumeMounts:
        - name: nfs-vol
          mountPath: /usr/share/nginx/html
  volumes:
    - name: nfs-vol
      nfs:
        server: 10.10.2.242
        path: /home/nfs

缺点分析:

1. 硬编码存储配置:
  • 存储服务器的IP、路径等信息直接写在Pod定义中,导致:
  • 跨环境迁移困难(如测试环境到生产环境)。
  • 存储配置无法复用,每个Pod都要重复配置。
2. 权限和安全性问题:
  • 直接暴露NFS服务器信息,可能存在安全风险(如权限泄露)。
  • 无法统一控制存储资源的访问权限(比如限制某些命名空间只能使用特定存储)。
3. 无法动态分配存储:
  • 如果存储资源需要动态创建(如云存储卷),直接挂载无法实现自动化。

    4. 缺乏生命周期管理:
  • 删除Pod时,直接挂载的存储卷不会自动清理(如云存储卷需要手动释放)。

    为什么需要PV和PVC?

    PV和PVC的设计目标是解耦存储配置和应用部署,解决以下问题:

1. 存储资源抽象化

  • PV(PersistentVolume) :定义存储资源的物理属性(容量、类型、访问模式等)。
  • PVC(PersistentVolumeClaim) :声明应用所需的存储资源(容量、访问模式等)。
  • 优势:应用开发者无需关心底层存储细节(如NFS服务器IP),只需声明需求(如“需要10Gi的可读写存储”)。

2. 动态存储分配

StorageClass:通过定义存储类(如nfs-storage、aws-ebs),可以动态创建PV。
示例:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-storage
provisioner: example.com/nfs  # 需要NFS Provisioner自动创建PV
parameters:
  server: 10.10.2.242
  path: /home/nfs

当用户创建PVC时,Kubernetes会自动创建对应的PV,无需手动配置。

3. 跨环境兼容性

  • 开发、测试、生产环境可能使用不同的存储后端(如本地NFS、云存储)。
  • 通过PV/PVC,应用无需修改YAML文件即可适配不同环境。

4. 权限和配额管理

集群管理员可以统一控制PV的访问权限(如RBAC)。
通过PVC限制资源使用(如某个命名空间只能申请特定大小的存储)。

5. 生命周期管理

PV可以绑定到PVC的生命周期(如删除PVC时自动释放PV)。

思考:如何简化PV/PVC的使用?
如果觉得手动创建PV/PVC太麻烦,可以通过以下方式简化:

1. 使用StorageClass动态创建PV

  • 前提:部署NFS Provisioner(如nfs-subdir-external-provisioner),它会根据PVC自动创建PV。
  • 操作步骤:
    (1)安装NFS Provisioner。
    (2)创建StorageClass:

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
    name: nfs-storage
    provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
    parameters:
    server: nfs-server.example.com
    path: /exports/data
    mountOptions: ["nfsvers=4.1"]

    (3)创建PVC(无需手动创建PV):

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
    name: my-pvc
    spec:
    storageClassName: nfs-storage
    accessModes: [ReadWriteOnce]
    resources:
      requests:
        storage: 10Gi

    (4)Pod挂载PVC:

    volumes:
    - name: my-storage
      persistentVolumeClaim:
        claimName: my-pvc

2. 直接挂载NFS目录的替代方案

如果仍希望直接挂载NFS目录,可以使用以下方法(不推荐长期使用):

volumes:
  - name: nfs-vol
    nfs:
      server: nfs-server.example.com
      path: /exports/data

但需注意前文提到的缺点。
总结
直接挂载NFS:适合临时测试或简单场景,但缺乏灵活性。
PV/PVC:适合生产环境,提供标准化、动态分配和安全性。
终极简化方案:通过StorageClass + NFS Provisioner实现自动化。


苦逼的小运维
1 声望1 粉丝