Fazer backup e restaurar o AlloyDB Omni para um armazenamento compatível com S3 usando o orquestrador RPM

1. Introdução

Neste codelab, você faz backup de um cluster de alta disponibilidade (HA) para repositório de objetos compatível com S3 para o AlloyDB Omni usando o orquestrador RPM.

Este codelab usa o cluster do codelab Implantar um cluster de alta disponibilidade do AlloyDB Omni em VMs do GCE usando o orquestrador RPM para criar um cluster de alta disponibilidade em máquinas virtuais (VMs) do Compute Engine. Neste codelab, você vai adicionar um servidor de repositório de objetos compatível com S3 a uma das VMs. Você usa o servidor de repositório de objetos para o cluster de alta disponibilidade fazer backup dos dados e restaurar o cluster do servidor.

O Cloud Shell se conecta à VM de controle. A VM de controle executa o Ansible e o MinIO. O psql se conecta ao cluster pelo IP virtual das VMs do HAProxy. As VMs de banco de dados enviam backups para o MinIO na porta 9000.

Pré-requisitos

  • Ter um projeto do Google Cloud com o faturamento ativado.
  • Os papéis do IAM listados no codelab de alta disponibilidade.
  • Conhecimento básico de comandos do Linux e SQL.

O que você vai aprender

  • Como instalar e executar um repositório de objetos compatível com S3 para backups.
  • Como criar um plano de backup que grava backups em um armazenamento compatível com S3.
  • Como criar um backup sob demanda.
  • Como restaurar um cluster de um backup e para um momento específico.

O que é necessário

2. Configuração e requisitos

  1. Nesta etapa, você vai criar um cluster de alta disponibilidade usando o codelab Implantar um cluster de alta disponibilidade do AlloyDB Omni em VMs do GCE usando o orquestrador RPM. Siga as etapas a seguir. Se você já tiver um cluster do codelab, siga para a próxima etapa.
  2. Observação: não execute a etapa "Limpar recursos" nesta fase. Você vai realizar essa etapa no final deste codelab.
  3. Volte a este codelab

3. Conectar ao cluster e adicionar dados de amostra

Nesta etapa, você carrega as configurações do cluster na VM de controle. Em seguida, conecte-se ao cluster e adicione uma tabela com dados de amostra.

  1. Se você não estiver conectado à VM de controle, faça isso no Cloud Shell:
    gcloud compute ssh "$CLUSTER-control" --zone="$ZONE" --project="$PROJECT"
    
    As variáveis CLUSTER, ZONE e PROJECT vêm da etapa Preparar as VMs para a implantação do codelab Implantar um cluster de alta disponibilidade do AlloyDB Omni em VMs do GCE usando o orquestrador RPM. Se o Cloud Shell não tiver essas variáveis, defina-as novamente.
  2. Na VM de controle, mude para seu diretório inicial e carregue as variáveis de ambiente. Em seguida, adicione o nome do cluster e o usuário SSH ao arquivo de ambiente:
    cd ~
    source /tmp/cluster.conf
    cat >> ~/.codelab.env <<EOF
    export CLUSTER="$cluster"
    export SSH_USER="$service_account"
    EOF
    source ~/.codelab.env
    env | grep -E '^(CLUSTER|SSH_USER|VIRTUAL_IP)='
    
    Verifique se a saída mostra CLUSTER, SSH_USER e VIRTUAL_IP. Observação:se você se conectar à VM de controle novamente mais tarde, execute cd ~ e source ~/.codelab.env antes de continuar.
  3. Adicione as configurações de conexão ao arquivo de ambiente. Quando o comando read pedir a senha, digite a senha do usuário postgres. Você define essa senha na etapa Inicializar o cluster do AlloyDB Omni do codelab Implantar um cluster de alta disponibilidade do AlloyDB Omni em VMs do GCE usando o orquestrador RPM.
    cat >> ~/.codelab.env <<'EOF'
    export PATH="/usr/pgsql-18/bin:$PATH"
    export PGHOST="$VIRTUAL_IP"
    export PGUSER="postgres"
    EOF
    read -rsp "Password of the postgres user: " PGPASSWORD; echo
    printf 'export PGPASSWORD=%q\n' "$PGPASSWORD" >> ~/.codelab.env
    source ~/.codelab.env
    env | grep -E '^(PGHOST|PGUSER|PGPASSWORD)='
    
  4. Crie uma tabela e adicione 1.000 linhas:
    psql <<'SQL'
    CREATE TABLE public.orders (
      id integer PRIMARY KEY,
      item text NOT NULL,
      created_at timestamptz NOT NULL DEFAULT pg_catalog.now()
    );
    INSERT INTO public.orders (id, item)
    SELECT g, 'item-' || g FROM pg_catalog.generate_series(1, 1000) AS g;
    SQL
    
  5. Conte as linhas:
    psql -c "SELECT pg_catalog.count(*) FROM public.orders;"
    
    Verifique se a saída retorna 1000.

