本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。

原始块卷支持进入 Beta 阶段

Kubernetes v1.13 将原生块存储卷支持提升至 beta 阶段。此功能允许持久卷在容器内部作为块设备而非挂载的文件系统暴露。

什么是块设备?

块设备能够以固定大小的块随机访问数据。硬盘、SSD 和 CD-ROM 驱动器都是块设备的示例。

通常,持久存储是分层实现的,文件系统(如 ext4)位于块设备(如旋转磁盘或 SSD)之上。然后应用程序读写文件,而不是直接操作块。操作系统负责使用指定的文件系统将文件读写到底层设备,以块的形式进行。

值得注意的是,虽然整个磁盘是块设备,但磁盘分区和存储区域网络 (SAN) 设备的 LUN 也是块设备。

为什么要在 Kubernetes 中添加原生块存储卷?

有些特殊应用程序需要直接访问块设备,例如,因为文件系统层引入了不必要的开销。最常见的用例是数据库,它们更喜欢直接在底层存储上组织数据。原生块设备也常用于任何本身实现某种存储服务(软件定义存储系统)的软件。

从程序员的角度来看,块设备是一个非常大的字节数组,通常读写具有最小粒度,通常为 512 字节,但经常是 4K 或更大。

随着在 Kubernetes 内部运行数据库软件和存储基础设施软件变得越来越普遍,Kubernetes 对原生块设备支持的需求也变得越来越重要。

哪些卷插件支持原生块存储?

截至本博客发布时,以下树内卷类型支持原生块存储:

  • AWS EBS
  • Azure Disk
  • Cinder
  • 光纤通道
  • GCE PD
  • iSCSI
  • 本地卷
  • RBD (Ceph)
  • Vsphere

树外 CSI 卷驱动程序 也可能支持原生块存储卷。Kubernetes CSI 对原生块存储卷的支持目前处于 alpha 阶段。请参阅此处的文档。

Kubernetes 原生块存储卷 API

原生块存储卷与普通卷有很多共同之处。两者都通过创建绑定到 PersistentVolume 对象的 PersistentVolumeClaim 对象来请求,并通过将它们包含在 PodSpec 的 volumes 数组中来附加到 Kubernetes 中的 Pod。

但是,有 2 个重要的区别。首先,要请求原生块 PersistentVolumeClaim,您必须在 PersistentVolumeClaimSpec 中设置 volumeMode = "Block"。将 volumeMode 留空等同于指定 volumeMode = "Filesystem",这将导致传统行为。PersistentVolumes 在其 PersistentVolumeSpec 中也有一个 volumeMode 字段,并且 "Block" 类型的 PVC 只能绑定到 "Block" 类型的 PV,而 "Filesystem" 类型的 PVC 只能绑定到 "Filesystem" 类型的 PV。

其次,当在 Pod 中使用原生块存储卷时,您必须在 PodSpec 的容器部分中指定 VolumeDevice 而不是 VolumeMountVolumeDevices 具有 devicePaths 而不是 mountPaths,并且在容器内部,应用程序将在此路径上看到一个设备,而不是挂载的文件系统。

应用程序在容器内部打开、读取和写入设备节点,就像它们在非容器化或虚拟化环境中与系统上的任何块设备交互一样。

创建新的原生块 PVC

首先,确保您选择的存储类关联的 Provisioner 支持原生块存储。然后创建 PVC。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteMany
  volumeMode: Block
  storageClassName: my-sc
  resources:
    requests:
    storage: 1Gi

使用原生块 PVC

当您在 Pod 定义中使用 PVC 时,您可以为块设备选择设备路径,而不是为文件系统选择挂载路径。

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
    - name: my-container
      image: busybox
      command:
        - sleep
        - “3600”
      volumeDevices:
        - devicePath: /dev/block
          name: my-volume
      imagePullPolicy: IfNotPresent
  volumes:
    - name: my-volume
      persistentVolumeClaim:
        claimName: my-pvc

作为存储供应商,我如何为我的 CSI 插件添加原生块设备支持?

CSI 插件的原生块支持仍处于 alpha 阶段,但现在就可以添加支持。CSI 规范详细说明了如何处理具有 BlockVolume 功能而不是 MountVolume 功能的卷请求。CSI 插件可以支持两种类型的卷,或其中一种。有关更多详细信息,请参阅此处的文档。

问题/陷阱

由于块设备实际上是设备,因此可以在容器内部对其进行文件系统卷无法实现的低级操作。例如,实际是 SCSI 磁盘的块设备支持使用 Linux ioctl 向设备发送 SCSI 命令。

但是,默认情况下,Linux 不允许容器在容器内部向磁盘发送 SCSI 命令。为此,您必须授予容器安全上下文 SYS_RAWIO 功能以允许此操作。请参阅此处的文档。

此外,虽然 Kubernetes 保证向容器提供块设备,但不能保证它实际上是 SCSI 磁盘或任何其他类型的磁盘。用户必须要么确保其 Pod 使用所需的磁盘类型,要么只部署可以处理各种块设备类型的应用程序。

我如何了解更多信息?

请查看此处有关快照功能的其他文档:原生块存储卷支持

我如何参与?

加入 Kubernetes 存储 SIG 和 CSI 社区,帮助我们添加更多优秀功能并改进现有功能,例如原生块存储!

https://github.com/kubernetes/community/tree/master/sig-storage https://github.com/container-storage-interface/community/blob/master/README.md

特别感谢所有帮助 Kubernetes 添加块存储卷支持的贡献者,包括: