定义自定义备份和恢复逻辑


当您在 Google Kubernetes Engine 集群中启用 Backup for GKE 代理时,Backup for GKE 会提供引入一种新的 Kubernetes 资源 ProtectedApplicationCustomResourceDefinition

编写 ProtectedApplication 涉及两个活动:

在应用级层自定义备份和恢复逻辑时,ProtectedApplication 资源为您提供以下功能:

  • 更精细的备份和恢复操作。如果没有 ProtectedApplications,您必须在 Namespace 级层定义备份范围(通过选择 allNamespaceselectNamespace)。类似的逻辑适用于命名空间型资源恢复。通过创建 ProtectedApplication 资源,您可以为 Namespace 中的部分资源提供名称。然后,您可以在备份范围内列出 SelectedApplications,以备份和恢复该子集(对于恢复也是如此)。

  • 编排备份或恢复过程的精细详细信息,包括:

    • 在备份期间跳过选定的卷。

    • 将应用拓扑整合到备份和恢复中(例如,仅备份复制数据库的一个实例并使用它来恢复多个实例)。

    • 在截取卷快照之前和之后,执行用户定义的钩子。例如,这些钩子可用于在截取快照前刷入工作负载并使其静默,并在之后取消静默。

与其他 Kubernetes 资源一样,您可以通过 kubectl 创建 ProtectedApplication。它们是完全可选的。如果 ProtectedApplication 资源不存在,Backup for GKE 会为备份范围内的所有卷创建卷备份,生成的卷备份将具有崩溃一致性,即特定时间点刷入磁盘的所有写入都将被捕获(即没有部分写入)。但是,某些应用可能会将数据保留在未刷入磁盘的内存中,因此应用是否可以从崩溃一致的备份成功恢复取决于应用逻辑。

选择资源

构建 ProtectedApplication 资源的第一步是确定同一 Namespace 中要包含在应用中的其他资源。如果您在 BackupPlan 配置中提供了 selectedApplications 范围选项,那么这是将会备份或恢复的一组资源。

你可以使用标签选择器来识别资源。这要求您使用相同标签为所有资源加标签(使用每个资源中的 metadata.label 字段)。请注意,这也适用于控制器自动创建的资源。这些自动创建的资源通过其对应的模板来加标签。请注意,常见做法是重复使用已用于将生成的 PodsPersistentVolumeClaims 与其父资源关联的同一标签。以下示例展示了如何将 app: nginx 标签应用于除 Deployment 之外的其他资源。

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-vars
  namespace: webserver
  labels:
    app: nginx
  data:
    ...
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-logs
  namespace: webserver
  labels:
    app: nginx
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 50Mi
  storageClassName: standard-rwo
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: webserver
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      volumes:
        - name: nginx-logs
          persistentVolumeClaim:
           claimName: nginx-logs
      containers:
      ...

将所选标签应用于所有目标资源(以及生成其他资源的模板)后,您就可以从 ProtectedApplication 引用这些资源。例如:

kind: ProtectedApplication
apiVersion: gkebackup.gke.io/v1alpha2
metadata:
  name: nginx
  namespace: webserver
spec:
  resourceSelection:
    type: Selector
    selector:
      matchLabels:
        app: nginx
  ...

定义编排规则

确定 ProtectedApplication 中的所有资源后,您可以选择为这一资源子集定义详细的编排规则。这些规则仅适用于这两种资源:DeploymentStatefulSet,并在 components部分 ProtectedApplication 中引用。

组件概览

配置组件涉及以下任务:

  • 选择此组件的备份和恢复的基本策略。有三种可用的策略:

    • BackupAllRestoreAll - 备份与组件的所有实例关联的卷,并从备份恢复所有卷

    • BackupOneRestoreAll - 仅从组件的一个实例备份卷,并使用这些备份恢复所有实例

    • DumpAndLoad - 备份时将数据从应用导出到单个卷,并在恢复时将这些数据导入应用

  • 定义在备份期间运行的执行钩子(也可能在恢复期间运行,具体取决于策略)。钩子是在特定容器中执行的命令。

  • 选择要备份的卷子集

执行钩子

钩子是 Backup for GKE 在备份或恢复过程的特定阶段在容器中执行的 shell 命令。

钩子有四种不同的类型:

  • pre hooks - 这些命令在备份卷之前执行,通常用于将内存中的所有数据刷入磁盘,然后让应用处于静默状态,以避免发生新的磁盘写入。这些钩子在 BackupAllRestoreAllBackupOneRestoreAll 策略中使用。

  • post hooks - 这些命令在卷备份过程中的截取快照步骤之后以及上传步骤之前执行。通常,截取快照步骤只需几秒钟时间。这些钩子通常用于取消应用静默(即允许继续执行正常处理和磁盘写入)。这些钩子在 BackupAllRestoreAllBackupOneRestoreAllDumpAndLoad 策略中使用。

  • dump hooks - 这些命令在 DumpAndLoad 策略中的备份卷步骤之前执行,通常用于将数据从应用导入指定的备份卷。

  • load hooks - 采用 DumpAndLoad 策略时,这些命令在恢复备份卷后执行。它们通常用于将备份卷中的数据导入应用。

