Defina uma lógica de cópia de segurança e restauro personalizada


Quando ativa o agente da Cópia de segurança do GKE no seu cluster do Google Kubernetes Engine, a Cópia de segurança do GKE fornece um CustomResourceDefinition que introduz um novo tipo de recurso do Kubernetes: o ProtectedApplication.

A composição de um ProtectedApplication envolve três atividades:

Os recursos ProtectedApplication oferecem-lhe estas capacidades quando personaliza a lógica de cópia de segurança e restauro ao nível da aplicação:

  • Operações de cópia de segurança e restauro mais detalhadas. Sem ProtectedApplications, o âmbito das suas cópias de segurança tem de ser definido ao nível de Namespace (selecionando allNamespaces ou selectedNamespaces). Aplica-se uma lógica semelhante à restauração de recursos com espaço de nomes. A criação de recursos ProtectedApplication permite-lhe fornecer um nome a um subconjunto dos recursos numa Namespace. Em seguida, pode fazer uma cópia de segurança e restaurar esse subconjunto listando selectedApplications no âmbito da cópia de segurança (e, da mesma forma, para restore).

  • Orquestrar detalhes detalhados do processo de cópia de segurança ou restauro, incluindo:

    • Ignorar volumes selecionados durante a cópia de segurança.

    • Incorporar a topologia da aplicação na cópia de segurança e no restauro (por exemplo, fazer uma cópia de segurança apenas de uma instância de uma base de dados replicada e usá-la para restaurar várias instâncias).

    • Executar hooks definidos pelo utilizador antes e depois de serem tiradas capturas de ecrã dos volumes. Podem ser usados, por exemplo, para limpar e silenciar uma carga de trabalho antes de criar uma captura de ecrã e, em seguida, reativá-la.

Crie ProtectedApplication usando kubectl como outros recursos do Kubernetes. São completamente opcionais. Se os recursos ProtectedApplication não estiverem presentes, o Backup for GKE cria cópias de segurança de volumes para todos os volumes no âmbito de uma cópia de segurança, e as cópias de segurança de volumes resultantes são consistentes em caso de falha do sistema. Isto significa que todas as gravações transferidas para o disco num determinado momento são capturadas (ou seja, não existem gravações parciais). No entanto, algumas aplicações podem manter dados na memória que não são descarregados para o disco. Por isso, o facto de uma aplicação poder ou não recuperar com êxito de uma cópia de segurança consistente em caso de falha depende da lógica da aplicação.

Selecionar recursos

O primeiro passo na criação do recurso ProtectedApplication é identificar os outros recursos no mesmo Namespace que quer incluir como parte da aplicação. Este é o conjunto de recursos dos quais é feita uma cópia de segurança ou que são restaurados se fornecer a opção de âmbito selectedApplications na sua configuração BackupPlan.

Os recursos são identificados através de um seletor de etiquetas. Isto requer que etiquete todos os seus recursos (usando o campo metadata.label em cada recurso) com a mesma etiqueta. Tenha em atenção que isto também se aplica a recursos criados automaticamente por controladores. Estes recursos criados automaticamente são etiquetados com o respetivo modelo. Tenha em atenção que é comum reutilizar a mesma etiqueta que já está a usar para associar os Pods e os PersistentVolumeClaims gerados ao respetivo recurso principal.

As considerações de utilização incluem o seguinte:

  • Se quiser proteger recursos que criam recursos secundários, os recursos principais (como StatefulSet, Deployment ou DaemonSet) e os recursos secundários (como Pod ou PersistentVolumeClaim) têm de ter a etiqueta usada no campo Selector de ProtectedApplication.
  • Se alguns dos recursos referenciados pelo seu ProtectedApplication forem criados automaticamente por um operador, também deve incluir os recursos personalizados do operador no seu seletor ProtectedApplication. Isto ajuda a evitar uma condição de corrida no momento do restauro que pode ocorrer quando o operador tenta criar um recurso enquanto este está a ser restaurado a partir da cópia de segurança.