4. Instalar e executar o repositório de objetos compatível com S3

Nesta etapa, você vai escrever um playbook do Ansible que instala um servidor MinIO na VM de controle. O playbook também cria o bucket e o usuário para os backups e garante que as VMs de banco de dados possam se conectar ao MinIO. Execute todos os comandos desta etapa na VM de controle.

  1. Na VM de controle, adicione as configurações de armazenamento ao arquivo de ambiente. Os comandos openssl criam senhas aleatórias.
    MD=http://metadata.google.internal/computeMetadata/v1/instance
    S3_IP=$(curl -s -H "Metadata-Flavor: Google" "$MD/network-interfaces/0/ip")
    cat >> ~/.codelab.env <<EOF
    export S3_IP="$S3_IP"
    export S3_HOST="$CLUSTER-control"
    export S3_BUCKET="alloydb-backups"
    export S3_REGION="us-east-1"
    export MINIO_ROOT_USER="s3admin"
    export MINIO_ROOT_PASSWORD="$(openssl rand -hex 16)"
    export S3_ACCESS_KEY_ID="alloydb-backup"
    export S3_SECRET_ACCESS_KEY="$(openssl rand -hex 16)"
    export MINIO_URL="https://github.com/minio/minio/releases/download/RELEASE.2024-05-10T01-41-38Z/minio.linux-amd64.RELEASE.2024-05-10T01-41-38Z"
    export MC_URL="https://github.com/minio/mc/releases/download/RELEASE.2024-05-09T17-04-24Z/mc.linux-amd64.RELEASE.2024-05-09T17-04-24Z"
    EOF
    source ~/.codelab.env
    echo "$S3_HOST $S3_IP"
    
    Verifique se a saída mostra o nome e o endereço IP interno da VM de controle, por exemplo, my-cluster-control 10.1.0.2. As VMs de banco de dados usam esse nome do host e endereço IP para se conectar ao MinIO. O servidor de metadados da VM fornece o endereço IP. Para mais informações, consulte a documentação de metadados da VM.Os valores MINIO_URL e MC_URL são os URLs de download do servidor MinIO e do cliente MinIO (mc).
  2. Instale a coleção community.crypto do Ansible necessária na VM de controle:
    ansible-galaxy collection install community.crypto
    
  3. Crie o playbook s3_server.yaml:
    cat > s3_server.yaml <<EOF
    - name: Install and run MinIO on the control VM
      hosts: localhost
      connection: local
      become: true
      gather_facts: false
      tasks:
        - name: Create MinIO directories
          ansible.builtin.file:
            path: "{{ item }}"
            state: directory
            mode: "0755"
          loop:
            - /var/lib/minio/data
            - /var/lib/minio/certs
    
        - name: Download MinIO server and client
          ansible.builtin.get_url:
            url: "{{ item.url }}"
            dest: "{{ item.dest }}"
            mode: "0755"
          loop:
            - url: "$MINIO_URL"
              dest: /usr/local/bin/minio
            - url: "$MC_URL"
              dest: /usr/local/bin/mc
    
        - name: Generate MinIO TLS private key
          community.crypto.openssl_privatekey:
            path: /var/lib/minio/certs/private.key
            size: 2048
            mode: "0600"
    
        - name: Generate MinIO certificate signing request
          community.crypto.openssl_csr_pipe:
            privatekey_path: /var/lib/minio/certs/private.key
            common_name: "$S3_HOST"
            subject_alt_name:
              - "DNS:$S3_HOST"
              - "DNS:$S3_BUCKET.$S3_HOST"
              - "DNS:localhost"
              - "IP:127.0.0.1"
              - "IP:$S3_IP"
          register: minio_csr
    
        - name: Generate self-signed MinIO TLS certificate
          community.crypto.x509_certificate:
            path: /var/lib/minio/certs/public.crt
            csr_content: "{{ minio_csr.csr }}"
            privatekey_path: /var/lib/minio/certs/private.key
            provider: selfsigned
            selfsigned_not_after: "+365d"
            mode: "0644"
    
        - name: Create MinIO systemd service unit
          ansible.builtin.copy:
            dest: /etc/systemd/system/minio.service
            mode: "0600"
            content: |
              [Unit]
              Description=MinIO Object Storage
              After=network.target
    
              [Service]
              Environment="MINIO_ROOT_USER=$MINIO_ROOT_USER"
              Environment="MINIO_ROOT_PASSWORD=$MINIO_ROOT_PASSWORD"
              Environment="MINIO_DOMAIN=$S3_HOST"
              ExecStart=/usr/local/bin/minio server /var/lib/minio/data --certs-dir /var/lib/minio/certs
              Restart=on-failure
    
              [Install]
              WantedBy=multi-user.target
    
        - name: Start and enable MinIO service
          ansible.builtin.systemd_service:
            name: minio
            daemon_reload: true
            state: started
            enabled: true
    
        - name: Add storage host names to /etc/hosts on the control VM
          ansible.builtin.lineinfile:
            path: /etc/hosts
            line: "$S3_IP $S3_HOST $S3_BUCKET.$S3_HOST"
            state: present
    
        - name: Wait for MinIO health endpoint
          ansible.builtin.uri:
            url: "https://$S3_HOST:9000/minio/health/live"
            ca_path: /var/lib/minio/certs/public.crt
            status_code: 200
          register: minio_health
          until: minio_health.status == 200
          retries: 6
          delay: 5
    
        - name: Create backup bucket and user in MinIO
          ansible.builtin.command:
            argv: "{{ item }}"
          loop:
            - - /usr/local/bin/mc
              - --insecure
              - alias
              - set
              - s3repo
              - "https://$S3_HOST:9000"
              - "$MINIO_ROOT_USER"
              - "$MINIO_ROOT_PASSWORD"
            - - /usr/local/bin/mc
              - --insecure
              - mb
              - --ignore-existing
              - "s3repo/$S3_BUCKET"
            - - /usr/local/bin/mc
              - --insecure
              - admin
              - user
              - add
              - s3repo
              - "$S3_ACCESS_KEY_ID"
              - "$S3_SECRET_ACCESS_KEY"
            - - /usr/local/bin/mc
              - --insecure
              - admin
              - policy
              - attach
              - s3repo
              - readwrite
              - --user
              - "$S3_ACCESS_KEY_ID"
          become: false
          no_log: true
    
    - name: Configure database VMs for MinIO
      hosts: primary_instance_nodes
      become: true
      gather_facts: false
      vars:
        ansible_user: $SSH_USER
        ansible_ssh_private_key_file: $HOME/ssh-key-cluster-sa
      tasks:
        - name: Set SELinux to permissive mode
          ansible.builtin.command:
            cmd: setenforce 0
    
        - name: Add storage host names to /etc/hosts
          ansible.builtin.lineinfile:
            path: /etc/hosts
            line: "$S3_IP $S3_HOST $S3_BUCKET.$S3_HOST"
            state: present
    
        - name: Verify storage host resolution
          ansible.builtin.getent:
            database: hosts
            key: "$S3_BUCKET.$S3_HOST"
    
        - name: Verify connection to MinIO
          ansible.builtin.uri:
            url: "https://$S3_HOST:9000/minio/health/live"
            validate_certs: false
            status_code: 200
    EOF
    
    A variável MINIO_DOMAIN permite que o MinIO aceite solicitações de estilo de host virtual. O orquestrador RPM usa o usuário alloydb-backup para gravar os backups. A política readwrite é uma política integrada do MinIO.
  4. Execute o playbook:
    ansible-playbook s3_server.yaml -i deployment_spec.yaml
    
    Verifique se a saída PLAY RECAP mostra failed=0 para localhost e para cada VM de banco de dados.
  5. Verifique se o bucket existe:
    mc --insecure ls s3repo
    
    Verifique se a saída mostra o bucket alloydb-backups/.

