Benutzerdefinierte Sicherungs- und Wiederherstellungslogik definieren


Wenn Sie den Backup for GKE-Agent in Ihrem Google Kubernetes Engine-Cluster aktivieren, stellt Backup for GKE ein CustomResourceDefinition bereit, das eine neue Art Kubernetes-Ressource einführt: ProtectedApplication.

Das Erstellen einer ProtectedApplication umfasst zwei Aktivitäten:

ProtectedApplication-Ressourcen bieten Ihnen folgende Funktionen, wenn Sie die Sicherungs- und Wiederherstellungslogik auf Anwendungsebene anpassen:

  • Detailliertere Sicherungs- und Wiederherstellungsvorgänge. Ohne ProtectedApplications muss der Bereich Ihrer Sicherungen auf der Namespace-Ebene definiert werden (durch Auswahl von allNamespaces oder selectedNamespaces). Eine ähnliche Logik gilt für die Wiederherstellung von Ressourcen mit Namespace. Durch das Erstellen von ProtectedApplication-Ressourcen können Sie einer Teilmenge der Ressourcen in einem Namespace einen Namen bereitstellen. Um diese Teilmenge dann zu sichern und wiederherzustellen können Sie selectedApplications in Ihrem Sicherungsbereich auflisten (oder entsprechend für die Wiederherstellung vorgehen).

  • Genaue Details des Sicherungs- oder Wiederherstellungsprozesses orchestrieren, einschließlich:

    • Ausgewählte Volumes während der Sicherung überspringen.

    • Anwendungstopologie in die Sicherung und Wiederherstellung einbinden (z. B. nur eine Instanz einer replizierten Datenbank sichern und diese zur Wiederherstellung mehrerer Instanzen verwenden)

    • Ausführen benutzerdefinierter Hooks vor und nach dem Erstellen von Volumen-Snapshots. Diese können beispielsweise verwendet werden, um eine Arbeitslast zu leeren und stillzulegen, bevor sie erstellt und wieder aktiviert wird.

Sie erstellen ProtectedApplication über kubectl, so wie andere Kubernetes-Ressourcen. Ihre Verwendung ist völlig optional. Sind keine ProtectedApplication-Ressourcen vorhanden erstellt Backup for GKE Volume-Sicherungen für alle Volumes im Sicherungsbereich. Die resultierenden Volume-Sicherungen sind Absturz konsistent – alle Schreibvorgänge, die zu einer bestimmten Zeit auf das Laufwerk geleert werden, werden erfasst (d. h. keine Teilschreibvorgänge). Einige Anwendungen speichern jedoch Daten im Arbeitsspeicher, die nicht auf das Laufwerk geleert werden. Ob eine Anwendung nach einer Absturzsicherung gesichert werden kann, hängt also von der Anwendungslogik ab.

Ressourcen wählen

Der erste Schritt beim Erstellen Ihrer ProtectedApplication-Ressource besteht darin, die anderen Ressourcen in der Namespace zu identifizieren, die Sie als Teil der Anwendung hinzufügen möchten. Dies ist die Gruppe an Ressourcen, die gesichert oder wiederhergestellt werden sollen, wenn Sie in der BackupPlan-Konfiguration die Bereichsoption selectedApplications angeben.

Ressourcen werden mithilfe eines Labelselektors identifiziert. Dazu müssen Sie alle Ihre Ressourcen (mit dem Feld "metadata.label" in jeder Ressource) mit demselben Label versehen. Dies gilt auch für Ressourcen, die automatisch von Controllern erstellt werden. Diese automatisch erstellten Ressourcen werden mit der entsprechenden Vorlage gekennzeichnet. Beachten Sie, dass es üblich ist, bereits verwendete Label wiederzuverwenden, um generierte Pods und PersistentVolumeClaims mit der jeweils übergeordneten Ressource zu verknüpfen. Im folgenden Beispiel wird gezeigt, wie Sie das app: nginx-Label zusätzlich zu Deployment auf die anderen Ressourcen anwenden können.

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:
      ...

Nachdem das ausgewählte Label auf alle Zielressourcen (und die Vorlagen, aus denen zusätzliche Ressourcen generiert werden) angewendet wurde, können Sie auf diese Ressourcen aus einem ProtectedApplication heraus verweisen. Beispiele:

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

Orchestrierungsregeln definieren

