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

Kubernetes 1.17 功能:Kubernetes Volume Snapshot 进入 Beta 阶段

Kubernetes Volume Snapshot 功能现已在 Kubernetes v1.17 中进入 Beta 阶段。它最初在 Kubernetes v1.12 中以 Alpha 版本引入,并在 Kubernetes v1.13 中发布了包含破坏性更改的第二个 Alpha 版本。本文总结了 Beta 版本中的变更。

什么是 Volume Snapshot?

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

为什么要在 Kubernetes 中添加 Volume Snapshots?

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

支持所有这些功能的基础是 Kubernetes 的工作负载可移植性目标:Kubernetes 旨在在分布式应用程序和底层集群之间创建一个抽象层,以便应用程序不受其运行集群的特定细节影响,并且应用程序部署不需要“集群特定”知识。

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

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

相反,Kubernetes 用户现在能够以集群无关的方式将快照操作整合到其工具和策略中,并确信无论底层存储如何,它都能在任意 Kubernetes 集群上工作。

此外,这些 Kubernetes 快照原语充当基本构建块,解锁了为 Kubernetes 开发高级企业级存储管理功能的能力,包括应用程序或集群级别的备份解决方案。

Beta 版本有什么新功能?

随着 Volume Snapshot 晋升到 Beta 阶段,此功能现已在标准 Kubernetes 部署中默认启用,而不是可选加入。

Kubernetes Volume Snapshot 功能进入 Beta 阶段还意味着

  • 重塑卷快照 API。
  • CSI external-snapshotter 边车被拆分为两个控制器:一个通用快照控制器和一个 CSI external-snapshotter 边车。
  • 删除 Secret 作为 Annotation 添加到卷快照内容中。
  • 向卷快照 API 对象添加了一个新的 Finalizer,以防止它在绑定到卷快照内容 API 对象时被删除。

Kubernetes Volume Snapshots 要求

如上所述,随着 Volume Snapshot 晋升到 Beta 阶段,此功能现已在标准 Kubernetes 部署中默认启用,而不是可选加入。

为了使用 Kubernetes Volume Snapshot 功能,您必须确保您的 Kubernetes 集群已部署以下组件:

有关详细信息,请参阅下面的部署部分。

哪些驱动程序支持 Kubernetes Volume Snapshots?

Kubernetes 支持三种类型的卷插件:树内、Flex 和 CSI。有关详细信息,请参阅Kubernetes Volume Plugin FAQ

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

阅读博客文章“Kubernetes CSI (Container Storage Interface) GA”,了解有关 CSI 以及如何部署 CSI 驱动程序的更多信息。

截至本文发布时,以下 CSI 驱动程序已更新,支持 Volume Snapshots Beta 功能:

其他CSI 驱动程序的 Beta 级别 Volume Snapshot 支持正在进行中,应该很快就能提供。

Kubernetes Volume Snapshot Beta API

在 Alpha 到 Beta 阶段,Kubernetes 卷快照 API 发生了一些变化。这些变化不向后兼容。这些变化的目的是使 API 定义更加清晰且易于使用。

所做的更改如下:

  • DeletionPolicy 现在是 VolumeSnapshotClassVolumeSnapshotContent 中的必填字段,而不是可选字段。这样用户必须明确指定它,不会造成混淆。
  • VolumeSnapshotSpec 有一个新的必填字段 SourceSource 可以是 PersistentVolumeClaimName(如果动态 Provisioning 快照)或 VolumeSnapshotContentName(如果预 Provisioning 快照)。
  • VolumeSnapshotContentSpec 也有一个新的必填字段 Source。这个 Source 可以是 VolumeHandle(如果动态 Provisioning 快照)或 SnapshotHandle(如果预 Provisioning 卷快照)。
  • VolumeSnapshotStatus 现在包含 BoundVolumeSnapshotContentName,表示 VolumeSnapshot 对象已绑定到 VolumeSnapshotContent
  • VolumeSnapshotContent 现在包含一个 Status,指示内容的当前状态。它有一个字段 SnapshotHandle,指示 VolumeSnapshotContent 代表存储系统上的快照。

Beta 版本的 Kubernetes VolumeSnapshot API 对象