5. Criar um plano de backup

Um plano de backup contém o local de armazenamento, a programação e o período de retenção dos backups de um cluster. Nesta etapa, você vai criar um plano de backup para o bucket do MinIO.

  1. Na VM de controle, crie os playbooks de backup e de status. Você usa o playbook de backup para os recursos Secret, BackupPlan e Backup. Você usa o playbook de status para mostrar o status de um recurso.
    cat > backup.yaml <<EOF
    - name: Manage AlloyDB Omni backups
      hosts: localhost
      roles:
        - role: google.alloydbomni_orchestrator.backup
    EOF
    cat > status.yaml <<EOF
    - name: Get resource status
      hosts: localhost
      roles:
        - role: google.alloydbomni_orchestrator.status
    EOF
    
  2. Crie um recurso Secret para as credenciais do S3. Em seguida, aplique o recurso:
    S3_KEY_ID_B64=$(printf '%s' "$S3_ACCESS_KEY_ID" | base64 -w 0)
    S3_KEY_B64=$(printf '%s' "$S3_SECRET_ACCESS_KEY" | base64 -w 0)
    cat > s3_secret.yaml <<EOF
    Secret:
      metadata:
        name: s3-backup-secret
      spec:
        type: Opaque
        data:
          access-key-id: "$S3_KEY_ID_B64"
          access-key: "$S3_KEY_B64"
    EOF
    ansible-playbook backup.yaml -i deployment_spec.yaml \
        -e resource_spec=s3_secret.yaml
    
    Os nomes das chaves na seção data precisam ser access-key-id e access-key. É necessário aplicar o recurso Secret antes do recurso BackupPlan.
  3. Crie e aplique o recurso BackupPlan:
    cat > backup_plan.yaml <<EOF
    BackupPlan:
      metadata:
        name: s3-backup-plan
      spec:
        dbclusterRef: $CLUSTER
        backupLocation:
          type: S3
          s3Options:
            bucket: $S3_BUCKET
            key: /backups
            endpoint: https://$S3_HOST:9000
            region: $S3_REGION
            secretRef:
              name: s3-backup-secret
            caBundle:
              - |
    $(sed 's/^/            /' /var/lib/minio/certs/public.crt)
    EOF
    ansible-playbook backup.yaml -i deployment_spec.yaml \
        -e resource_spec=backup_plan.yaml
    
    O valor key é o caminho dos backups no bucket. Esse caminho precisa começar com uma barra (/). O campo caBundle contém o certificado de CA codificado em PEM que valida o certificado do servidor de armazenamento do S3.
  4. Verifique se o plano de backup está pronto:
    ansible-playbook status.yaml -i deployment_spec.yaml \
        -e resource_type=BackupPlan -e resource_name=s3-backup-plan
    
    Verifique se o campo phase mostra Ready. Se a fase não for Ready, aguarde um minuto e execute o comando novamente.
  5. Quando um plano de backup é criado, o orquestrador do RPM inicia automaticamente um backup completo inicial. Verifique se esse backup inicial foi concluído antes de criar um backup on demand:
    ansible-playbook status.yaml -i deployment_spec.yaml \
        -e resource_type=Backup
    
    Verifique se a fase inicial de backup foi concluída.