O exemplo seguinte mostra como pode aplicar a etiqueta app: nginx aos outros recursos, além do 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 a etiqueta selecionada a todos os recursos de destino (e aos modelos a partir dos quais são gerados recursos adicionais), pode fazer referência a esses recursos a partir de um ProtectedApplication. Por exemplo:

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

Defina regras de orquestração

Depois de identificar todos os recursos no seu ProtectedApplication, pode optar por definir regras de orquestração detalhadas para um subconjunto destes recursos. Estas regras só se podem aplicar a dois tipos de recursos: Deployments e StatefulSets e são referenciadas na secção components do ProtectedApplication.

Vista geral dos componentes

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

  • Selecionar uma estratégia fundamental para o funcionamento da cópia de segurança e do restauro deste componente. Existem três estratégias disponíveis:

    • BackupAllRestoreAll: fazer uma cópia de segurança dos volumes associados a todas as instâncias do componente e restaurá-los todos a partir das cópias de segurança.

    • BackupOneRestoreAll: fazer uma cópia de segurança dos volumes de apenas uma instância do componente e usar essas cópias de segurança para restaurar todas as instâncias.

    • DumpAndLoad: exportar dados da aplicação para um único volume no momento da cópia de segurança e importar esses dados para a aplicação no momento do restauro.

  • Definir hooks de execução para serem executados durante a cópia de segurança (e, possivelmente, o restauro, consoante a estratégia). Um comando é um comando que é executado em contentores específicos.

  • Selecionar um subconjunto de volumes para fazer uma cópia de segurança.

Introduções de execução

Um comando é um comando de shell que a Cópia de segurança do GKE executa num contentor numa fase específica do processo de cópia de segurança ou restauro.

Existem quatro tipos diferentes de hooks:

  • pre hooks: estes comandos são executados imediatamente antes de ser feita uma cópia de segurança dos volumes e, geralmente, espera-se que limpem todos os dados na memória para o disco e, em seguida, desativem a aplicação para que não ocorram novas gravações no disco. Estes pontos de união são usados nas estratégias BackupAllRestoreAll e BackupOneRestoreAll.

  • post hooks – estes comandos são executados durante o processo de cópia de segurança do volume imediatamente após o passo SNAPSHOTTING do processo de cópia de segurança do volume (antes do passo UPLOADING). Geralmente, o passo de CAPTURA DE IMAGENS demora apenas alguns segundos. Geralmente, espera-se que desativem o estado de inatividade da aplicação (ou seja, permitam que o processamento normal e as escritas no disco continuem). Estes pontos de gancho são usados nas estratégias BackupAllRestoreAll, BackupOneRestoreAll e DumpAndLoad.

  • dump hooks – estes comandos são executados antes de ser feito uma cópia de segurança do volume na estratégia DumpAndLoad e, geralmente, espera-se que exportem dados da aplicação para o volume de cópia de segurança designado.

  • load hooks - estes comandos são executados no momento do restauro após o restauro do volume de cópia de segurança nos casos de estratégia DumpAndLoad. Geralmente, espera-se que importem os dados do volume de cópia de segurança para a aplicação.

Pode fornecer mais do que um ponto de gancho para cada tipo, e o Backup for GKE executa-os pela ordem que definir.

Define os hooks como parte da secção de componentes da especificação ProtectedApplication. Todas as definições de hooks têm os mesmos campos disponíveis:

  • name: um nome que atribui ao gancho.

  • container - (opcional) nome do contentor no qual executar o comando. Se não for fornecido o contentor, o Backup for GKE executa o comando no primeiro contentor definido para os destinos Pod(s)

  • command: este é o comando real enviado para o contentor, construído como uma matriz de palavras. A primeira palavra na matriz é o caminho para o comando e as palavras subsequentes são os argumentos a transmitir ao comando.

  • timeoutSeconds - (opcional) tempo antes de a execução do gancho ser anulada. Se não fornecer este valor, a predefinição é 30 segundos.

  • onError: (opcional) comportamento adotado quando o gancho falha. Pode ser definido como Ignore ou Fail (predefinição). Se definir esta opção como Fail, quando um gancho falha, a cópia de segurança do volume falha. Se definir esta opção como Ignore, as falhas deste gancho são ignoradas.

