Definir uma lógica personalizada de backup e restauração


Quando você ativa o agente do Backup para GKE no cluster do Google Kubernetes Engine, o Backup para GKE fornece um CustomResourceDefinition que introduz um novo tipo de recurso do Kubernetes: o ProtectedApplication.

A composição de um ProtectedApplication envolve duas atividades:

Os recursos do ProtectedApplication oferecem essas capacidades ao personalizar a lógica de backup e restauração no nível do aplicativo:

  • Operações de backup e restauração mais detalhadas. Sem ProtectedApplications, o escopo dos backups precisa ser definido no nível Namespace (selecionando allNamespaces ou selectedNamespaces). Uma lógica semelhante se aplica à restauração de recursos com namespace. A criação de recursos ProtectedApplication permite que você forneça um nome a um subconjunto dos recursos em um Namespace. Em seguida, é possível fazer backup e restaurar esse subconjunto listando selectedApplications no escopo de backup e de maneira semelhante para restaurar.

  • Orquestrar detalhes do processo de backup ou restauração, como:

    • ignorar volumes selecionados durante o backup;

    • incorporar a topologia do aplicativo no backup e na restauração (por exemplo, fazer backup de apenas uma instância de um banco de dados replicado e usá-la para restaurar várias instâncias).

    • A execução de ganchos definidos pelo usuário antes e depois dos volumes terem snapshots. Eles podem ser usados, por exemplo, para limpar e silenciar uma carga de trabalho antes de criar um snapshot e remover o silenciamento depois.

Crie ProtectedApplication usando kubectl como outros recursos do Kubernetes. Eles são completamente opcionais. Se recursos de ProtectedApplication não estão presentes, o Backup para GKE cria backups de volume para todos os volumes no escopo de um backup e os backups de volume resultantes sãoconsistentes com a falha. Todas as gravações transferidas para o disco em um determinado momento serão capturadas, ou seja, não serão gravadas parcialmente. No entanto, alguns aplicativos podem manter dados na memória que não são transferidos para o disco. Portanto, se um aplicativo pode ou não se recuperar de um backup consistente com falha, depende da lógica do aplicativo.

Como selecionar recursos

O primeiro passo para criar seu recurso ProtectedApplication é identificar os outros recursos no mesmo Namespace que você quer incluir como parte do aplicativo. Este é o conjunto de recursos que será armazenado em backup ou restaurado se você fornecer a opção de escopo selectedApplications na configuração BackupPlan.

Os recursos são identificados por um seletor de rótulo. Isso exige que você rotule todos os recursos (usando o campo metadata.label em cada recurso) com o mesmo rótulo. Observe que isso também se aplica a recursos criados automaticamente por controladores. Esses recursos criados automaticamente são identificados usando o modelo correspondente. É comum reutilizar o mesmo identificador que você já está usando para associar o Pods e o PersistentVolumeClaims gerados ao recurso pai. O exemplo a seguir mostra como aplicar o identificador app: nginx aos outros recursos, além de 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:
      ...

Depois de aplicar o identificador selecionado a todos os recursos de destino e aos modelos dos quais outros recursos são gerados, será possível referenciar esses recursos de um ProtectedApplication. Exemplo:

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

Definir regras de orquestração

Depois de identificar todos os recursos no ProtectedApplication, é possível definir regras de orquestração detalhadas para um subconjunto desses recursos. Essas regras só podem ser aplicadas a dois tipos de recursos: implantações e StatefulSets e são referenciadas na seção components de ProtectedApplication.

Visão geral do componente

A configuração de um componente envolve o seguinte:

  • A seleção de uma estratégia fundamental para o funcionamento do backup e da restauração desse componente. Há três estratégias disponíveis:

    • BackupAllRestoreAll: fazer backup dos volumes associados a todas as instâncias do componente e restaurar todos eles usando os backups;

    • BackupOneRestoreAll: fazer backup dos volumes de apenas uma instância do componente e usar estes backups para restaurar todas as instâncias;

    • DumpAndLoad: exportar dados do aplicativo para um único volume no momento do backup e importar esses dados para o aplicativo no momento da restauração.

  • Definir ganchos de execução a serem executados durante o backup e, possivelmente, restaurar, dependendo da estratégia. Um gancho é um comando executado em contêineres específicos.

  • Como selecionar um subconjunto de volumes para o backup.

Ganchos de execução

Um gancho é um comando do shell que o Backup para GKE executa em um contêiner em uma fase específica do processo de backup ou restauração.