6. Criar um backup on demand

Nesta etapa, você vai criar um backup sob demanda do cluster.

  1. Na VM de controle, crie o recurso Backup. Em seguida, aplique o recurso:
    cat > create_backup.yaml <<EOF
    Backup:
      metadata:
        name: s3-backup-1
      spec:
        backupPlanRef: s3-backup-plan
        dbclusterRef: $CLUSTER
    EOF
    ansible-playbook backup.yaml -i deployment_spec.yaml \
        -e resource_spec=create_backup.yaml
    
    O campo backupPlanRef é o nome do plano de backup. O campo dbclusterRef é o nome do cluster.
  2. Verifique se o backup foi concluído:
    ansible-playbook status.yaml -i deployment_spec.yaml \
        -e resource_type=Backup -e resource_name=s3-backup-1
    
    Verifique se o campo phase mostra Succeeded. Se a fase não for Succeeded, aguarde um minuto e execute o comando novamente.
  3. Verifique se os arquivos de backup estão no bucket:
    mc --insecure tree "s3repo/$S3_BUCKET"
    
    Verifique se a saída mostra uma pasta backup que contém uma pasta db.

7. Restaurar o cluster de um backup

O orquestrador de RPM restaura um cluster no local. Nesta etapa, você vai excluir uma tabela e restaurá-la do backup. Depois, é possível restaurar o cluster para um momento específico.

