跳转至

在 GKE 和 EKS 上使用本地持久化存储卷

在 K8s 中,本地持久化存储卷(Local Persistent Volumes,Local PV)直接使用节点的本地磁盘目录存储容器数据。相比网络存储,Local PV 提供更高的 IOPS 和更低的读写延迟,适合数据密集型应用。本文介绍如何在 GKE(Google Kubernetes Engine)EKS(Amazon Elastic Kubernetes Service)中使用 Local PV 以及在使用 Local PV 过程中节点发生故障的处理方法。

虽然使用 Local PV 能提升性能,但是不同于网络存储,本地存储数据不会自动备份。如果节点因任何原因停止,本地存储上的所有数据可能会丢失。因此,使用 Local PV 时,需要在服务可用性、数据持久性和灵活性方面做出一定权衡取舍。

原理介绍

NebulaGraph Operator 实现了存储卷 Provisioner 接口。Provisioner 接口负责创建和删除 Persistent Volume 对象。通过存储卷 Provisioner,您可按需创建 Local PV。NebulaGraph Operator 根据集群配置文件中定义的 PVC 和 StorageClass,自动创建 PVC 并绑定到对应 Local PV 上。

当 Provisioner 接口创建 Local PV 时,Provisioner 控制器创建local类型的 PV,并且设置nodeAffinity字段,这样将使用local类型的 PV 的 Pod 被调度到特定节点上。当删除 Local PV 时,Provisioner 控制器移除local类型的 PV 对象,并清理节点上的存储资源。

前提条件

已安装 NebulaGraph Operator。详情参见安装 NebulaGraph Operator

操作步骤