type VolumeSnapshot struct {
        metav1.TypeMeta
        metav1.ObjectMeta

        Spec VolumeSnapshotSpec
        Status *VolumeSnapshotStatus
}
type VolumeSnapshotSpec struct {
	Source VolumeSnapshotSource
	VolumeSnapshotClassName *string
}
// Exactly one of its members MUST be specified
type VolumeSnapshotSource struct {
	// +optional
	PersistentVolumeClaimName *string
	// +optional
	VolumeSnapshotContentName *string
}
type VolumeSnapshotStatus struct {
	BoundVolumeSnapshotContentName *string
	CreationTime *metav1.Time
	ReadyToUse *bool
	RestoreSize *resource.Quantity
	Error *VolumeSnapshotError
}

Beta 版本的 Kubernetes VolumeSnapshotContent API 对象

type VolumeSnapshotContent struct {
        metav1.TypeMeta
        metav1.ObjectMeta

        Spec VolumeSnapshotContentSpec
        Status *VolumeSnapshotContentStatus
}
type VolumeSnapshotContentSpec struct {
         VolumeSnapshotRef core_v1.ObjectReference
         Source VolumeSnapshotContentSource
         DeletionPolicy DeletionPolicy
         Driver string
         VolumeSnapshotClassName *string
}
type VolumeSnapshotContentSource struct {
	// +optional
	VolumeHandle *string
	// +optional
	SnapshotHandle *string
}
type VolumeSnapshotContentStatus struct {
  CreationTime *int64
  ReadyToUse *bool
  RestoreSize *int64
  Error *VolumeSnapshotError
  SnapshotHandle *string
}

Beta 版本的 Kubernetes VolumeSnapshotClass API 对象

type VolumeSnapshotClass struct {
        metav1.TypeMeta
        metav1.ObjectMeta

        Driver string
        Parameters map[string]string
        DeletionPolicy DeletionPolicy
}

如何在我的 Kubernetes 集群上部署 Volume Snapshots 支持?

请注意,除了卷快照 CRD 之外,Volume Snapshot 功能现在还依赖于一个新的通用卷快照控制器。卷快照控制器和 CRD 都独立于任何 CSI 驱动程序。无论集群上部署了多少个 CSI 驱动程序,每个集群上只能运行一个卷快照控制器实例,并安装一套卷快照 CRD。

因此,强烈建议 Kubernetes 分发商将其控制器和 CRD 作为其 Kubernetes 集群管理过程的一部分打包和部署(独立于任何 CSI Driver)。

如果您的集群没有预装正确的组件,您可以执行以下步骤手动安装这些组件。

安装快照 Beta CRD

安装通用快照控制器

安装 CSI Driver

遵循您的 CSI Driver 供应商提供的说明。

如何使用 Kubernetes Volume Snapshots?

假设您的集群已部署并运行所有必需的组件(包括 CSI 驱动程序),您可以使用 VolumeSnapshot API 对象创建卷快照,并通过在 PVC 上指定 VolumeSnapshot 数据源来恢复它们。

使用 Kubernetes 创建新的 Volume Snapshot

您可以通过创建一个指向支持卷快照的 CSI Driver 的 VolumeSnapshotClass API 对象,来启用 Kubernetes 集群中的卷快照创建/删除。

例如,以下 VolumeSnapshotClass 告诉 Kubernetes 集群,CSI 驱动程序 testdriver.csi.k8s.io 可以处理卷快照,并且当创建这些快照时,其删除策略应该是删除。

apiVersion: snapshot.storage.k8s.io/v1beta1
kind: VolumeSnapshotClass
metadata:
  name: test-snapclass
driver: testdriver.csi.k8s.io
deletionPolicy: Delete
parameters:
  csi.storage.k8s.io/snapshotter-secret-name: mysecret
  csi.storage.k8s.io/snapshotter-secret-namespace: mysecretnamespace

通用快照控制器保留参数键 csi.storage.k8s.io/snapshotter-secret-namecsi.storage.k8s.io/snapshotter-secret-namespace。如果指定了这些键,它会获取引用的 Kubernetes Secret,并将其设置为卷快照内容对象上的 Annotation。CSI external-snapshotter 边车从内容 Annotation 中检索它,并在创建快照期间将其传递给 CSI 驱动程序。