Sobald Sie alle Ressourcen in Ihrer ProtectedApplication identifiziert haben, können Sie detaillierte Orchestrierungsregeln für eine Teilmenge dieser Ressourcen definieren. Diese Regeln gelten nur für zwei Arten von Ressourcen: Deployments und StatefulSets. Sie werden im components-Abschnitt der ProtectedApplication referenziert.

Komponentenübersicht

Die Konfiguration einer Komponente umfasst Folgendes:

  • Wählen Sie eine grundlegende Strategie für die Funktionsweise von Sicherung und Wiederherstellung für die Komponente aus. Es stehen drei Strategien zur Verfügung:

    • BackupAllRestoreAll – Die mit allen Instanzen der Komponente verknüpften Volumes werden gesichert und aus Sicherungen wiederhergestellt

    • BackupOneRestoreAll – Die Volumes von nur einer Instanz der Komponente werden gesichert; diese Sicherungen werden dazu verwendet, alle Instanzen wiederherzustellen

    • DumpAndLoad – Daten werden zur Zeit der Sicherung aus der Anwendung in ein einzelnes Volume exportieren; diese Daten werden bei der Wiederherstellung in die Anwendung importieren

  • Definieren Sie Ausführungs-Hooks, die während der Sicherung ausgeführt werden (und je nach Strategie auch bei der Wiederherstellung). Ein Hook ist ein Befehl, der in bestimmten Containern ausgeführt wird.

  • Teilmenge der zu sichernden Volumes wählen

Ausführungs-Hooks

Ein Hook ist ein Shell-Befehl, den Backup for GKE in einem Container in einer bestimmten Phase des Sicherungs- oder Wiederherstellungsprozesses ausführt.

Es gibt vier verschiedene Arten von Hooks:

  • pre hooks – Diese Befehle werden direkt vor dem Sichern von Volumes ausgeführt. Sie sollten generell alle Daten im Arbeitsspeicher auf das Laufwerk leeren und dann die Anwendung stilllegen, damit keine weiteren Schreibvorgänge auf dem Laufwerk stattfinden. Diese Hooks werden in den Strategien BackupAllRestoreAll und BackupOneRestoreAll verwendet.

  • post hooks – Diese Befehle werden während des Volume-Sicherungsvorgangs direkt nach dem SNAPSHOTTING-Schritt des Volume-Sicherungsprozesses ausgeführt (vor dem UPLOADING-Schritt). Im Allgemeinen dauert der SNAPSHOTTING-Schritt nur wenige Sekunden. Es wird generell erwartet, dass die Anwendung dabei stillgelegt wird. Das bedeutet, dass die normale Verarbeitung und die Schreibvorgänge auf dem Laufwerk fortgesetzt werden können. Diese Hooks werden in den Strategien BackupAllRestoreAll, BackupOneRestoreAll und DumpAndLoad verwendet.

  • dump hooks – Diese Befehle werden ausgeführt, bevor das Volume in der Strategie DumpAndLoad gesichert wurde. Es wird erwartet, dass Daten aus der Anwendung in das festgelegte Sicherungs-Volume exportiert werden.

  • load hooks: Diese Befehle werden zur Zeit der Wiederherstellung ausgeführt, nachdem das Sicherungs-Volume in DumpAndLoad-Strategiefällen wiederhergestellt wurde. Es wird generell erwartet, dass sie die Daten aus dem Sicherungs-Volume in die Anwendung importieren.

Sie können für jeden Typ mehr als einen Hook angeben. Backup for GKE führt diese dann in der von Ihnen definierten Reihenfolge aus.

Sie definieren Hooks als Teil des Komponentenabschnitts der Spezifikation ProtectedApplication. Alle Hook-Definitionen haben die gleichen verfügbaren Felder:

  • name – der Name, den Sie dem Hook zuweisen.

  • container – (optional) der Name des Containers, in dem der Befehl ausgeführt werden soll. Wenn Sie den Container nicht bereitstellen, führt Backup for GKE den Hook im ersten Container aus, der für die Ziel-Pod(s) definiert ist.

  • command – der eigentliche Befehl, der an den Container gesendet wird; wird als Wörter-Array erstellt. Das erste Wort im Array ist der Pfad zum Befehl und die folgenden Wörter sind die Argumente, die an den Befehl übergeben werden sollen.

  • timeoutSeconds – (optional) Zeit, bevor die Hook-Ausführung abgebrochen wird. Wenn Sie diese Einstellung nicht angeben, wird der Standardwert von 30 Sekunden verwendet.

  • onError: (optional) Verhalten, das verwendet wird, wenn der Hook fehlschlägt. Kann auf Ignore oder Fail (Standardeinstellung) festgelegt werden. Wenn Sie Fail festlegen und ein Hook fehlschlägt, schlägt die Volume-Sicherung fehl. Wenn Sie Ignore festlegen, werden Fehler dieses Hooks ignoriert.