以下示例所创建的资源均处于默认命名空间default中。

  1. 创建具备本地 SSD 的节点池。

    gcloud container node-pools create "pool-1" --cluster "gke-1" --region us-central1 --node-version "1.27.10-gke.1055000" --machine-type "n2-standard-2" --local-nvme-ssd-block count=2 --max-surge-upgrade 1 --max-unavailable-upgrade 0 --num-nodes 1 --enable-autoscaling --min-nodes 1 --max-nodes 2
    

    关于创建具备本地 SSD 节点池的参数解释,请参见创建具备本地 SSD 的节点池

  2. 使用 DaemonSet 配置 RAID 并对磁盘进行格式化。

    1. 下载 gke-daemonset-raid-disks.yaml 文件。

    2. 部署 RAID 磁盘 DaemonSet。DaemonSet 会在所有本地 SSD 磁盘上设置 RAID 0 阵列,并将设备格式化为 ext4 文件系统。

      kubectl apply -f gke-daemonset-raid-disks.yaml
      

  3. 部署 Local PV Provisioner。

    1. 下载 local-pv-provisioner.yaml 文件。
    2. 部署 Local PV Provisioner。
      kubectl apply -f local-pv-provisioner.yaml
      
  4. 在集群配置文件中,通过spec.storaged.dataVolumeClaimsspec.metad.dataVolumeClaim定义的 PVC 和 StorageClass 来自动创建 Local PV。其中,StorageClass 需要配置成local-nvme。具体操作步骤,参见创建NebulaGraph集群

    NebulaGraph集群的部分配置
    ...
    metad:
      dataVolumeClaim:
        resources:
          requests:
            storage: 2Gi
        storageClassName: local-nvme
    storaged:
      dataVolumeClaims:
      - resources:
          requests:
            storage: 2Gi
        storageClassName: local-nvme  
    ...
    
  5. 查看 PV 列表。

    kubectl get pv
    

    返回:

    NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                     STORAGECLASS   REASON   AGE
    pvc-01be9b75-9c50-4532-8695-08e11b489718   5Gi        RWO            Delete           Bound    default/storaged-data-nebula-storaged-0   local-nvme              3m35s
    pvc-09de8eb1-1225-4025-b91b-fbc0bcce670f   5Gi        RWO            Delete           Bound    default/storaged-data-nebula-storaged-1   local-nvme              3m35s
    pvc-4b2a9ffb-9000-4998-a7bb-edb825c872cb   5Gi        RWO            Delete           Bound    default/storaged-data-nebula-storaged-2   local-nvme              3m35s
    ...
    
  6. 查看 PV 的详细信息。

    kubectl get pv pvc-01be9b75-9c50-4532-8695-08e11b489718 -o yaml
    

    返回:

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      annotations:
        local.pv.provisioner/selected-node: gke-snap-test-snap-test-591403a8-xdfc
        nebula-graph.io/pod-name: nebula-storaged-0
        pv.kubernetes.io/provisioned-by: nebula-cloud.io/local-pv
      creationTimestamp: "2024-03-05T06:12:32Z"
      finalizers:
      - kubernetes.io/pv-protection
      labels:
        app.kubernetes.io/cluster: nebula
        app.kubernetes.io/component: storaged
        app.kubernetes.io/managed-by: nebula-operator
        app.kubernetes.io/name: nebula-graph
      name: pvc-01be9b75-9c50-4532-8695-08e11b489718
      resourceVersion: "9999469"
      uid: ee28a4da-6026-49ac-819b-2075154b4724
    spec:
      accessModes:
      - ReadWriteOnce
      capacity:
        storage: 5Gi
      claimRef:
        apiVersion: v1
        kind: PersistentVolumeClaim
        name: storaged-data-nebula-storaged-0
        namespace: default
        resourceVersion: "9996541"
        uid: 01be9b75-9c50-4532-8695-08e11b489718
      local:
        fsType: ext4
        path: /mnt/disks/raid0
      nodeAffinity:
        required:
          nodeSelectorTerms:
          - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
              - gke-snap-test-snap-test-591403a8-xdfc
      persistentVolumeReclaimPolicy: Delete
      storageClassName: local-nvme
      volumeMode: Filesystem
    status:
      phase: Bound    
    
  1. 创建具备 Instance Store 的节点池。

    eksctl create nodegroup  --instance-types m5ad.2xlarge  --nodes 3  --cluster eks-1
    

    关于创建的节点池的参数解释,请参见创建托管节点池

  2. 使用 DaemonSet 配置 RAID 并对磁盘进行格式化。

    1. 下载 eks-daemonset-raid-disks.yaml 文件。

    2. 根据步骤 1 中创建的节点类型,按需修改eks-daemonset-raid-disks.yaml文件中的nodeSelector.node.kubernetes.io/instance-type字段的值。

          spec:
            nodeSelector:
              node.kubernetes.io/instance-type: "m5ad.2xlarge"
      

    3. 安装 nvme-cli。

      • Ubuntu 和 Debian 系统
        sudo apt-get update
        sudo apt-get install -y nvme-cli
        
      • CentOS 和 RHEL 系统
        sudo yum install -y nvme-cli
        
    4. 部署 RAID 磁盘 DaemonSet。DaemonSet 会在所有本地 SSD 磁盘上设置 RAID 0 阵列,并将设备格式化为 ext4 文件系统。

      kubectl apply -f gke-daemonset-raid-disks.yaml
      

  3. 部署 Local PV Provisioner。

    1. 下载 local-pv-provisioner.yaml 文件。
    2. 部署 Local PV Provisioner。
      kubectl apply -f local-pv-provisioner.yaml
      
  4. 在集群配置文件中,通过spec.storaged.dataVolumeClaimsspec.metad.dataVolumeClaim定义的 PVC 和 StorageClass 来自动创建 Local PV。其中,StorageClass 需要配置成local-nvme。具体操作步骤,参见创建NebulaGraph集群

    NebulaGraph集群的部分配置
    metad:
      dataVolumeClaim:
        resources:
          requests:
            storage: 2Gi
        storageClassName: local-nvme
    storaged:
      dataVolumeClaims:
      - resources:
          requests:
            storage: 2Gi
        storageClassName: local-nvme  
    
  5. 查看 PV 列表。

    kubectl get pv
    

    返回:

    NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                     STORAGECLASS   REASON   AGE
    pvc-290c15cc-a302-4463-a591-84b7217a6cd2   5Gi        RWO            Delete           Bound    default/storaged-data-nebula-storaged-0   local-nvme              3m40s
    pvc-fbb3167f-f556-4a16-ae0e-171aed0ac954   5Gi        RWO            Delete           Bound    default/storaged-data-nebula-storaged-1   local-nvme              3m40s
    pvc-6c7cfe80-0134-4573-b93e-9b259c6fcd63   5Gi        RWO            Delete           Bound    default/storaged-data-nebula-storaged-2   local-nvme              3m40s
    ...
    
  6. 查看 PV 的详细信息。

    kubectl get pv pvc-290c15cc-a302-4463-a591-84b7217a6cd2 -o yaml
    

    返回:

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      annotations:
        local.pv.provisioner/selected-node: ip-192-168-77-60.ec2.internal
        nebula-graph.io/pod-name: nebula-storaged-0
        pv.kubernetes.io/provisioned-by: nebula-cloud.io/local-pv
      creationTimestamp: "2024-03-04T07:51:32Z"
      finalizers:
      - kubernetes.io/pv-protection
      labels:
        app.kubernetes.io/cluster: nebula
        app.kubernetes.io/component: storaged
        app.kubernetes.io/managed-by: nebula-operator
        app.kubernetes.io/name: nebula-graph
      name: pvc-290c15cc-a302-4463-a591-84b7217a6cd2
      resourceVersion: "7932689"
      uid: 66c0a2d3-2914-43ad-93b5-6d84fb62acef
    spec:
      accessModes:
      - ReadWriteOnce
      capacity:
        storage: 5Gi
      claimRef:
        apiVersion: v1
        kind: PersistentVolumeClaim
        name: storaged-data-nebula-storaged-0
        namespace: default
        resourceVersion: "7932688"
        uid: 8ecb5d96-004b-4672-bac4-1355ae15eae4
      local:
        fsType: ext4
        path: /mnt/disks/raid0
      nodeAffinity:
        required:
          nodeSelectorTerms:
          - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
              - ip-192-168-77-60.ec2.internal
      persistentVolumeReclaimPolicy: Delete
      storageClassName: local-nvme
      volumeMode: Filesystem
    status:
      phase: Bound    
    