Antes de aplicar os hooks ProtectedApplication à sua aplicação, deve testar o comando usando kubectl exec para garantir que os hooks se comportam como esperado:

kubectl exec POD_NAME -- COMMAND

Substitua o seguinte:

  • POD_NAME: o nome do agrupamento que contém o recurso ProtectedApplication.
  • COMMAND: a matriz que contém o comando que quer executar no contentor.

Selecionar um subconjunto de volumes para fazer uma cópia de segurança

Por vezes, as aplicações escrevem em volumes que não são interessantes para restaurar (por exemplo, determinados volumes de registo ou temporários). Pode suprimir a cópia de segurança destes volumes através de um seletor de volumes.

Para usar esta funcionalidade, tem de aplicar primeiro uma etiqueta comum aos recursos PersistentVolumeClaim dos volumes dos quais quer fazer uma cópia de segurança. Também tem de deixar esta etiqueta desativada nos recursos PersistentVolumeClaim dos volumes dos quais não quer fazer uma cópia de segurança. Em seguida, inclua uma cláusula volumeSelector na definição do componente da seguinte forma:

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

Se fornecer um volumeSelector para um componente, apenas os volumes cujos recursos PersistentVolumeClaim tenham a etiqueta especificada são copiados e restaurados. No momento do restauro, todos os outros volumes são aprovisionados como vazios, em vez de serem restaurados a partir de uma cópia de segurança de volume.

Estratégia: BackupAllRestoreAll

Esta é a estratégia mais simples e faz uma cópia de segurança de todos os volumes do componente no momento da cópia de segurança e restaura-os todos a partir das respetivas cópias de segurança de volumes no momento do restauro. É a melhor escolha quando a sua aplicação não tem replicação entre Pods.

Esta estratégia suporta os seguintes parâmetros:

  • backupPreHooks - (opcional) uma lista ordenada de hooks que são executados imediatamente antes de serem feitas cópias de segurança dos volumes. Estes comandos são executados em todos os Pods no componente.

  • backupPostHooks - (opcional) uma lista ordenada de hooks que são executados depois de as cópias de segurança de volumes terem atingido a fase UPLOADING. Estes comandos são executados em todos os Pods no componente.

  • volumeSelector - (opcional) lógica para fazer corresponder um subconjunto de volumes para fazer uma cópia de segurança.

Este exemplo cria um recurso ProtectedApplication que desativa o sistema de ficheiros antes de fazer uma cópia de segurança do volume de registos e reativa-o após a cópia de segurança:

kind: ProtectedApplication
apiVersion: gkebackup.gke.io/v1
metadata:
  name: nginx
  namespace: sales
spec:
  resourceSelection:
    type: Selector
    selector:
      matchLabels:
        app: nginx
  components:
  - name: nginx-app
    resourceKind: Deployment
    resourceNames: ["nginx-deployment"]
    strategy:
      type: BackupAllRestoreAll
      backupAllRestoreAll:
        backupPreHooks:
        - name: freeze
          container: nginx
          command:
          - bash
          - "-c"
          - |
            # Add application logic to flush data to disk before snapshot
            # and freeze the application from further changes.
            echo "Freezing the application"

            # Return 0 on successful freeze of application, and non-zero
            # for errors
            exit 0
        backupPostHooks:
        - name: unfreeze
          container: nginx
          command:
          - bash
          - "-c"
          - |
            # Add application logic to unfreeze the application.
            echo "Unfreezing the application"

            # Return 0 on successful freeze of application, and non-zero
            # for errors
            exit 0

Estratégia: BackupOneAndRestoreAll

Esta estratégia faz uma cópia de segurança de um Pod selecionado. Esta única cópia é a origem para restaurar todos os pods durante um restauro. Este método pode ajudar a reduzir o custo de armazenamento e o tempo de cópia de segurança. Esta estratégia funciona numa configuração de alta disponibilidade quando um componente é implementado com um PersistentVolumeClaim principal e vários PersistentVolumeClaims secundários.