您可以为每个类型提供多个钩子,Backup for GKE 将按照您定义的顺序执行这些钩子。

您可以在 ProtectedApplication 规范的组件部分中定义钩子。所有钩子定义都具有相同的可用字段:

  • name - 分配给钩子的名称。

  • container-(可选)要在其中运行命令的容器的名称。如果您未提供容器,Backup for GKE 会在为目标 Pod 定义的第一个容器中运行钩子。

  • command - 这是发送到容器的实际命令,以字词数组的形式构建。数组中的第一个字词是该命令的路径,后续字词是要传递给该命令的参数。

  • timeoutSeconds-(可选)取消钩子执行之前的时间。如果未提供值,则默认为 30 秒。

  • onError-(可选)钩子失败时采取的行为。可以设置为 IgnoreFail(默认)。如果将此字段设置为 Fail,则当钩子失败时,卷备份将失败。如果将此字段设置为 Ignore,则此钩子的失败将被忽略。

ProtectedApplication 钩子应用于您的应用之前,您应使用 kubectl exec 测试该命令,以确保钩子的行为符合预期:

kubectl exec POD_NAME -- COMMAND

请替换以下内容:

  • POD_NAME:包含 ProtectedApplication 资源的 Pod 的名称。
  • COMMAND:包含要在容器中运行的命令的数组,例如 /sbin/fsfreeze, -f, /var/log/nginx

选择要备份的卷子集

有时,应用会写入不需要恢复的卷(例如,某些日志或暂存卷)。您可以使用卷选择器阻止备份这些卷。

要使用此功能,您必须先将一个常用标签应用于要备份的卷,然后对于想备份的卷则不应用该标签。然后,您可以在组件定义中添加 volumeSelector 子句,如下所示:

spec:
  ...
  components:
  ...
    strategy:
      ...
      volumeSelector:
        matchLabels:
          label_name: label_value

如果您为组件提供 volumeSelector,则只会备份和恢复具有给定标签的卷。恢复时,任何其他卷将预配为空,而不是从卷备份中恢复。

策略:BackupAllRestoreAll

这是最简单的策略,它会在备份时备份组件的所有卷,并在恢复时从其卷备份中恢复所有卷。如果您的应用在 Pods 之间没有复制,那么这是最佳选择。

此策略支持以下参数:

  • backupPreHooks:(可选)在备份卷之前执行的钩子的有序列表。这些命令在组件中的所有 Pods 上执行。

  • backupPostHooks -(可选)在卷备份到达上传阶段后执行的钩子的有序列表。这些命令在组件中的所有 Pods 上执行。

  • volumeSelector -(可选)用于匹配要备份的卷子集的逻辑。

此示例会创建一项 ProtectedApplication 资源,以在备份日志卷之前将文件系统设为静默状态,并在备份后取消静默状态:

kind: ProtectedApplication
apiVersion: gkebackup.gke.io/v1alpha2
metadata:
  name: nginx
  namespace: sales
spec:
  resourceSelection:
    type: Selector
    selector:
      matchLabels:
        app: nginx
  components:
  - name: nginx-app
    resourceKind: Deployment
    resourceNames: ["nginx"]
    strategy:
      type: BackupAllRestoreAll
      backupAllRestoreAll:
        backupPreHooks:
        - name: fsfreeze
          container: nginx
          command: [ /sbin/fsfreeze, -f, /var/log/nginx ]
        backupPostHooks:
        - name: fsunfreeze
          container: nginx
          command: [ /sbin/fsfreeze, -u, /var/log/nginx ]

策略:BackupOneAndRestoreAll

此策略会备份所选 Pod 的一个副本。该单个副本是恢复期间用于恢复所有 Pod 的来源。这种方法可以帮助降低存储费用和缩短备份时间。此策略适合高可用性配置,此时使用一个主要 PersistentVolumeClaim 和多个辅助 PersistentVolumeClaims 部署组件。

此策略支持以下参数:

  • backupTargetName:(必需)指定要用于备份数据的 Deployment 或 StatefulSet。系统会自动选择最适合用于备份的 Pod。在高可用性配置中,我们建议您将其设置为一个应用副本。

  • backupPreHooks:(可选)在备份卷之前执行的钩子的有序列表。这些命令仅在选定的备份 Pod 上执行。

  • backupPostHooks -(可选)在卷备份到达上传阶段后执行的钩子的有序列表。这些命令仅在选定的备份 Pod 上执行。

  • volumeSelector -(可选)用于匹配要备份的卷子集的逻辑。

如果某个组件配置了多个 Deployment 或 StatefulSet,则所有资源都必须具有相同的 PersistentVolume 结构,这意味着它们必须遵循以下规则:

  • 所有 Deployment 或 StatefulSet 使用的 PersistentVolumeClaims 数量必须相同。
  • 同一索引中 PersistentVolumeClaims 的用途必须相同。对于 StatefulSet,索引在 volumeClaimTemplate 中定义。对于 Deployment,索引在 Volumes 中定义,且所有非永久性卷都会被跳过。
  • 如果应用组件由 Deployment 组成,则每个 Deployment 必须只有一个副本。