云上环境中 Local PV 的故障转移

使用网络存储(如 AWS EBS、Google Cloud Persistent Disk、Azure Disk Storage、Ceph、NFS 等)作为 PV,存储资源不依赖于任何特定节点,因此无论 Pod 被调度到哪个节点,都能挂载并使用此存储资源。然而,使用本地存储盘作为 PV 时,由于节点亲和性(NodeAffinity),存储资源只能被特定节点上的 Pod 使用。

NebulaGraph的 Storage 服务具备数据冗余能力,可以设置多个奇数分片副本。节点故障时,关联分片会自动迁移到健康节点。但是,使用 Local PV 的 Storage Pod 由于节点亲和性,不能在其他节点运行,必须等待节点恢复。若要在其他节点运行,需要解除 Pod 与 Local PV 的绑定。

针对使用 Local PV 过程中发生节点故障的情况,NebulaGraph Operator 支持结合云上环境的资源弹性伸缩能力进行自动故障转移操作。通过在集群的配置文件中设置spec.enableAutoFailovertrue,自动解除 Pod 与 Local PV 的绑定,从而使 Pod 能在其他节点上运行。

示例如下:

...
spec:
  # 开启自动故障转移
  enableAutoFailover: true
  # Storage 服务为`OFFLINE`状态后等待自动故障转移的时间。
  # 默认值 5 分钟。
  # 如果 Storage 服务在此期间内恢复正常状态,不会触发故障转移。
  failoverPeriod: "2m"
  ...

最后更新: September 6, 2024