Atenção:uma operação de restauração substitui todos os dados do cluster de banco de dados.

Restaurar a partir de um backup

  1. Na VM de controle, exclua a tabela orders. Em seguida, conte as linhas:
    psql -c "DROP TABLE public.orders;"
    psql -c "SELECT pg_catalog.count(*) FROM public.orders;"
    
    Verifique se o segundo comando falha com um erro. A mensagem de erro mostra que a relação não existe. Por exemplo, "ERROR: table "orders" does not exist"
  2. Crie o playbook de restauração:
    cat > restore.yaml <<EOF
    - name: Restore AlloyDB Omni cluster
      hosts: localhost
      roles:
        - role: google.alloydbomni_orchestrator.restore
    EOF
    
  3. Crie um recurso Restore para o backup s3-backup-1. Em seguida, aplique o recurso:
    cat > restore_backup.yaml <<EOF
    Restore:
      metadata:
        name: s3-restore-1
      spec:
        sourceDBCluster: $CLUSTER
        backup: s3-backup-1
    EOF
    ansible-playbook restore.yaml -i deployment_spec.yaml \
        -e resource_spec=restore_backup.yaml
    
  4. Verifique se a operação de restauração foi concluída:
    ansible-playbook status.yaml -i deployment_spec.yaml \
        -e resource_type=Restore -e resource_name=s3-restore-1
    
    Verifique se o campo phase mostra ProvisionSucceeded. Se a fase não for ProvisionSucceeded, aguarde um minuto e execute o comando novamente.
  5. Conte as linhas na tabela restaurada:
    psql -c "SELECT pg_catalog.count(*) FROM public.orders;"
    
    Verifique se a saída mostra 1000.

(Opcional) Restaurar para um momento específico

Uma restauração pontual usa um backup e o registro prévio de escrita (WAL) arquivado. É possível restaurar o cluster para qualquer momento na janela de recuperação do plano de backup.

Regras para o tempo de destino

Você precisa seguir todas as regras para escolher o valor e o formato do tempo de destino:

  • Use o formato RFC 3339 em UTC: YYYY-MM-DDThh:mm:ssZ. Por exemplo, 2026-06-19T14:30:00Z é 14:30:00 UTC em 19 de junho de 2026. A letra T separa a data e a hora. A letra Z mostra o UTC.
  • Use um tempo no passado.
  • Use um horário depois do valor begin do campo recoveryWindow do CRD BackupPlan.

Para mostrar a hora atual no formato RFC 3339, execute este comando:

date -u +%Y-%m-%dT%H:%M:%SZ

Para mudar um horário local para esse formato, adicione o ajuste de UTC do horário local ao comando date. Por exemplo, o comando a seguir muda 16:30:00 em 19 June 2026 em UTC+02:00:

date -u -d "2026-06-19 16:30:00 +0200" +%Y-%m-%dT%H:%M:%SZ

O comando retorna 2026-06-19T14:30:00Z.

Restaurar para um horário gravado