鉴于这些注意事项,您可以选择多个卷集进行备份,但只会从每个卷集中选择一个卷。

以下示例假设存在一个架构,它包含一个主要 StatefulSet 和一个辅助 StatefulSet,其中显示了对辅助 StatefulSet 中的一个 Pod 的卷进行备份,然后对所有其他卷进行恢复:

kind: ProtectedApplication
apiVersion: gkebackup.gke.io/v1alpha2
metadata:
  name: mariadb
  namespace: mariadb
spec:
  resourceSelection:
    type: Selector
    selector:
      matchLabels:
        app: mariadb
  components:
  - name: mariadb
    resourceKind: StatefulSet
    resourceNames: ["mariadb-primary", "mariadb-secondary"]
    strategy:
      type: BackupOneRestoreAll
      backupOneRestoreAll:
        backupTargetName: mariadb-secondary
        backupPreHooks:
        - name: quiesce
          container: mariadb
          command: [...]
        backupPostHooks:
        - name: unquiesce
          container: mariadb
          command: [...]

策略:DumpAndLoad

此策略使用专用卷进行备份和恢复过程,并且需要将专用的 PersistentVolumeClaim 挂接到存储转储数据的组件。

此策略支持以下参数:

  • dumpTarget:(必需)指定要用于备份数据的 Deployment 或 StatefulSet。系统会自动选择最适合用于备份的 Pod。在高可用性配置中,我们建议您将其设置为一个应用副本。

  • loadTarget:(必需)指定应使用哪个 Deployment 或 StatefulSet 来加载数据。系统会自动选择最适合用于备份的 Pod。加载目标不必与转储目标相同。

  • dumpHooks:(必需)为填充专用备份卷而执行的钩子的有序列表。这些命令仅在选定的转储 Pod 上执行。

  • backupPostHooks -(可选)在卷备份到达上传阶段后执行的钩子的有序列表。这些命令仅在选定的转储 Pod 上执行。

  • loadHooks:(必需)为了在应用启动后从恢复的卷加载数据而执行的钩子的有序列表。这些命令仅在选定的加载 Pod 上执行。

  • volumeSelector:(必需)用于将单个卷与备份和恢复(“转储”卷)匹配的逻辑。虽然它必需只匹配单个卷,但您可以采用与其他策略使用的要备份的卷子集相同的方式配置此参数。

如果应用由 Deployment 组成,则每个 Deployment 必须只有一个副本。

以下示例假设了这样一个架构,它包含一个主要 StatefulSet 和一个辅助 StatefulSet,且具有同时用于主要和辅助 StatefulSet 的专用 PersistentVolumeClaims。该示例显示了 DumpAndLoad 策略:

kind: ProtectedApplication
apiVersion: gkebackup.gke.io/v1alpha2
metadata:
  name: mariadb
  namespace: mariadb
spec:
  resourceSelection:
    type: Selector
    selector:
      matchLabels:
        app: mariadb
  components:
  - name: mariadb-dump
    resourceKind: StatefulSet
    resourceNames: ["mariadb-primary", "mariadb-secondary"]
    strategy:
      type: DumpAndLoad
      dumpAndLoad:
        loadTarget: mariadb-primary
        dumpTarget: mariadb-secondary
        dumpHooks:
        - name: db_dump
          container: mariadb
          command:
          - bash
          - "-c"
          - |
            mysqldump -u root --all-databases > /backup/mysql_backup.dump
        loadHooks:
        - name: db_load
          container: mariadb
          command:
          - bash
          - "-c"
          - |
            mysql -u root < /backup/mysql_backup.sql
        volumeSelector:
          matchLabels:
            gkebackup.gke.io/backup: dedicated-volume

检查 ProtectedApplication 是否已准备好进行备份

您可运行以下命令来检查 ProtectedApplication 是否已准备好进行备份:

kubectl describe protectedapplication APPLICATION_NAME

APPLICATION_NAME 替换为应用的名称。

准备就绪后,应用说明会将 Ready to backup 状态显示为 true,如以下示例所示:

% kubectl describe protectedapplication nginx
Name:         nginx
Namespace:    default
API Version:  gkebackup.gke.io/v1alpha2
Kind:         ProtectedApplication
Metadata:
  UID:               90c04a86-9dcd-48f2-abbf-5d84f979b2c2
Spec:
  Components:
    Name:           nginx
    Resource Kind:  Deployment
    Resource Names:
      nginx
    Strategy:
      Backup All Restore All:
        Backup Pre Hooks:
          Command:
             /sbin/fsfreeze
             -f
             /var/log/nginx
          Container:         nginx
          Name:              freeze
        Backup Post Hooks:
          Command:
             /sbin/fsfreeze
             -u
             /var/log/nginx
          Container:         nginx
          Name:              unfreeze
      Type:                  BackupAllRestoreAll
  Resource Selection:
    Selector:
      Match Labels:
        app:        nginx
    Type:           Selector
 Status:
  Ready To Backup:  true 
Events:             <none>

后续步骤