卷快照的创建是通过创建 VolumeSnapshot API 对象触发的。

VolumeSnapshot 对象必须指定以下源类型:persistentVolumeClaimName - 要进行快照的 PVC 的名称。请注意,VolumeSnapshot 对象的源 PVC、PV 和 VolumeSnapshotClass 必须指向同一个 CSI 驱动程序。

例如,以下 VolumeSnapshot 会使用上面的 VolumeSnapshotClass 触发名为 test-pvc 的 PVC 的快照创建。

apiVersion: snapshot.storage.k8s.io/v1beta1
kind: VolumeSnapshot
metadata:
  name: test-snapshot
spec:
  volumeSnapshotClassName: test-snapclass
  source:
    persistentVolumeClaimName: test-pvc

调用卷快照创建时,通用快照控制器首先创建一个 VolumeSnapshotContent 对象,其中包含 volumeSnapshotRef、源 volumeHandle、如果指定了则包含 volumeSnapshotClassNamedriverdeletionPolicy

CSI external-snapshotter 边车然后通过 CSI CreateSnapshot 调用将 VolumeSnapshotClass 参数、源卷 ID 以及任何引用的 Secret 传递给 CSI 驱动程序(在本例中为 testdriver.csi.k8s.io)。CSI 驱动程序响应此调用,为指定的卷创建一个新快照,并返回该快照的 ID。然后,CSI external-snapshotter 边车更新表示新快照的 VolumeSnapshotContent 对象的 status 字段中的 snapshotHandlecreationTimerestoreSizereadyToUse。对于需要在快照创建后上传快照的存储系统,CSI external-snapshotter 边车将持续调用 CSI CreateSnapshot 来检查状态,直到上传完成并将 readyToUse 设置为 true。

通用快照控制器将 VolumeSnapshotContent 对象绑定到 VolumeSnapshot(设置 BoundVolumeSnapshotContentName),并根据 VolumeSnapshotContent 对象的 status 字段更新 VolumeSnapshot 对象的 status 字段中的 creationTimerestoreSizereadyToUse

如果未指定 volumeSnapshotClassName,则会自动选择一个,如下所示:

获取源卷的 PVC 或 PV 中的 StorageClass。如果可用,则获取默认 VolumeSnapshotClass。默认 VolumeSnapshotClass 是由管理员创建的带有 snapshot.storage.kubernetes.io/is-default-class annotation 的快照类。如果默认 VolumeSnapshotClass 的 Driver 字段与 StorageClass 中的 Provisioner 字段相同,则使用默认 VolumeSnapshotClass。如果不存在默认 VolumeSnapshotClass 或快照对应多个默认 VolumeSnapshotClass,则会返回错误。

请注意,Kubernetes 快照 API 不提供任何一致性保证。您必须在创建快照之前手动或使用其他更高级别的 API/控制器准备您的应用程序(暂停应用程序、冻结文件系统等),以确保数据一致性。

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

Bound Volume Snapshot Content Name - Status 字段指示卷已绑定到指定的 VolumeSnapshotContent。Ready To Use - Status 字段指示此卷快照已准备好使用。Creation Time - Status 字段指示快照实际创建(生成)的时间。Restore Size - Status 字段指示从此快照恢复卷时所需的最小卷大小。

Name:         test-snapshot
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  snapshot.storage.k8s.io/v1beta1
Kind:         VolumeSnapshot
Metadata:
  Creation Timestamp:  2019-11-16T00:36:04Z
  Finalizers:
    snapshot.storage.kubernetes.io/volumesnapshot-as-source-protection
    snapshot.storage.kubernetes.io/volumesnapshot-bound-protection
  Generation:        1
  Resource Version:  1294
  Self Link:         /apis/snapshot.storage.k8s.io/v1beta1/namespaces/default/volumesnapshots/new-snapshot-demo
  UID:               32ceaa2a-3802-4edd-a808-58c4f1bd7869
Spec:
  Source:
    Persistent Volume Claim Name:  test-pvc
  Volume Snapshot Class Name:      test-snapclass
