预配和使用本地 SSD 支持的原始块存储


本页面介绍了如何在 Google Kubernetes Engine (GKE) 集群上预配本地 SSD 存储空间,以及如何配置工作负载以使用连接到集群中节点的本地 SSD 支持的原始块存储空间中的数据。

使用此本地 SSD 选项,您可以更好地控制底层存储,还可以为 Pod 构建自己的节点级缓存,以便为您的应用提供更好的性能。您还可以通过运行 DaemonSet 来配置 RAID 和格式化磁盘来自定义此选项,方法是在本地 SSD 磁盘上安装文件系统。

如需详细了解 GKE 上本地 SSD 对原始块访问的支持,请参阅本地 SSD 简介

须知事项

在开始之前,请确保您已执行以下任务:

  • 启用 Google Kubernetes Engine API。
  • 启用 Google Kubernetes Engine API
  • 如果您要使用 Google Cloud CLI 执行此任务,请安装初始化 gcloud CLI。 如果您之前安装了 gcloud CLI,请运行 gcloud components update 以获取最新版本。

创建具有本地 SSD 支持的原始块存储的集群或节点池

使用带有 --local-nvme-ssd-block 选项的 gcloud CLI 创建具有本地 SSD 支持的原始块存储的集群。

您用于创建集群或节点池的 gcloud CLI 命令取决于您使用的机器类型所属的机器系列代。例如,N1 和 N2 机器类型分别属于第一代和第二代机器系列,而 C3 机器类型属于第三代机器系列。

创建具有本地 SSD 的集群

第 1 代或第 2 代

如果您使用第一代或第二代机器系列中的机器类型,则可以通过指定 --local-nvme-ssd-block count=NUMBER_OF_DISKS 选项来创建集群。该选项指定要挂接到每个节点的本地 SSD 磁盘数量。 数量上限因机器类型和区域而异

要创建集群,请执行以下操作:

gcloud container clusters create CLUSTER_NAME \
    --local-nvme-ssd-block count=NUMBER_OF_DISKS \
    --machine-type=MACHINE_TYPE \
    --release-channel CHANNEL_NAME

替换以下内容:

  • CLUSTER_NAME:集群的名称。
  • NUMBER_OF_DISKS:每个节点上预配的本地固态硬盘的数量。磁盘的最大数量因机器类型和区域而异
  • MACHINE_TYPE:要使用的第一代或第二代机器类型。此字段是必填字段,因为您不能将本地 SSD 与默认的 e2-medium 类型搭配使用。
  • CHANNEL_NAME:包含高于 1.25.3-gke.1800 的 GKE 版本的发布渠道

第 3 代

如果您使用第三代机器系列中的机器类型,请使用 --local-nvme-ssd-block 选项(不使用计数字段)创建集群。GKE 会根据虚拟机类型自动为集群预配本地 SSD 容量。数量上限因机器类型和区域而异

gcloud container clusters create CLUSTER_NAME \
    --machine-type=MACHINE_TYPE \
    --cluster-version CLUSTER_VERSION \
    --local-nvme-ssd-block

替换以下内容:

  • CLUSTER_NAME:集群的名称。
  • MACHINE_TYPE:要使用的第 3 代机器系列中的机器类型。
  • CLUSTER_VERSIONGKE 集群版本,支持在第 3 代机器系列中的机器类型上使用本地 SSD。

创建具有本地 SSD 的节点池

第 1 代或第 2 代

如需创建使用本地 SSD 磁盘进行原始块访问的节点池,请运行以下命令:

gcloud container node-pools create POOL_NAME \
    --cluster=CLUSTER_NAME \
    --machine-type=MACHINE_TYPE \
    --local-nvme-ssd-block count=NUMBER_OF_DISKS

替换以下内容:

  • POOL_NAME:新节点池的名称。
  • CLUSTER_NAME:集群的名称。
  • MACHINE_TYPE:要使用的第一代或第二代机器类型。此字段是必填字段,因为本地 SSD 不能与默认的 e2-medium 类型搭配使用。
  • NUMBER_OF_DISKS:每个节点上预配的本地固态硬盘的数量。磁盘的最大数量因机器类型和区域而异