Esta estratégia suporta os seguintes parâmetros:

  • backupTargetName: (obrigatório) especifica que Deployment ou StatefulSet quer usar para fazer uma cópia de segurança dos dados. O melhor Pod para fazer uma cópia de segurança é selecionado automaticamente. Numa configuração de alta disponibilidade, recomendamos que defina este valor para uma das réplicas da sua aplicação.

  • backupPreHooks - (opcional) uma lista ordenada de hooks que são executados imediatamente antes de serem feitas cópias de segurança dos volumes. Estes comandos só são executados na cópia de segurança selecionada Pod.

  • backupPostHooks - (opcional) uma lista ordenada de hooks que são executados depois de as cópias de segurança de volumes terem atingido a fase UPLOADING. Estes comandos só são executados na cópia de segurança selecionada Pod.

  • volumeSelector - (opcional) lógica para fazer corresponder um subconjunto de volumes para fazer uma cópia de segurança.

Se um componente estiver configurado com várias implementações ou StatefulSets, todos os recursos têm de ter a mesma estrutura de PersistentVolume, o que significa que têm de seguir estas regras:

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

Tendo em conta estas considerações, é possível selecionar vários conjuntos de volumes para a cópia de segurança, mas apenas é selecionado um volume de cada conjunto de volumes.

Este exemplo, partindo do princípio de uma arquitetura de um StatefulSet principal e um StatefulSet secundário, mostra uma cópia de segurança dos volumes de um Pod no StatefulSet secundário e, em seguida, um restauro a todos os outros volumes:

kind: ProtectedApplication
apiVersion: gkebackup.gke.io/v1
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

Esta estratégia usa um volume dedicado para processos de cópia de segurança e restauro e requer um PersistentVolumeClaim dedicado anexado a um componente que armazena dados de despejo.

Esta estratégia suporta os seguintes parâmetros:

  • dumpTarget: (obrigatório) especifica a implementação ou o StatefulSet que quer usar para fazer uma cópia de segurança dos dados. O melhor Pod para fazer uma cópia de segurança é selecionado automaticamente. Numa configuração de alta disponibilidade, recomendamos que defina este valor para uma das réplicas da sua aplicação.

  • loadTarget - (obrigatório) especifica que Deployment ou StatefulSet deve ser usado para carregar os dados. O melhor Pod para fazer uma cópia de segurança é selecionado automaticamente. O objetivo de carregamento não tem de ser igual ao objetivo de despejo.

  • dumpHooks - (obrigatório) uma lista ordenada de hooks que são executados para preencher o volume de cópia de segurança dedicado. Estes comandos só são executados no despejo selecionado Pod.

  • backupPostHooks - (opcional) uma lista ordenada de hooks que são executados depois de as cópias de segurança de volumes terem atingido a fase UPLOADING. Estes comandos são executados apenas no despejo selecionado Pod.

  • loadHooks - (obrigatório) Uma lista ordenada de hooks que são executados para carregar os dados do volume restaurado após o início da aplicação. Estes comandos são executados apenas na carga selecionada Pod.

  • volumeSelector - (obrigatório) lógica para fazer corresponder um único volume à cópia de segurança e à restauração (o volume "dump"). Embora só tenha de corresponder a um único volume, configura-o da mesma forma que o subconjunto de volumes a fazer uma cópia de segurança usado por outras estratégias.

Se a aplicação consistir em implementações, cada implementação tem de ter exatamente uma réplica.

Este exemplo, assumindo uma arquitetura de um StatefulSet principal e um StatefulSet secundário com PersistentVolumeClaims dedicado para StatefulSets principal e secundário, mostra uma estratégia DumpAndLoad:

kind: ProtectedApplication
apiVersion: gkebackup.gke.io/v1
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

Verifique se um ProtectedApplication está pronto para a cópia de segurança

Pode verificar se um ProtectedApplication está pronto para uma cópia de segurança executando o seguinte comando:

kubectl describe protectedapplication APPLICATION_NAME

Substitua APPLICATION_NAME pelo nome da sua aplicação.

Se estiver pronta, a descrição da aplicação mostra o estado Ready to backup como true, como neste exemplo:

% kubectl describe protectedapplication nginx
Name:         nginx
Namespace:    default
API Version:  gkebackup.gke.io/v1
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>

O que se segue?