Status:
  Bound Volume Snapshot Content Name:  snapcontent-32ceaa2a-3802-4edd-a808-58c4f1bd7869
  Creation Time:                       2019-11-16T00:36:04Z
  Ready To Use:                        true
  Restore Size:                        1Gi

提醒任何使用卷快照 API 构建控制器的开发者:在使用 VolumeSnapshot API 对象之前,请验证 VolumeSnapshot 与其绑定的 VolumeSnapshotContent 之间的双向绑定,以确保绑定完整且正确(否则可能导致安全问题)。

kubectl describe volumesnapshotcontent
Name:         snapcontent-32ceaa2a-3802-4edd-a808-58c4f1bd7869
Namespace:
Labels:       <none>
Annotations:  <none>
API Version:  snapshot.storage.k8s.io/v1beta1
Kind:         VolumeSnapshotContent
Metadata:
  Creation Timestamp:  2019-11-16T00:36:04Z
  Finalizers:
    snapshot.storage.kubernetes.io/volumesnapshotcontent-bound-protection
  Generation:        1
  Resource Version:  1292
  Self Link:         /apis/snapshot.storage.k8s.io/v1beta1/volumesnapshotcontents/snapcontent-32ceaa2a-3802-4edd-a808-58c4f1bd7869
  UID:               7dfdf22e-0b0c-4b71-9ddf-2f1612ca2aed
Spec:
  Deletion Policy:  Delete
  Driver:           testdriver.csi.k8s.io
  Source:
    Volume Handle:             d1b34a5f-0808-11ea-808a-0242ac110003
  Volume Snapshot Class Name:  test-snapclass
  Volume Snapshot Ref:
    API Version:       snapshot.storage.k8s.io/v1beta1
    Kind:              VolumeSnapshot
    Name:              test-snapshot
    Namespace:         default
    Resource Version:  1286
    UID:               32ceaa2a-3802-4edd-a808-58c4f1bd7869
Status:
  Creation Time:    1573864564608810101
  Ready To Use:     true
  Restore Size:     1073741824
  Snapshot Handle:  127c5798-0809-11ea-808a-0242ac110003
Events:             <none>

使用 Kubernetes 导入现有卷快照

您始终可以通过手动创建 VolumeSnapshotContent 对象来代表现有卷快照,从而在 Kubernetes 中公开预先存在的卷快照。由于 VolumeSnapshotContent 是非命名空间的 API 对象,只有集群管理员才有权限创建它。通过指定 volumeSnapshotRef,集群管理员可以精确指定哪些用户可以使用该快照。

例如,以下 VolumeSnapshotContent 公开了一个属于名为 testdriver.csi.k8s.io 的 CSI 驱动程序的卷快照,其名称为 7bdd0de3-aaeb-11e8-9aae-0242ac110002

集群管理员应创建包含以下字段的 VolumeSnapshotContent 对象来表示现有快照:

  • driver - 用于处理此卷的 CSI 驱动程序。此字段是必填项。
  • source - 快照识别信息
  • snapshotHandle - 快照的名称/标识符。此字段是必填项。
  • volumeSnapshotRef - 指向此内容应绑定的 VolumeSnapshot 对象的指针。
  • namenamespace - 指定内容绑定的 VolumeSnapshot 对象的名称和命名空间。
  • deletionPolicy - 有效值为 DeleteRetain。如果 deletionPolicyDelete,则底层存储快照将随 VolumeSnapshotContent 对象一起删除。如果 deletionPolicyRetain,则底层快照和 VolumeSnapshotContent 都将保留。
apiVersion: snapshot.storage.k8s.io/v1beta1
kind: VolumeSnapshotContent
metadata:
  name: manually-created-snapshot-content
spec:
  deletionPolicy: Delete
  driver: testdriver.csi.k8s.io
  source:
    snapshotHandle: 7bdd0de3-aaeb-11e8-9aae-0242ac110002
  volumeSnapshotRef:
    name: test-snapshot
    namespace: default

创建 VolumeSnapshotContent 对象后,用户可以创建指向 VolumeSnapshotContent 对象的 VolumeSnapshot 对象。VolumeSnapshot 对象的名称和命名空间必须与 VolumeSnapshotContent 的 volumeSnapshotRef 中指定的名称/命名空间匹配。它指定以下字段:volumeSnapshotContentName - 上述卷快照内容的名称。此字段是必填项。volumeSnapshotClassName - 卷快照类的名称。此字段是可选的。