Bevor Sie ProtectedApplication-Hooks auf Ihre Anwendung anwenden, können Sie den Befehl mit kubectl exec testen, um zu prüfen, ob sich die Hooks wie erwartet verhalten:

kubectl exec POD_NAME -- COMMAND

Dabei gilt:

  • POD_NAME: der Name des Pods, der die Ressource ProtectedApplication enthält.
  • COMMAND: das Array mit dem Befehl, den Sie im Container ausführen möchten, z. B. /sbin/fsfreeze, -f, /var/log/nginx.

Teilmenge der zu sichernden Volumes wählen

Manchmal schreiben Anwendungen in Volumes, die nicht wiederhergestellt werden sollen (z. B. bestimmte Log- oder Scratch-Volumes). Sie können die Sicherung dieser Volumes mithilfe eines Volume-Selektors unterdrücken.

Um dieses Feature zu nutzen, müssen Sie zuerst ein gemeinsames Label auf die Volumes anwenden, die Sie sichern möchten, und dieses Label dann für die Volumes, die Sie nicht sichern wollen, deaktivieren. Anschließend fügen Sie eine volumeSelector-Klausel in Ihre Komponentendefinition ein:

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

Wenn Sie ein volumeSelector für eine Komponente angeben, werden nur die Volumes mit dem angegebenen Label gesichert und wiederhergestellt. Zur Zeit der Wiederherstellung werden alle anderen Volumes leer bereitgestellt und nicht aus einer Volume-Sicherung wiederhergestellt.

Strategie: BackupAllRestoreAll

Dies ist die einfachste Strategie. Es sichert alle Volumes der Komponente und stellt alle Volumes aus deren Sicherungen wieder her. Dies ist die beste Wahl, wenn Ihre Anwendung keine Replikation zwischen Pods hat.

Diese Strategie unterstützt die folgenden Parameter:

  • backupPreHooks: (optional) eine geordnete Liste von Hooks, die direkt vor der Sicherung von Volumes ausgeführt werden. Diese Befehle werden für alle Pods in der Komponente ausgeführt.

  • backupPostHooks: (optional) eine geordnete Liste von Hooks, die ausgeführt werden, nachdem Volume-Sicherungen die UPLOADING-Phase erreicht haben. Diese Befehle werden für alle Pods in der Komponente ausgeführt.

  • volumeSelector: (optional) Logik für den Abgleich einer Teilmenge der Volumes zur Sicherung.

In diesem Beispiel wird eine ProtectedApplication-Ressource erstellt, die das Dateisystem stilllegt, bevor das Logvolume gesichert wurde, und die Stilllegung nach der Sicherung wieder aufhebt:

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 ]

Strategie: BackupOneAndRestoreAll

Mit dieser Strategie wird eine Kopie eines ausgewählten Pods gesichert. Diese eine Kopie ist die Quelle für die Wiederherstellung aller Pods während einer Wiederherstellung. Mit dieser Methode können Sie die Speicherkosten und die Sicherungszeit reduzieren. Diese Strategie funktioniert in einer Hochverfügbarkeitskonfiguration, wenn eine Komponente mit einem primären PersistentVolumeClaim und mehreren sekundären PersistentVolumeClaims bereitgestellt wird.

Diese Strategie unterstützt die folgenden Parameter:

  • backupTargetName – (erforderlich) gibt an, welches Deployment oder StatefulSet Sie zum Sichern der Daten verwenden möchten. Der beste zu sichernde Pod wird automatisch ausgewählt. In Konfigurationen für hohe Verfügbarkeit empfehlen wir, dies auf eines Ihrer Anwendungsreplikate festzulegen.

  • backupPreHooks: (optional) eine geordnete Liste von Hooks, die direkt vor der Sicherung von Volumes ausgeführt werden. Diese Befehle werden nur für den ausgewählten Sicherungs-Pod ausgeführt.

  • backupPostHooks: (optional) eine geordnete Liste von Hooks, die ausgeführt werden, nachdem Volume-Sicherungen die UPLOADING-Phase erreicht haben. Diese Befehle werden nur für den ausgewählten Sicherungs-Pod ausgeführt.

  • volumeSelector: (optional) Logik für den Abgleich einer Teilmenge der Volumes zur Sicherung.