Há quatro tipos diferentes de ganchos:

  • pre hooks: esses comandos são executados logo antes de fazer backup dos volumes e geralmente transferem todos os dados na memória para o disco e desativa o aplicativo para que não ocorram novas gravações de disco. Esses ganchos são usados nas estratégias BackupAllRestoreAll e BackupOneRestoreAll.

  • post hooks: esses comandos são executados durante o processo de backup de volume logo após a etapa SNAPSHOTTING do processo de backup de volume (antes da etapa UPLOADING). Geralmente, a etapa SNAPSHOTTING leva apenas alguns segundos. Geralmente, espera-se que eles removam o silenciamento do aplicativo, o que permite continuar o processamento normal e as gravações de disco. Esses ganchos são usados nas estratégias BackupAllRestoreAll, BackupOneRestoreAll e DumpAndLoad.

  • dump hooks: esses comandos são executados antes de fazer o backup do volume na estratégia DumpAndLoad e geralmente espera-se que exportem os dados do aplicativo para o volume de backup designado.

  • load hooks: esses comandos são executados no momento da restauração depois que o volume de backup é restaurado nos casos de estratégia DumpAndLoad. Geralmente, é esperado que os dados sejam importados do volume de backup para o aplicativo.

É possível fornecer mais de um gancho para cada tipo, e o Backup para GKE os executará na ordem em que você os define.

Você define ganchos como parte da seção de componentes da especificação ProtectedApplication. Todas as definições de ganchos têm os mesmos campos disponíveis:

  • name: um nome que você atribui ao gancho.

  • container: (opcional) nome do contêiner em que o comando será executado. Se você não informar o contêiner, o Backup para GKE executará o hook no primeiro contêiner definido para os Pods de destino.

  • command: é o comando atual enviado para o contêiner, construído como uma matriz de palavras. A primeira palavra na matriz é o caminho para o comando, e as palavras seguintes são os argumentos que vão ser transmitidos para o comando.

  • timeoutSeconds (opcional): tempo antes do cancelamento da execução do gancho. Se você não informar esse valor, o padrão será de 30 segundos.

  • onError: (opcional) comportamento tomado quando o gancho falha. Pode ser definido como Ignore ou Fail (padrão). Se você definir como Fail, quando o gancho falhar, o backup do volume falhará. Se você definir como Ignore, as falhas desse gancho serão ignoradas.

Antes de aplicar os ganchos do ProtectedApplication ao seu aplicativo, teste o comando usando kubectl exec para garantir que os ganchos se comportem conforme o esperado:

kubectl exec POD_NAME -- COMMAND

Substitua:

  • POD_NAME: o nome do pod que contém o recurso ProtectedApplication.
  • COMMAND: a matriz que contém o comando que você quer executar no contêiner, por exemplo, /sbin/fsfreeze, -f, /var/log/nginx.

Como selecionar um subconjunto de volumes para o backup

Às vezes, os aplicativos gravam em volumes que não são interessantes para restaurar (por exemplo, alguns volumes de registro ou de rascunho). É possível suprimir o backup desses volumes usando um seletor de volume.

Para usar esse recurso, primeiro aplique um identificador comum aos volumes que você quer fazer backup e deixe esse identificador desativado para os volume que você não quer fazer backup. Em seguida, inclua uma cláusula volumeSelector na definição do componente da seguinte maneira:

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

Se você fornecer um volumeSelector para um componente, somente os volumes que têm o identificador especificado serão salvos em backup e restaurados. No momento da restauração, qualquer outro volume será provisionado como vazio em vez de restaurado de um backup de volume.

Estratégia: BackupAllRestoreAll

Essa é a estratégia mais simples, faz backup de todos os volumes do componente no momento do backup e restaura todos eles a partir dos backups de volume no momento da restauração. Essa é melhor opção quando o aplicativo não tem replicação entre Pods.

Essa estratégia é compatível com os seguintes parâmetros:

  • backupPreHooks (opcional): uma lista ordenada de ganchos que são executados logo antes do backup dos volumes. Esses comandos são executados em todos os Pods no componente.

  • backupPostHooks (opcional): uma lista ordenada de ganchos que são executadas após os backups de volume alcançarem a fase UPLOADING. Esses comandos são executados em todos os Pods no componente.

  • volumeSelector (opcional): lógica para corresponder um subconjunto de volumes ao backup.

Este exemplo cria um recurso ProtectedApplication que desativa o sistema de arquivos antes de fazer backup do volume de registros e cancela a desativação após o backup:

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 ]

Estratégia: BackupOneAndRestoreAll