apiVersion: snapshot.storage.k8s.io/v1beta1
kind: VolumeSnapshot
metadata:
  name: manually-created-snapshot
spec:
  source:
        volumeSnapshotContentName: test-content

创建这两个对象后,通用快照控制器会验证 VolumeSnapshot 和 VolumeSnapshotContent 对象之间的绑定是否正确,并标记 VolumeSnapshot 为就绪状态(如果 CSI 驱动程序支持 ListSnapshots 调用,控制器还会验证引用的快照是否存在)。如果实现了 ListSnapshots CSI 方法,CSI external-snapshotter 边车会检查快照是否存在,否则它会假定快照存在。external-snapshotter 边车会将 VolumeSnapshotContent 的 status 字段中的 readyToUse 设置为 true。通用快照控制器会相应地将快照标记为就绪状态。

从快照创建卷

拥有绑定且就绪的 VolumeSnapshot 对象后,您可以使用该对象 Provision 一个新卷,该卷预先填充了快照中的数据。

要 Provision 一个预先填充了快照数据的新卷,请在 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: testdriver.csi.k8s.io
  dataSource:
    name: manually-created-snapshot
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

创建 PersistentVolumeClaim 对象后,将触发新卷的供应,新卷会预填充指定快照中的数据。作为存储厂商,如何向我的 CSI 驱动程序添加快照支持?为了实现快照功能,CSI 驱动程序必须添加对额外的控制器能力 CREATE_DELETE_SNAPSHOTLIST_SNAPSHOTS 的支持,并实现额外的控制器 RPCs:CreateSnapshotDeleteSnapshotListSnapshots。有关详细信息,请参阅 CSI 规范Kubernetes-CSI 驱动程序开发者指南

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

作为此推荐部署过程的一部分,Kubernetes 团队提供了许多边车(辅助)容器,包括 external-snapshotter 边车容器。

external-snapshotter 监视 Kubernetes API Server 的 VolumeSnapshotContent 对象,并触发针对 CSI endpoint 的 CreateSnapshotDeleteSnapshot 操作。CSI external-provisioner 边车容器也已更新,支持使用 dataSource PVC 字段从快照恢复卷。

为了支持快照功能,建议存储厂商除了 external provisioner 外,还部署 external-snapshotter 边车容器以及他们的 CSI 驱动程序。

Beta 版本的局限性是什么?

Kubernetes 卷快照的 Beta 实现有以下局限性:

  • 不支持将现有卷恢复到由快照表示的较早状态(Beta 版本仅支持从快照供应新卷)。
  • 除了存储系统提供的保证(例如崩溃一致性)之外,没有快照一致性保证。这些是由更高级别的 API/控制器负责的。

下一步是什么?

根据反馈和采用情况,Kubernetes 团队计划在 1.18 或 1.19 版本中将 CSI 快照实现推向 GA(普遍可用)。我们有兴趣支持的一些功能包括一致性组、应用一致性快照、工作负载静默、原地恢复、卷备份等。

如何了解更多信息?

您还可以查看 external-snapshotter 源代码库

在此 此处此处 查看有关快照功能的更多文档。

如何参与?

与所有 Kubernetes 项目一样,本项目也是许多来自不同背景的贡献者共同努力的成果。

我们非常感谢过去几个季度挺身而出,帮助项目达到 Beta 阶段的贡献者们:

  • Xing Yang (xing-yang)
  • Xiangqian Yu (yuxiangqian)
  • Jing Xu (jingxu97)
  • Grant Griffiths (ggriffiths)
  • Can Zhu (zhucan)

特别感谢以下人员,感谢他们富有洞察力的评审和对设计的周全考虑:

  • Michelle Au (msau42)
  • Saad Ali (saadali)
  • Patrick Ohly (pohly)
  • Tim Hockin (thockin)
  • Jordan Liggitt (liggitt)。

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

我们还会定期举行 SIG-Storage 快照工作组会议。欢迎新成员加入讨论设计和开发。