本文发表已超过一年。较早的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已发生变化。

介绍 Kubernetes 的卷快照 Alpha 版本

Kubernetes v1.12 引入了对卷快照的 Alpha 支持。此功能允许使用 Kubernetes API 原生地创建/删除卷快照,以及从快照创建新卷。

什么是快照?

许多存储系统(例如 Google Cloud Persistent Disks、Amazon Elastic Block Storage 以及许多本地存储系统)都提供了创建持久卷“快照”的能力。快照是卷在特定时间点的副本。快照可以用来供应新卷(预填充快照数据)或将现有卷恢复到先前的状态(由快照表示)。

为什么要在 Kubernetes 中添加快照?

Kubernetes 卷插件系统已经提供了强大的抽象,可自动化块存储和文件存储的供应、挂接和挂载。

支撑所有这些特性的是 Kubernetes 的工作负载可移植性目标:Kubernetes 旨在为分布式系统应用和底层集群之间创建一个抽象层,以便应用无需关注它们运行在哪个集群的具体细节,并且应用部署无需“集群特定”知识。

Kubernetes Storage SIG 将快照操作确定为许多有状态工作负载的关键功能。例如,数据库管理员可能希望在开始数据库操作之前对数据库卷进行快照。

通过在 Kubernetes API 中提供触发快照操作的标准方法,Kubernetes 用户现在可以在不绕过 Kubernetes API(以及手动执行存储系统特定操作)的情况下处理此类用例。

相反,Kubernetes 用户现在能够以与集群无关的方式将快照操作集成到他们的工具和策略中,并且放心地知道无论底层存储如何,它都可以在任意 Kubernetes 集群上工作。

此外,这些 Kubernetes 快照原语作为基本构建块,为开发 Kubernetes 的高级企业级存储管理功能提供了可能,例如数据保护、数据复制和数据迁移。

哪些卷插件支持 Kubernetes 快照?

Kubernetes 支持三种类型的卷插件:in-tree、Flex 和 CSI。有关详细信息,请参阅Kubernetes 卷插件常见问题解答

快照仅支持 CSI 驱动程序(不支持 in-tree 或 Flex)。要使用 Kubernetes 快照功能,请确保在集群上部署了实现快照的 CSI 驱动程序。

截至本博客发布时,以下 CSI 驱动程序支持快照

对其他驱动程序的快照支持正在进行中,应该很快就可以使用。阅读“容器存储接口 (CSI) for Kubernetes 进入 Beta”博客文章,了解有关 CSI 以及如何部署 CSI 驱动程序的更多信息。

Kubernetes 快照 API

与用于管理 Kubernetes 持久卷的 API 类似,Kubernetes 卷快照引入了三个新的 API 对象来管理快照

  • VolumeSnapshot
    • 由 Kubernetes 用户创建,用于请求为指定卷创建快照。它包含有关快照操作的信息,例如拍摄快照的时间戳以及快照是否可以使用。
    • PersistentVolumeClaim 对象类似,此对象的创建和删除代表用户希望创建或删除集群资源(快照)。
  • VolumeSnapshotContent
    • 由 CSI 卷驱动程序在成功创建快照后创建。它包含有关快照的信息,包括快照 ID。
    • PersistentVolume 对象类似,此对象代表集群上的已供应资源(快照)。
    • PersistentVolumeClaimPersistentVolume 对象一样,快照创建后,VolumeSnapshotContent 对象会绑定到创建它的 VolumeSnapshot(一对一映射)。
  • VolumeSnapshotClass
    • 由集群管理员创建,用于描述如何创建快照,包括驱动程序信息、访问快照所需的 Secret 等。

重要的是要注意,与核心的 Kubernetes 持久卷对象不同,这些快照对象被定义为 CustomResourceDefinitions (CRDs)。Kubernetes 项目正在摆脱在 API Server 中预定义资源类型的方式,转而采用 API Server 独立于 API 对象的设计模式。这使得 API Server 可以被 Kubernetes 之外的项目重用,并且使用者(如 Kubernetes)可以简单地将他们所需的资源类型作为 CRD 安装。

支持快照的CSI 驱动程序会自动安装所需的 CRD。Kubernetes 终端用户只需验证其 Kubernetes 集群上是否部署了支持快照的 CSI 驱动程序。

