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


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

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

如需详细了解本地 SSD 对 GKE 上原始块访问的支持,请参阅本地 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 中的存储空间进行问题排查

后续步骤