在 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
中。
-
创建具备本地 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 的节点池。
-
使用 DaemonSet 配置 RAID 并对磁盘进行格式化。
-
部署 RAID 磁盘 DaemonSet。DaemonSet 会在所有本地 SSD 磁盘上设置 RAID 0 阵列,并将设备格式化为 ext4 文件系统。
kubectl apply -f gke-daemonset-raid-disks.yaml
-
部署 Local PV Provisioner。
- 下载 local-pv-provisioner.yaml 文件。
- 部署 Local PV Provisioner。
kubectl apply -f local-pv-provisioner.yaml
-
在集群配置文件中,通过
spec.storaged.dataVolumeClaims
或spec.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 ...
-
查看 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 ...
-
查看 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
-
创建具备 Instance Store 的节点池。
eksctl create nodegroup --instance-types m5ad.2xlarge --nodes 3 --cluster eks-1
关于创建的节点池的参数解释,请参见创建托管节点池。
-
使用 DaemonSet 配置 RAID 并对磁盘进行格式化。
-
根据步骤 1 中创建的节点类型,按需修改
eks-daemonset-raid-disks.yaml
文件中的nodeSelector.node.kubernetes.io/instance-type
字段的值。spec: nodeSelector: node.kubernetes.io/instance-type: "m5ad.2xlarge"
-
安装 nvme-cli。
- Ubuntu 和 Debian 系统
sudo apt-get update sudo apt-get install -y nvme-cli
- CentOS 和 RHEL 系统
sudo yum install -y nvme-cli
- Ubuntu 和 Debian 系统
-
部署 RAID 磁盘 DaemonSet。DaemonSet 会在所有本地 SSD 磁盘上设置 RAID 0 阵列,并将设备格式化为 ext4 文件系统。
kubectl apply -f gke-daemonset-raid-disks.yaml
-
部署 Local PV Provisioner。
- 下载 local-pv-provisioner.yaml 文件。
- 部署 Local PV Provisioner。
kubectl apply -f local-pv-provisioner.yaml
-
在集群配置文件中,通过
spec.storaged.dataVolumeClaims
或spec.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
-
查看 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 ...
-
查看 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.enableAutoFailover
为true
,自动解除 Pod 与 Local PV 的绑定,从而使 Pod 能在其他节点上运行。
示例如下:
...
spec:
# 开启自动故障转移
enableAutoFailover: true
# Storage 服务为`OFFLINE`状态后等待自动故障转移的时间。
# 默认值 5 分钟。
# 如果 Storage 服务在此期间内恢复正常状态,不会触发故障转移。
failoverPeriod: "2m"
...