除了这些新对象之外,PersistentVolumeClaim 对象还添加了一个新的 DataSource 字段

type PersistentVolumeClaimSpec struct {
	AccessModes []PersistentVolumeAccessMode
	Selector *metav1.LabelSelector
	Resources ResourceRequirements
	VolumeName string
	StorageClassName *string
	VolumeMode *PersistentVolumeMode
	DataSource *TypedLocalObjectReference
}

这个新的 Alpha 字段使得可以创建一个新卷,并自动用现有快照中的数据预填充。

Kubernetes 快照要求

在使用 Kubernetes 卷快照功能之前,您必须

  • 确保在您的 Kubernetes 集群上部署并运行了一个实现快照的 CSI 驱动程序。
  • 通过新的 Kubernetes Feature Gate 启用 Kubernetes 卷快照功能(Alpha 版本默认禁用)
    • 在 API Server 二进制文件上设置以下标志:--feature-gates=VolumeSnapshotDataSource=true

在创建快照之前,您还需要通过创建 VolumeSnapshotClass 对象并设置 snapshotter 字段指向您的 CSI 驱动程序来指定快照的 CSI 驱动程序信息。在下面的 VolumeSnapshotClass 示例中,CSI 驱动程序是 com.example.csi-driver。每个快照供应者至少需要一个 VolumeSnapshotClass 对象。您还可以通过在类定义中添加 annotation snapshot.storage.kubernetes.io/is-default-class: "true" 来为每个 CSI 驱动程序设置默认的 VolumeSnapshotClass

apiVersion: snapshot.storage.k8s.io/v1alpha1
kind: VolumeSnapshotClass
metadata:
  name: default-snapclass
  annotations:
    snapshot.storage.kubernetes.io/is-default-class: "true"
snapshotter: com.example.csi-driver


apiVersion: snapshot.storage.k8s.io/v1alpha1
kind: VolumeSnapshotClass
metadata:
  name: csi-snapclass
snapshotter: com.example.csi-driver
parameters:
  fakeSnapshotOption: foo
  csiSnapshotterSecretName: csi-secret
  csiSnapshotterSecretNamespace: csi-namespace

您必须根据您的 CSI 驱动程序文档设置任何所需的 opaque 参数。如上例所示,参数 fakeSnapshotOption: foo 以及任何引用的 secret 将在创建和删除快照期间传递给 CSI 驱动程序 com.example.csi-driver。默认的 CSI external-snapshotter 保留了参数键 csiSnapshotterSecretNamecsiSnapshotterSecretNamespace。如果指定,它会获取 Secret 并在创建和删除快照时将其传递给 CSI 驱动程序。

最后,在创建快照之前,您必须使用您的 CSI 驱动程序供应一个卷,并在其中填充一些您想要进行快照的数据(请参阅有关如何创建和使用 CSI 卷的CSI 博客文章)。

使用 Kubernetes 创建新快照

定义 VolumeSnapshotClass 对象并拥有要进行快照的卷后,您可以通过创建 VolumeSnapshot 对象来创建新快照。

快照的源指定了从中创建快照的卷。它有两个参数

  • kind - 必须是 PersistentVolumeClaim
  • name - PVC API 对象的名称

要进行快照的卷的命名空间被假定与 VolumeSnapshot 对象的命名空间相同。

apiVersion: snapshot.storage.k8s.io/v1alpha1
kind: VolumeSnapshot
metadata:
  name: new-snapshot-demo
  namespace: demo-namespace
spec:
  snapshotClassName: csi-snapclass
  source:
    name: mypvc
    kind: PersistentVolumeClaim

VolumeSnapshot 规范中,用户可以指定 VolumeSnapshotClass,其中包含用于创建快照的 CSI 驱动程序信息。创建 VolumeSnapshot 对象时,来自 VolumeSnapshotClass 的参数 fakeSnapshotOption: foo 以及任何引用的 Secret 将通过 CreateSnapshot 调用传递给 CSI 插件 com.example.csi-driver

