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

Kubernetes 1.17 功能:Kubernetes 卷快照升至 Beta 版

Kubernetes 卷快照功能现已在 Kubernetes v1.17 中进入 Beta 阶段。它在 Kubernetes v1.12 中作为 Alpha 版 引入,并在 Kubernetes v1.13 中发布了包含重大更改的 第二个 Alpha 版。本文总结了 Beta 版中的更改。

什么是卷快照?

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

为什么要将卷快照添加到 Kubernetes?

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

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

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

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

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

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

Beta 版中的新功能是什么?

随着卷快照升级到 Beta 版,该功能现在默认在标准 Kubernetes 部署中启用,而不是选择加入。

Kubernetes 卷快照功能升级到 Beta 版还意味着:

  • 卷快照 API 的改版。
  • CSI external-snapshotter sidecar 被拆分为两个控制器,一个通用快照控制器和一个 CSI external-snapshotter sidecar。
  • 删除 Secret 作为注解添加到卷快照内容中。
  • 一个新终结器被添加到卷快照 API 对象中,以防止它在绑定到卷快照内容 API 对象时被删除。

Kubernetes 卷快照要求

如上所述,随着卷快照升级到 Beta 版,该功能现在默认在标准 Kubernetes 部署中启用,而不是选择加入。

为了使用 Kubernetes 卷快照功能,您必须确保已在 Kubernetes 集群上部署以下组件:

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

哪些驱动程序支持 Kubernetes 卷快照?

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

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

阅读“Kubernetes 的容器存储接口 (CSI) GA”博客文章,了解有关 CSI 以及如何部署 CSI 驱动程序的更多信息。

截至本博客发布时,以下 CSI 驱动程序已更新以支持卷快照 Beta 版:

其他 CSI 驱动程序 的 Beta 级卷快照支持即将推出,应该很快就会可用。

Kubernetes 卷快照 Beta API

在 Kubernetes 卷快照 API 的 Alpha 版到 Beta 版之间进行了多项更改。这些更改不向后兼容。这些更改的目的是使 API 定义更清晰、更易于使用。

进行了以下更改:

  • `DeletionPolicy` 现在是 `VolumeSnapshotClass` 和 `VolumeSnapshotContent` 中的必需字段,而不是可选字段。这样用户必须明确指定它,避免混淆。
  • `VolumeSnapshotSpec` 有一个新的必需 `Source` 字段。`Source` 可以是 `PersistentVolumeClaimName`(如果动态供应快照)或 `VolumeSnapshotContentName`(如果预供应快照)。
  • `VolumeSnapshotContentSpec` 也有一个新的必需 `Source` 字段。此 `Source` 可以是 `VolumeHandle`(如果动态供应快照)或 `SnapshotHandle`(如果预供应卷快照)。
  • `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 集群上部署卷快照支持?

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

因此,强烈建议 Kubernetes 分发商将其 Kubernetes 集群管理过程的一部分(独立于任何 CSI 驱动程序)捆绑和部署控制器和 CRD。

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

安装快照 Beta CRD

安装通用快照控制器

安装 CSI 驱动程序

请遵循 CSI 驱动程序供应商提供的说明。

如何使用 Kubernetes 卷快照?

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

使用 Kubernetes 创建新卷快照

您可以通过创建指向支持卷快照的 CSI 驱动程序的 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-name` 和 `csi.storage.k8s.io/snapshotter-secret-namespace`。如果指定,它将获取引用的 Kubernetes secret 并将其设置为卷快照内容对象上的注解。CSI external-snapshotter sidecar 从内容注解中检索它,并在快照创建期间将其传递给 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`、如果指定了 `volumeSnapshotClassName`、`driver` 和 `deletionPolicy`。

CSI external-snapshotter sidecar 随后通过 CSI `CreateSnapshot` 调用将 VolumeSnapshotClass 参数、源卷 ID 和任何引用的 secret 传递给 CSI 驱动程序(在本例中为 `testdriver.csi.k8s.io`)。作为响应,CSI 驱动程序为指定卷创建一个新快照,并返回该快照的 ID。CSI external-snapshotter sidecar 随后更新代表新快照的 VolumeSnapshotContent 对象的 status 字段中的 `snapshotHandle`、`creationTime`、`restoreSize` 和 `readyToUse`。对于需要上传快照(已剪切)的存储系统,CSI external-snapshotter sidecar 将继续调用 CSI `CreateSnapshot` 以检查状态,直到上传完成并将 `readyToUse` 设置为 true。

通用快照控制器将 VolumeSnapshotContent 对象绑定到 VolumeSnapshot(设置 `BoundVolumeSnapshotContentName`),并根据 VolumeSnapshotContent 对象的 status 字段更新 VolumeSnapshot 对象的 status 字段中的 `creationTime`、`restoreSize` 和 `readyToUse`。

如果未指定 `volumeSnapshotClassName`,则自动选择如下:

从源卷的 PVC 或 PV 中获取 `StorageClass`。如果可用,则获取默认 VolumeSnapshotClass。默认 VolumeSnapshotClass 是管理员使用 `snapshot.storage.kubernetes.io/is-default-class` 注解创建的快照类。如果默认 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 公开了一个名为 7bdd0de3-aaeb-11e8-9aae-0242ac110002 的卷快照,它属于一个名为 testdriver.csi.k8s.io 的 CSI 驱动。

集群管理员应创建具有以下字段的 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 调用,控制器还会验证引用的快照是否存在)。CSI external-snapshotter Sidecar 会检查快照是否存在(如果实现了 ListSnapshots CSI 方法),否则它会假定快照存在。external-snapshotter Sidecar 将 VolumeSnapshotContent 的 status 字段中的 readyToUse 设置为 true。通用快照控制器相应地将快照标记为就绪。

从快照创建卷

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

要预配一个预先填充了来自快照数据的新卷,请使用 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 的支持,并实现附加控制器 RPC:CreateSnapshotDeleteSnapshotListSnapshots。有关详细信息,请参阅 CSI 规范Kubernetes-CSI 驱动程序开发人员指南

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

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

external-snapshotter 监视 Kubernetes API 服务器中的 VolumeSnapshotContent 对象,并针对 CSI 端点触发 CreateSnapshotDeleteSnapshot 操作。CSI external-provisioner Sidecar 容器也已更新,以支持使用 dataSource PVC 字段从快照恢复卷。

为了支持快照功能,建议存储供应商除了 external provisioner 之外,还部署 external-snapshotter Sidecar 容器以及他们的 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 快照工作组会议。欢迎新成员加入设计和开发讨论。