Neste procedimento, você adiciona linhas à tabela e registra um horário. Ao registrar um horário, você marca o momento exato em que o banco de dados está completamente intacto (com exatamente 1.500 linhas). Em seguida,exclua as linhas e restaure o cluster para o horário registrado.

  1. Adicione 500 linhas à tabela:
    psql <<'SQL'
    INSERT INTO public.orders (id, item)
    SELECT g, 'item-' || g FROM pg_catalog.generate_series(1001, 1500) AS g;
    SQL
    
  2. Registre o horário. A tabela tem 1.500 linhas no momento.
    sleep 5
    PITR_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)
    echo "export PITR_TIME=$PITR_TIME" >> ~/.codelab.env
    echo "$PITR_TIME"
    sleep 5
    
    Verifique se a saída mostra uma hora no formato YYYY-MM-DDThh:mm:ssZ, por exemplo, 2026-10-05T11:16:02Z.
  3. Exclua linhas da tabela para simular uma exclusão acidental de dados. Em seguida, inicie um novo arquivo do WAL:
    psql -c "DELETE FROM public.orders WHERE id > 1000;"
    psql -c "SELECT pg_catalog.count(*) FROM public.orders;"
    psql -c "SELECT pg_catalog.pg_switch_wal();"
    
    Verifique se a consulta count mostra 1000. A função pg_switch_wal faz com que o servidor inicie um novo arquivo WAL. Em seguida, o servidor pode arquivar o arquivo WAL que contém suas mudanças.
  4. Verifique se o período de recuperação do plano de backup contém o horário gravado:
    test -n "$PITR_TIME" || { echo "PITR_TIME is not set. Run step 2 again."; exit 1; }
    echo "$PITR_TIME"
    ansible-playbook status.yaml -i deployment_spec.yaml \
        -e resource_type=BackupPlan -e resource_name=s3-backup-plan
    
    Verifique se o valor PITR_TIME está depois do valor begin do campo recoveryWindow.
  5. Crie um recurso Restore para o tempo gravado. Em seguida, aplique o recurso:
    cat > restore_pitr.yaml <<EOF
    Restore:
      metadata:
        name: s3-restore-pitr
      spec:
        sourceDBCluster: $CLUSTER
        pointInTime: "$PITR_TIME"
    EOF
    ansible-playbook restore.yaml -i deployment_spec.yaml \
        -e resource_spec=restore_pitr.yaml
    
  6. Verifique se a operação de restauração foi concluída:
    ansible-playbook status.yaml -i deployment_spec.yaml \
        -e resource_type=Restore -e resource_name=s3-restore-pitr
    
    Verifique se o campo phase mostra ProvisionSucceeded. Se a fase não for ProvisionSucceeded, aguarde um minuto e execute o comando novamente.
  7. Conte as linhas:
    psql -c "SELECT pg_catalog.count(*) FROM public.orders;"
    
    Verifique se a saída mostra 1500.

8. Limpeza

Para evitar cobranças na sua conta do Google Cloud, exclua os recursos deste codelab e do codelab Implantar um cluster de alta disponibilidade do AlloyDB Omni em VMs do GCE usando o RPM Orchestrator. Primeiro, exclua os recursos de backup, depois o cluster e o ambiente de computação.

  1. Na VM de controle, crie o playbook de exclusão:
    cat > delete.yaml <<EOF
    - name: Delete AlloyDB Omni resources
      hosts: localhost
      roles:
        - role: google.alloydbomni_orchestrator.delete
    EOF
    
  2. Liste os backups:
    ansible-playbook status.yaml -i deployment_spec.yaml -e resource_type=Backup
    
    Verifique se a saída mostra o backup s3-backup-1.
  3. Exclua o backup do s3-backup-1:
    ansible-playbook delete.yaml -i deployment_spec.yaml \
        -e resource_type=Backup -e resource_name=s3-backup-1
    
  4. Exclua o plano de backup:
    ansible-playbook delete.yaml -i deployment_spec.yaml \
        -e resource_type=BackupPlan -e resource_name=s3-backup-plan
    
  5. Exclua o cluster e o ambiente de computação usando a etapa Limpar recursos do codelab Implantar um cluster de alta disponibilidade do AlloyDB Omni em VMs do GCE usando o orquestrador RPM. O servidor MinIO e os backups nele estão na VM de controle. Ao excluir o ambiente de computação, você exclui o servidor e os backups.

9. Parabéns

Parabéns! Você fez backup de um cluster de alta disponibilidade (HA) para repositório de objetos compatível com S3 para o AlloyDB Omni usando o orquestrador RPM. Em seguida, você restaurou o cluster dos backups.

O que vimos

  • Como instalar e executar o MinIO como repositório de objetos compatível com S3.
  • Como criar um plano de backup e um backup sob demanda.
  • Como restaurar um cluster de um backup e para um momento específico.

Para mais informações, consulte as seguintes páginas:

10. Pesquisa

Como você usará este tutorial?

Apenas leitura Leitura e exercícios