响应时,CSI 驱动程序触发卷的快照,然后自动创建一个 VolumeSnapshotContent 对象来表示新快照,并将新的 VolumeSnapshotContent 对象绑定到 VolumeSnapshot,使其可以使用。如果 CSI 驱动程序创建快照失败并返回错误,快照控制器会在 VolumeSnapshot 对象的 status 中报告错误,并且不会重试(这与 Kubernetes 中的其他控制器不同,这样做是为了防止在意外时间拍摄快照)。

如果未指定快照类,外部快照程序将尝试查找并为快照设置默认快照类。默认快照类中 snapshotter 指定的 CSI 驱动程序必须与 PVC 的 storage class 中 provisioner 指定的 CSI 驱动程序匹配。

请注意,Kubernetes 快照的 Alpha 版本不提供任何一致性保证。您必须在拍摄快照之前准备您的应用(暂停应用、冻结文件系统等),以确保数据一致性。

您可以通过运行 kubectl describe volumesnapshot 来验证 VolumeSnapshot 对象是否已创建并与 VolumeSnapshotContent 绑定

  • Status 下的 Ready 字段应设置为 true,表示此卷快照已可以使用。
  • Creation Time 字段表示快照实际创建(剪切)的时间。
  • Restore Size 字段表示从快照恢复卷时的最小卷大小。
  • spec 中的 Snapshot Content Name 字段指向为此快照创建的 VolumeSnapshotContent 对象。

使用 Kubernetes 导入现有快照

您始终可以通过手动创建一个 VolumeSnapshotContent 对象来代表现有快照,从而将其导入到 Kubernetes 中。由于 VolumeSnapshotContent 是一个非命名空间的 API 对象,只有系统管理员才有权限创建它。创建 VolumeSnapshotContent 对象后,用户可以创建一个指向 VolumeSnapshotContent 对象的 VolumeSnapshot 对象。外部快照程序控制器在验证快照存在且 VolumeSnapshotVolumeSnapshotContent 对象之间的绑定正确后,会将快照标记为就绪。绑定后,快照即可在 Kubernetes 中使用。

应使用以下字段创建 VolumeSnapshotContent 对象以代表预供应的快照

  • csiVolumeSnapshotSource - 快照标识信息。
    • snapshotHandle - 快照的名称/标识符。此字段是必需的。
    • driver - 用于处理此卷的 CSI 驱动程序。此字段是必需的。它必须与快照控制器中的 snapshotter 名称匹配。
    • creationTimerestoreSize - 这些字段对于预供应卷不是必需的。外部快照程序控制器将在创建后自动更新它们。
  • volumeSnapshotRef - 指向此对象应绑定到的 VolumeSnapshot 对象的指针。
    • namenamespace - 它指定内容绑定到的 VolumeSnapshot 对象的名称和命名空间。
    • UID - 这些字段对于预供应卷不是必需的。外部快照程序控制器将在绑定后自动更新该字段。如果用户指定了 UID 字段,则必须确保它与绑定快照的 UID 匹配。如果指定的 UID 与绑定快照的 UID 不匹配,则该内容被视为孤立对象,控制器将删除它及其关联的快照。
  • snapshotClassName - 此字段是可选的。外部快照程序控制器将在绑定后自动更新该字段。
apiVersion: snapshot.storage.k8s.io/v1alpha1
kind: VolumeSnapshotContent
metadata:
  name: static-snapshot-content
spec:
  csiVolumeSnapshotSource:
    driver: com.example.csi-driver
    snapshotHandle: snapshotcontent-example-id
  volumeSnapshotRef:
    kind: VolumeSnapshot
    name: static-snapshot-demo
    namespace: demo-namespace

应创建一个 VolumeSnapshot 对象以允许用户使用快照

  • snapshotClassName - 卷快照类的名称。此字段是可选的。如果设置,快照类中的 snapshotter 字段必须与快照控制器的 snapshotter 名称匹配。如果未设置,快照控制器将尝试查找默认快照类。
  • snapshotContentName - 卷快照内容的名称。此字段对于预供应卷是必需的。
apiVersion: snapshot.storage.k8s.io/v1alpha1
kind: VolumeSnapshot
metadata:
  name: static-snapshot-demo
  namespace: demo-namespace
spec:
  snapshotClassName: csi-snapclass
  snapshotContentName: static-snapshot-content