第 3 代

如果您使用第三代机器系列中的机器类型,请使用 --local-nvme-ssd-block 选项(不使用计数字段)创建集群:

gcloud container node-pools create POOL_NAME \
    --cluster=CLUSTER_NAME \
    --machine-type=MACHINE_TYPE \
    --node-version NODE_VERSION \
    --local-nvme-ssd-block

替换以下内容:

  • POOL_NAME:新节点池的名称。
  • CLUSTER_NAME:集群的名称。
  • MACHINE_TYPE:要使用的第 3 代机器类型中的机器类型。
  • NODE_VERSIONGKE 节点池版本,支持在第三代机器系列中的机器类型上使用本地 SSD。

在节点池中创建的节点包含一个 cloud.google.com/gke-local-nvme-ssd=true 标签。您可以通过运行以下命令来验证标签:

kubectl describe node NODE_NAME

对于挂接到节点池的每个本地 SSD,主机操作系统都会创建一个符号链接(用于访问序号文件夹下的磁盘),以及一个包含通用唯一标识符 (UUID) 的符号链接。例如,如果您使用 --local-nvme-ssd-block 选项创建具有三个本地 SSD 的节点池,则主机操作系统会为磁盘创建以下符号链接:

  • /dev/disk/by-id/google-local-ssd-block0
  • /dev/disk/by-id/google-local-ssd-block1
  • /dev/disk/by-id/google-local-ssd-block2

相应地,主机操作系统还会为磁盘创建以下具有 UUID 的符号链接:

  • /dev/disk/by-uuid/google-local-ssds-nvme-block/local-ssd-GENERATED_UUID1
  • /dev/disk/by-uuid/google-local-ssds-nvme-block/local-ssd-GENERATED_UUID2
  • /dev/disk/by-uuid/google-local-ssds-nvme-block/local-ssd-GENERATED_UUID3

这样就能确保可以使用唯一标识符访问磁盘。

访问本地 SSD 卷

以下示例展示了如何访问本地 SSD 支持的原始块存储。

本地 PersistentVolume

您可以使用 PersistentVolume 将本地 SSD 卷作为 Pod 装载。

如需从本地 SSD 创建 PersistentVolume,您既可以手动创建 PersistentVolume,也可以运行本地卷静态预配工具

本地 PersistentVolume 的限制

  • 本地 PersistentVolume 不支持集群自动扩缩动态预配

  • 升级 GKE 集群或修复节点会删除 Compute Engine 实例,同时也会删除本地 SSD 磁盘上的所有数据。

  • 请勿针对使用本地 SSD 来存储持久性数据的集群或节点池启用节点自动升级节点自动修复。您必须先备份应用数据,然后将数据还原到新的集群或节点池。

  • 当删除、升级、修复或缩减节点时,系统不会自动清理本地 PersistentVolume 对象。我们建议您定期扫描并删除与已删除节点关联的过时本地 PersistentVolume 对象。

手动创建 PersistentVolume

您可以为集群中每个节点上的每个本地 SSD 手动创建 PersistentVolume。

请使用 PersistentVolume 对象中的 nodeAffinity 字段来引用特定节点上的本地 SSD。以下示例展示了运行 Linux 的节点上本地 SSD 的 PersistentVolume 规范:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: "example-local-pv"
spec:
  capacity:
    storage: 375Gi
  accessModes:
  - "ReadWriteOnce"
  persistentVolumeReclaimPolicy: "Retain"
  storageClassName: "local-storage"
  local:
    path: "/mnt/disks/ssd0"
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: "kubernetes.io/hostname"
          operator: "In"
          values:
          - "gke-test-cluster-default-pool-926ddf80-f166"

在此示例中,本地 SSD 磁盘为 RAID 手动进行了配置和格式化,然后装载到节点 gke-test-cluster-default-pool-926ddf80-f166/mnt/disks/ssd0 处。nodeAffinity 字段用于帮助将工作负载分配给具有手动配置为 RAID 的本地 SSD 的节点。如果集群中只有一个节点,或者您为所有节点配置了 RAID,则无需 nodeAffinity 字段。