Essa estratégia faz backup de uma cópia de um pod selecionado. Essa cópia única é a fonte para restaurar todos os pods durante uma restauração. Esse método ajuda a reduzir o custo de armazenamento e o tempo de backup. Essa estratégia funciona em uma configuração de alta disponibilidade quando um componente é implantado com um PersistentVolumeClaim primário e vários PersistentVolumeClaims secundários.

Essa estratégia é compatível com os seguintes parâmetros:

  • backupTargetName (obrigatório): especifica qual implantação ou StatefulSet você quer usar para fazer backup dos dados. O melhor pod para fazer backup é selecionado automaticamente. Em uma configuração de alta disponibilidade, recomendamos que você a defina como uma das réplicas do seu aplicativo.

  • backupPreHooks: (opcional) uma lista ordenada de ganchos que são executados logo antes do backup dos volumes. Esses comandos são executados apenas no Pod de backup selecionado.

  • backupPostHooks (opcional): uma lista ordenada de ganchos que são executadas após os backups de volume alcançarem a fase UPLOADING. Esses comandos são executados apenas no Pod de backup selecionado.

  • volumeSelector (opcional): lógica para corresponder um subconjunto de volumes ao backup.

Se um componente for configurado com várias implantações ou StatefulSets, todos os recursos precisarão ter a mesma estrutura PersistentVolume, o que significa que eles precisam seguir estas regras:

  • O número de PersistentVolumeClaims usado por todas as implantações ou StatefulSets precisa ser o mesmo.
  • A finalidade de PersistentVolumeClaims no mesmo índice precisa ser a mesma. Para StatefulSets, o índice é definido no volumeClaimTemplate. Para implantações, o índice é definido em Volumes e todos os volumes não permanentes são ignorados.
  • Se o componente do aplicativo consistir em implantações, cada implantação precisará ter exatamente uma réplica.

Considerando essas considerações, vários conjuntos de volumes podem ser selecionados para backup, mas apenas um volume de cada conjunto será selecionado.

Neste exemplo, supondo uma arquitetura de um StatefulSet principal e um StatefulSet secundário, mostramos um backup de volumes de um pod no StatefulSet secundário e uma restauração para todos os outros volumes:

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

Estratégia: DumpAndLoad

Essa estratégia usa um volume dedicado para processos de backup e restauração e requer um PersistentVolumeClaim dedicado anexado a um componente que armazena dados dump.

Essa estratégia é compatível com os seguintes parâmetros:

  • dumpTarget (obrigatório): especifica qual implantação ou StatefulSet você quer usar para fazer backup dos dados. O melhor pod para fazer backup é selecionado automaticamente. Em uma configuração de alta disponibilidade, recomendamos que você a defina como uma das réplicas do seu aplicativo.

  • loadTarget (obrigatório): especifica qual implantação ou StatefulSet será usado para carregar os dados. O melhor pod para fazer backup é selecionado automaticamente. O destino de carregamento não precisa ser o mesmo que o destino de despejo.

  • dumpHooks (obrigatório): uma lista ordenada de ganchos que são executados para preencher o volume de backup dedicado. Esses comandos são executados apenas no Pod de despejo selecionado.

  • backupPostHooks (opcional): uma lista ordenada de ganchos que são executadas após os backups de volume alcançarem a fase UPLOADING. Esses comandos são executados apenas no Pod de despejo selecionado.

  • loadHooks (obrigatório): uma lista ordenada de ganchos que são executados para carregar os dados do volume restaurado após o início do aplicativo. Esses comandos são executados apenas no Pod do carregamento selecionado.

  • volumeSelector (obrigatório): lógica para corresponder um único volume para backup e restauração (o volume "despejo"). Embora ela só precise corresponder a um único volume, você a configura da mesma forma que o subconjunto de volumes para backup usado por outras estratégias.

Se o aplicativo consistir em implantações, cada implantação precisará ter exatamente uma réplica.

Neste exemplo, suponha que uma arquitetura de um StatefulSet principal e um StatefulSet secundário com PersistentVolumeClaims dedicado para StatefulSets principais e secundários mostre uma estratégia 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

Verificar se um ProtectedApplication está pronto para backup

É possível verificar se um ProtectedApplication está pronto para um backup executando o seguinte comando:

kubectl describe protectedapplication APPLICATION_NAME

Substitua APPLICATION_NAME pelo nome do aplicativo.

Se estiver pronto, a descrição do aplicativo mostrará o status Ready to backup como true, como neste exemplo:

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

A seguir