一旦创建了这些对象,快照控制器将把它们绑定在一起,并将 Ready 字段(在 Status 下)设置为 True,表示快照已准备好使用。

使用 Kubernetes 从快照创建新卷

要从快照对象的数据预填充来创建新卷,请在 PersistentVolumeClaim 中使用新的 dataSource 字段。它有三个参数

  • name - 表示用作源的快照的 VolumeSnapshot 对象的名称
  • kind - 必须是 VolumeSnapshot
  • apiGroup - 必须是 snapshot.storage.k8s.io

VolumeSnapshot 对象的命名空间被假定与 PersistentVolumeClaim 对象的命名空间相同。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-restore
  Namespace: demo-namespace
spec:
  storageClassName: csi-storageclass
  dataSource:
    name: new-snapshot-demo
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

创建 PersistentVolumeClaim 对象时,它将触发创建新卷,该卷预填充了指定快照中的数据。

作为存储厂商,如何向我的 CSI 驱动程序添加快照支持?

为了实现快照特性,CSI 驱动程序必须支持额外的控制器能力 CREATE_DELETE_SNAPSHOTLIST_SNAPSHOTS,并实现额外的控制器 RPC:CreateSnapshotDeleteSnapshotListSnapshots。有关详细信息,请参阅 CSI 规范

尽管 Kubernetes 对 CSI 卷驱动程序的打包和部署 尽可能减少规定性限制,但它提供了一种 建议的机制,用于在 Kubernetes 上部署任意容器化的 CSI 驱动程序,以简化容器化 CSI 兼容卷驱动程序的部署。

作为此推荐部署过程的一部分,Kubernetes 团队提供了一些 Sidecar(helper)容器,其中包括一个新的 external-snapshotter Sidecar 容器。

external-snapshotter 监听 Kubernetes API 服务器上的 VolumeSnapshotVolumeSnapshotContent 对象,并针对 CSI endpoint 触发 CreateSnapshot 和 DeleteSnapshot 操作。CSI external-provisioner Sidecar 容器也已更新,以支持使用新的 dataSource PVC 字段从快照恢复卷。

为了支持快照特性,建议存储厂商除了部署 external provisioner 和 external attacher 之外,还应将其 CSI 驱动程序与 external-snapshotter Sidecar 容器一起部署在 StatefulSet 中,如下图所示。

在这个 示例部署 YAML 文件中,external provisioner 和 external snapshotter 这两个 Sidecar 容器以及 CSI 驱动程序与 hostpath CSI 插件一起部署在 StatefulSet Pod 中。Hostpath CSI 插件是一个示例插件,不适用于生产环境。

Alpha 版本的限制是什么?

Kubernetes 快照功能的 Alpha 实现有以下限制

  • 不支持将现有卷回滚到快照所代表的先前状态(alpha 仅支持从快照创建新卷)。
  • 不支持从快照对现有 PersistentVolumeClaim 进行“原地恢复”:即,从快照创建新卷,但更新现有的 PersistentVolumeClaim 指向新卷,从而使 PVC 看起来恢复到先前状态(alpha 仅支持通过新的 PV/PVC 使用从快照创建的新卷)。
  • 不提供超出存储系统提供的任何保证之外的快照一致性保证(例如,崩溃一致性)。

接下来是什么?

根据反馈和采用情况,Kubernetes 团队计划在 1.13 或 1.14 版本中将 CSI 快照实现推进到 Beta 阶段。

如何了解更多信息?

在此处查看有关快照功能的其他文档:http://k8s.io/docs/concepts/storage/volume-snapshotshttps://kubernetes-csi.github.io/docs/

如何参与贡献?

这个项目,就像 Kubernetes 的所有项目一样,是来自不同背景的许多贡献者共同努力的成果。

除了参与快照特性工作的贡献者之外

我们非常感谢所有在 Kubernetes Storage SIG 和 CSI 社区中帮助评审项目设计和实现的贡献者,包括但不限于以下人员

如果您有兴趣参与 CSI 或 Kubernetes 存储系统的任何部分的设计和开发,请加入 Kubernetes 存储特别兴趣小组 (SIG)。我们正在快速壮大,始终欢迎新的贡献者。