相应的 PersistenVolumeClaim 规范如下所示:

  kind: PersistentVolumeClaim
  apiVersion: v1
  metadata:
    name: ssd-local-claim
  spec:
    accessModes:
    - ReadWriteOnce
    storageClassName: local-storage
    resources:
      requests:
        storage: 37Gi

如果删除 PersistentVolume,您必须手动清空磁盘中的数据。

运行本地卷静态预配工具

您可以使用本地卷静态预配工具自动为本地 SSD 创建 PersistentVolume。预配工具是一个 DaemonSet,用于管理每个节点上的本地 SSD 磁盘、为它们创建和删除 PersistentVolume 以及在释放 PersistentVolume 时清除本地 SSD 磁盘上的数据。

要运行本地卷静态预配工具,请执行以下操作:

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

    1. 下载 gke-daemonset-raid-disks.yaml 规范。
    2. 部署 RAID 磁盘 DaemonSet。DaemonSet 会在所有本地 SSD 磁盘上设置 RAID 0 阵列,并将设备格式化为 ext4 文件系统。

      kubectl create -f gke-daemonset-raid-disks.yaml
      
  2. 下载 gke-nvme-ssd-block-raid.yaml 规范,并根据需要修改该规范的命名空间字段。

    规范包括以下资源:

    • 预配工具的 ServiceAccount
    • 拥有以下权限的 ClusterRole 和 ClusterRoleBinding:
      • 创建和删除 PersistentVolume 对象
      • 获取 Node 对象
    • 具有适用于 GKE 的预配工具设置的 ConfigMap
    • 用于运行预配工具的 DaemonSet
  3. 部署预配工具:

    kubectl create -f gke-nvme-ssd-block-raid.yaml
    

    预配工具成功运行后,它将为集群中的 RAID 本地 SSD 设备创建一个 PersistentVolume 对象。

  4. 将以下 PersistentVolumeClaim 清单保存为 provisioner-pvc-example.yaml

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: PVC_NAME
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 50Gi
      storageClassName: nvme-ssd-block
    

    PVC_NAME 替换为您的 PersistentVolumeClaim 名称。

  5. 创建 PersistentVolumeClaim:

    kubectl create -f provisioner-pvc-example.yaml
    
  6. 将以下 Pod 清单保存为 provisioner-pod-example.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: POD_NAME
    spec:
      containers:
      - name: "shell"
        image: "ubuntu:14.04"
        command: ["/bin/sh", "-c"]
        args: ["echo 'hello world' > /cache/test.txt && sleep 1 && cat /cache/test.txt && sleep 3600"]
        volumeMounts:
        - mountPath: /cache
          name: local-ssd-storage
      volumes:
      - name: local-ssd-storage
        persistentVolumeClaim:
          claimName: PVC_NAME
    

    POD_NAME 替换为您的 Pod 名称。

  7. 创建 Pod:

    kubectl create -f provisioner-pod-example.yaml
    

启用延迟的卷绑定

为了提升调度性能,我们还建议您使用 volumeBindingMode: WaitForFirstConsumer 创建一个 StorageClass。这会将 PersistentVolumeClaim 绑定延迟到 Pod 调度阶段,以便从可运行 Pod 的适当节点中选择本地固态硬盘。在为可运行的 Pod 选择节点时,此增强的调度行为不仅考虑了 Pod CPU 和内存请求、节点亲和性、Pod 亲和性和反亲和性以及多个 PersistentVolumeClaim 请求,还考虑了哪些节点具有可用的本地固态硬盘。

此示例使用延迟的卷绑定模式:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: "local-nvme"
provisioner: "kubernetes.io/no-provisioner"
volumeBindingMode: "WaitForFirstConsumer"

如需创建具有延迟绑定的 StorageClass,请将 YAML 清单保存到本地文件,并使用以下命令将其应用到集群:

kubectl apply -f filename

问题排查

如需了解问题排查说明,请参阅对 GKE 中的存储空间进行问题排查

后续步骤