Wenn eine Komponente mit mehreren Deployments oder StatefulSets konfiguriert ist, müssen alle Ressourcen dieselbe PersistentVolume-Struktur haben. Dies bedeutet, dass sie die folgenden Regeln einhalten müssen:

  • Die Anzahl der PersistentVolumeClaims, die von allen Deployments oder StatefulSets verwendet werden, muss identisch sein.
  • Der Zweck von PersistentVolumeClaims im selben Index muss identisch sein. Bei StatefulSets wird der Index in volumeClaimTemplate definiert. Bei Deployments ist der Index in Volumes definiert und alle nicht nichtflüchtigen Volumes werden übersprungen.
  • Wenn die Anwendungskomponente aus Deployments besteht, muss jedes Deployment genau ein Replikat haben.

Angesichts dieser Überlegungen können mehrere Volume-Sätze für die Sicherung ausgewählt werden, aber nur ein Volume aus jedem Volume-Set wird ausgewählt.

In diesem Beispiel wird davon ausgegangen, dass die Architektur eines primären StatefulSets und eines sekundären StatefulSets eine Sicherung der Volumes eines Pods im sekundären StatefulSet und dann eine Wiederherstellung in allen anderen Volumes zeigt:

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: [...]

Strategie: DumpAndLoad

Diese Strategie verwendet ein dediziertes Volume für Sicherungs- und Wiederherstellungsprozesse und benötigt eine dedizierte PersistentVolumeClaim, die an eine Komponente angehängt ist, die Dumpdaten speichert.

Diese Strategie unterstützt die folgenden Parameter:

  • dumpTarget – (erforderlich) gibt an, welches Deployment oder StatefulSet Sie zum Sichern der Daten verwenden möchten. Der beste zu sichernde Pod wird automatisch ausgewählt. In Konfigurationen für hohe Verfügbarkeit empfehlen wir, dies auf eines Ihrer Anwendungsreplikate festzulegen.

  • loadTarget – (erforderlich) gibt an, welches Deployment oder StatefulSet zum Laden der Daten verwendet werden soll. Der beste zu sichernde Pod wird automatisch ausgewählt. Das Ladeziel muss nicht mit dem Dumpziel übereinstimmen.

  • dumpHooks – (erforderlich) eine geordnete Liste von Hooks, die ausgeführt werden, um das dedizierte Sicherungs-Volume zu füllen. Diese Befehle werden nur für den ausgewählten Dump-Pod ausgeführt.

  • backupPostHooks: (optional) eine geordnete Liste von Hooks, die ausgeführt werden, nachdem Volume-Sicherungen die UPLOADING-Phase erreicht haben. Diese Befehle werden nur für den ausgewählten Dump-Pod ausgeführt.

  • loadHooks – (erforderlich) eine geordnete Liste von Hooks, die ausgeführt werden, um die Daten nach dem Start der Anwendung aus dem wiederhergestellten Volume zu laden. Diese Befehle werden nur für den ausgewählten Load-Pod ausgeführt.

  • volumeSelector – (erforderlich) Logik zum Abgleichen eines einzelnen Volumes an Sicherung und Wiederherstellung (das "Dump"-Volume). Obwohl hier nur die Übereinstimmung mit einem einzelnen Volume erforderlich ist, konfigurieren Sie dies genauso wie Teilmengen der Volumes, die gesichert werden sollen, die von anderen Strategien verwendet werden.

Wenn die Anwendung aus Deployments besteht, muss jedes Deployment genau ein Replikat haben.

In diesem Beispiel wird davon ausgegangen, dass die Architektur eines primären StatefulSets und eines sekundären StatefulSets mit dediziertem PersistentVolumeClaims für primäre und sekundäre StatefulSets eine DumpAndLoad-Strategie nutzt:

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

Prüfen, ob ein ProtectedApplication zur Sicherung bereit ist

Mit dem folgenden Befehl können Sie prüfen, ob ein ProtectedApplication zur Sicherung bereit ist:

kubectl describe protectedapplication APPLICATION_NAME

Ersetzen Sie APPLICATION_NAME durch den Namen der Anwendung.

Wenn die Anwendung bereit ist, wird in der Anwendungsbeschreibung der Status Ready to backup als true angezeigt, wie in diesem Beispiel:

% 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>

Nächste Schritte