Desplegar una base de datos de PostgreSQL de alta disponibilidad en GKE

PostgreSQL es una base de datos relacional de objetos de código abierto conocida por su fiabilidad e integridad de los datos. Cumple los requisitos de ACID y admite claves externas, uniones, vistas, activadores y procedimientos almacenados.

Este documento está dirigido a administradores de bases de datos, arquitectos de la nube y profesionales de operaciones que quieran desplegar una topología de PostgreSQL de alta disponibilidad en Google Kubernetes Engine (GKE).

Objetivos

En este tutorial aprenderás a:

  • Usa Terraform para crear un clúster de GKE regional.
  • Despliega una base de datos PostgreSQL de alta disponibilidad.
  • Configura la monitorización de la aplicación PostgreSQL.
  • Realiza actualizaciones de bases de datos PostgreSQL y clústeres de GKE.
  • Simula una interrupción del clúster y una conmutación por error de la réplica de PostgreSQL.
  • Realiza copias de seguridad y restauraciones de la base de datos PostgreSQL.

Arquitectura

En esta sección se describe la arquitectura de la solución que crearás en este tutorial.

Aprovisionarás dos clústeres de GKE en regiones diferentes: un clúster principal y un clúster de copia de seguridad. En este tutorial, el clúster principal está en la región us-central1 y el clúster de copia de seguridad está en la región us-west1. Esta arquitectura te permite aprovisionar una base de datos PostgreSQL de alta disponibilidad y probar la recuperación tras desastres, como se describe más adelante en este tutorial.

En el clúster de origen, usarás un gráfico de Helm (bitnami/postgresql-ha) para configurar un clúster de PostgreSQL de alta disponibilidad.

En el diagrama se muestra un ejemplo de arquitectura de un clúster de PostgreSQL de alta disponibilidad.
Figura 1: Arquitectura de ejemplo de un clúster de PostgreSQL de alta disponibilidad.

Costes

En este documento, se utilizan los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costes basada en el uso previsto, utiliza la calculadora de precios.

Los usuarios nuevos Google Cloud pueden disfrutar de una prueba gratuita.

Cuando termines las tareas que se describen en este documento, puedes evitar que se te siga facturando eliminando los recursos que has creado. Para obtener más información, consulta la sección Limpiar.

Antes de empezar

Configurar el proyecto

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, click Create project to begin creating a new Google Cloud project.

    Roles required to create a project

    To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. Enable the Google Kubernetes Engine, Backup for GKE, Artifact Registry, Compute Engine, and IAM APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  5. In the Google Cloud console, on the project selector page, click Create project to begin creating a new Google Cloud project.

    Roles required to create a project

    To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  6. Verify that billing is enabled for your Google Cloud project.

  7. Enable the Google Kubernetes Engine, Backup for GKE, Artifact Registry, Compute Engine, and IAM APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  8. Configurar roles

    1. Make sure that you have the following role or roles on the project: roles/storage.objectViewer, roles/logging.logWriter, roles/artifactregistry.Admin, roles/container.clusterAdmin, roles/container.serviceAgent, roles/serviceusage.serviceUsageAdmin, roles/iam.serviceAccountAdmin

      Check for the roles

      1. In the Google Cloud console, go to the IAM page.

        Go to IAM
      2. Select the project.
      3. In the Principal column, find all rows that identify you or a group that you're included in. To learn which groups you're included in, contact your administrator.

      4. For all rows that specify or include you, check the Role column to see whether the list of roles includes the required roles.

      Grant the roles

      1. In the Google Cloud console, go to the IAM page.

        Ir a IAM
      2. Selecciona el proyecto.
      3. Haz clic en Conceder acceso.
      4. En el campo Nuevos principales, introduce tu identificador de usuario. Normalmente, se trata de la dirección de correo de una cuenta de Google.

      5. En la lista Selecciona un rol, elige un rol.
      6. Para conceder más roles, haz clic en Añadir otro rol y añade cada rol adicional.
      7. Haz clic en Guardar.

      Configurar un entorno

      En este tutorial, usarás Cloud Shell para gestionar los recursos alojados enGoogle Cloud. Cloud Shell incluye preinstalado el software que necesitarás para este tutorial, como Docker, kubectl, la CLI de gcloud, Helm y Terraform.

      Para usar Cloud Shell y configurar tu entorno, sigue estos pasos:

      1. Inicia una sesión de Cloud Shell desde la Google Cloud consolaIcono de activación de Cloud Shell haciendo clic en Activar Cloud Shell en la Google Cloud consola. Se iniciará una sesión en el panel inferior de la consola. Google Cloud

      2. Define las variables de entorno.

        export PROJECT_ID=PROJECT_ID
        export SOURCE_CLUSTER=cluster-db1
        export REGION=us-central1
        

        Sustituye los siguientes valores:

      3. Define las variables de entorno predeterminadas.

        gcloud config set project PROJECT_ID
        
      4. Clona el repositorio de código.

        git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
        
      5. Cambia al directorio de trabajo.

        cd kubernetes-engine-samples/databases/gke-stateful-postgres
        

      Crear la infraestructura del clúster

      En esta sección, ejecutarás una secuencia de comandos de Terraform para crear una nube privada virtual (VPC) personalizada, un repositorio de Artifact Registry para almacenar imágenes de PostgreSQL y dos clústeres de GKE regionales. Un clúster se desplegará en us-central1 y el segundo clúster de copia de seguridad se desplegará en us-west1.

      Para crear el clúster, sigue estos pasos:

      Autopilot

      En Cloud Shell, ejecuta los siguientes comandos:

      terraform -chdir=terraform/gke-autopilot init
      terraform -chdir=terraform/gke-autopilot apply -var project_id=$PROJECT_ID
      

      Cuando se te solicite, escribe yes.

      Información sobre la configuración de Terraform

      Los archivos de configuración de Terraform crean los siguientes recursos para desplegar tu infraestructura:

      • Crea un repositorio de Artifact Registry para almacenar las imágenes de Docker.
        resource "google_artifact_registry_repository" "main" {
          location      = "us"
          repository_id = "main"
          format        = "DOCKER"
          project       = var.project_id
        }
      • Crea la red VPC y la subred de la interfaz de red de la VM.
        module "gcp-network" {
          source  = "terraform-google-modules/network/google"
          version = "< 8.0.0"
        
          project_id   = var.project_id
          network_name = "vpc-gke-postgresql"
        
          subnets = [
            {
              subnet_name           = "snet-gke-postgresql-us-central1"
              subnet_ip             = "10.0.0.0/17"
              subnet_region         = "us-central1"
              subnet_private_access = true
            },
            {
              subnet_name           = "snet-gke-postgresql-us-west1"
              subnet_ip             = "10.0.128.0/17"
              subnet_region         = "us-west1"
              subnet_private_access = true
            },
          ]
        
          secondary_ranges = {
            ("snet-gke-postgresql-us-central1") = [
              {
                range_name    = "ip-range-pods-db1"
                ip_cidr_range = "192.168.0.0/18"
              },
              {
                range_name    = "ip-range-svc-db1"
                ip_cidr_range = "192.168.64.0/18"
              },
            ],
            ("snet-gke-postgresql-us-west1") = [
              {
                range_name    = "ip-range-pods-db2"
                ip_cidr_range = "192.168.128.0/18"
              },
              {
                range_name    = "ip-range-svc-db2"
                ip_cidr_range = "192.168.192.0/18"
              },
            ]
          }
        }
        
        output "network_name" {
          value = module.gcp-network.network_name
        }
        
        output "primary_subnet_name" {
          value = module.gcp-network.subnets_names[0]
        }
        
        output "secondary_subnet_name" {
          value = module.gcp-network.subnets_names[1]
        }
      • Crea un clúster de GKE principal.

        Terraform crea un clúster privado en la región us-central1 y habilita Copia de seguridad de GKE para la recuperación ante desastres y Managed Service para Prometheus para la monitorización de clústeres.

        Managed Service para Prometheus solo se admite en clústeres de Autopilot que ejecuten la versión 1.25 de GKE o una posterior.

        module "gke-db1-autopilot" {
          source                          = "../modules/beta-autopilot-private-cluster"
          project_id                      = var.project_id
          name                            = "cluster-db1"
          kubernetes_version              = "1.25" # Will be ignored if use "REGULAR" release_channel
          region                          = "us-central1"
          regional                        = true
          zones                           = ["us-central1-a", "us-central1-b", "us-central1-c"]
          network                         = module.network.network_name
          subnetwork                      = module.network.primary_subnet_name
          ip_range_pods                   = "ip-range-pods-db1"
          ip_range_services               = "ip-range-svc-db1"
          horizontal_pod_autoscaling      = true
          release_channel                 = "RAPID" # Default version is 1.22 in REGULAR. GMP on Autopilot requires V1.25 via var.kubernetes_version
          enable_vertical_pod_autoscaling = true
          enable_private_endpoint         = false
          enable_private_nodes            = true
          master_ipv4_cidr_block          = "172.16.0.0/28"
          create_service_account          = false
        }

      • Crea un clúster de copia de seguridad en la región us-west1 para la recuperación tras fallos.

        module "gke-db2-autopilot" {
          source                          = "../modules/beta-autopilot-private-cluster"
          project_id                      = var.project_id
          name                            = "cluster-db2"
          kubernetes_version              = "1.25" # Will be ignored if use "REGULAR" release_channel
          region                          = "us-west1"
          regional                        = true
          zones                           = ["us-west1-a", "us-west1-b", "us-west1-c"]
          network                         = module.network.network_name
          subnetwork                      = module.network.secondary_subnet_name
          ip_range_pods                   = "ip-range-pods-db2"
          ip_range_services               = "ip-range-svc-db2"
          horizontal_pod_autoscaling      = true
          release_channel                 = "RAPID" # Default version is 1.22 in REGULAR. GMP on Autopilot requires V1.25 via var.kubernetes_version
          enable_vertical_pod_autoscaling = true
          enable_private_endpoint         = false
          enable_private_nodes            = true
          master_ipv4_cidr_block          = "172.16.0.16/28"
          create_service_account          = false
        }

      Estándar

      En Cloud Shell, ejecuta los siguientes comandos:

      terraform -chdir=terraform/gke-standard init
      terraform -chdir=terraform/gke-standard apply -var project_id=$PROJECT_ID
      

      Cuando se te solicite, escribe yes.

      Información sobre la configuración de Terraform

      Los archivos de configuración de Terraform crean los siguientes recursos para desplegar tu infraestructura:

      • Crea un repositorio de Artifact Registry para almacenar las imágenes de Docker.
        resource "google_artifact_registry_repository" "main" {
          location      = "us"
          repository_id = "main"
          format        = "DOCKER"
          project       = var.project_id
        }
        resource "google_artifact_registry_repository_iam_binding" "binding" {
          provider   = google-beta
          project    = google_artifact_registry_repository.main.project
          location   = google_artifact_registry_repository.main.location
          repository = google_artifact_registry_repository.main.name
          role       = "roles/artifactregistry.reader"
          members = [
            "serviceAccount:${module.gke-db1.service_account}",
          ]
        }
      • Crea la red VPC y la subred de la interfaz de red de la VM.
        module "gcp-network" {
          source  = "terraform-google-modules/network/google"
          version = "< 8.0.0"
        
          project_id   = var.project_id
          network_name = "vpc-gke-postgresql"
        
          subnets = [
            {
              subnet_name           = "snet-gke-postgresql-us-central1"
              subnet_ip             = "10.0.0.0/17"
              subnet_region         = "us-central1"
              subnet_private_access = true
            },
            {
              subnet_name           = "snet-gke-postgresql-us-west1"
              subnet_ip             = "10.0.128.0/17"
              subnet_region         = "us-west1"
              subnet_private_access = true
            },
          ]
        
          secondary_ranges = {
            ("snet-gke-postgresql-us-central1") = [
              {
                range_name    = "ip-range-pods-db1"
                ip_cidr_range = "192.168.0.0/18"
              },
              {
                range_name    = "ip-range-svc-db1"
                ip_cidr_range = "192.168.64.0/18"
              },
            ],
            ("snet-gke-postgresql-us-west1") = [
              {
                range_name    = "ip-range-pods-db2"
                ip_cidr_range = "192.168.128.0/18"
              },
              {
                range_name    = "ip-range-svc-db2"
                ip_cidr_range = "192.168.192.0/18"
              },
            ]
          }
        }
        
        output "network_name" {
          value = module.gcp-network.network_name
        }
        
        output "primary_subnet_name" {
          value = module.gcp-network.subnets_names[0]
        }
        
        output "secondary_subnet_name" {
          value = module.gcp-network.subnets_names[1]
        }
      • Crea un clúster de GKE principal.

        Terraform crea un clúster privado en la región us-central1 y habilita Copia de seguridad de GKE para la recuperación ante desastres y Managed Service para Prometheus para la monitorización de clústeres.

        module "gke-db1" {
          source                   = "../modules/beta-private-cluster"
          project_id               = var.project_id
          name                     = "cluster-db1"
          regional                 = true
          region                   = "us-central1"
          network                  = module.network.network_name
          subnetwork               = module.network.primary_subnet_name
          ip_range_pods            = "ip-range-pods-db1"
          ip_range_services        = "ip-range-svc-db1"
          create_service_account   = true
          enable_private_endpoint  = false
          enable_private_nodes     = true
          master_ipv4_cidr_block   = "172.16.0.0/28"
          network_policy           = true
          cluster_autoscaling = {
            "autoscaling_profile": "OPTIMIZE_UTILIZATION",
            "enabled" : true,
            "gpu_resources" : [],
            "min_cpu_cores" : 36,
            "min_memory_gb" : 144,
            "max_cpu_cores" : 48,
            "max_memory_gb" : 192,
          }
          monitoring_enable_managed_prometheus = true
          gke_backup_agent_config = true
        
          node_pools = [
            {
              name            = "pool-sys"
              autoscaling     = true
              min_count       = 1
              max_count       = 3
              max_surge       = 1
              max_unavailable = 0
              machine_type    = "e2-standard-4"
              node_locations  = "us-central1-a,us-central1-b,us-central1-c"
              auto_repair     = true
            },
            {
              name            = "pool-db"
              autoscaling     = true
              max_surge       = 1
              max_unavailable = 0
              machine_type    = "e2-standard-8"
              node_locations  = "us-central1-a,us-central1-b,us-central1-c"
              auto_repair     = true
            },
          ]
          node_pools_labels = {
            all = {}
            pool-db = {
              "app.stateful/component" = "postgresql"
            }
            pool-sys = {
              "app.stateful/component" = "postgresql-pgpool"
            }
          }
          node_pools_taints = {
            all = []
            pool-db = [
              {
                key    = "app.stateful/component"
                value  = "postgresql"
                effect = "NO_SCHEDULE"
              },
            ],
            pool-sys = [
              {
                key    = "app.stateful/component"
                value  = "postgresql-pgpool"
                effect = "NO_SCHEDULE"
              },
            ],
          }
          gce_pd_csi_driver = true
        }

      • Crea un clúster de copia de seguridad en la región us-west1 para la recuperación tras fallos.

        module "gke-db2" {
          source                   = "../modules/beta-private-cluster"
          project_id               = var.project_id
          name                     = "cluster-db2"
          regional                 = true
          region                   = "us-west1"
          network                  = module.network.network_name
          subnetwork               = module.network.secondary_subnet_name
          ip_range_pods            = "ip-range-pods-db2"
          ip_range_services        = "ip-range-svc-db2"
          create_service_account   = false
          service_account          = module.gke-db1.service_account
          enable_private_endpoint  = false
          enable_private_nodes     = true
          master_ipv4_cidr_block   = "172.16.0.16/28"
          network_policy           = true
          cluster_autoscaling = {
            "autoscaling_profile": "OPTIMIZE_UTILIZATION",
            "enabled" : true,
            "gpu_resources" : [],
            "min_cpu_cores" : 10,
            "min_memory_gb" : 144,
            "max_cpu_cores" : 48,
            "max_memory_gb" : 192,
          }
          monitoring_enable_managed_prometheus = true
          gke_backup_agent_config = true
          node_pools = [
            {
              name            = "pool-sys"
              autoscaling     = true
              min_count       = 1
              max_count       = 3
              max_surge       = 1
              max_unavailable = 0
              machine_type    = "e2-standard-4"
              node_locations  = "us-west1-a,us-west1-b,us-west1-c"
              auto_repair     = true
            },
            {
              name            = "pool-db"
              autoscaling     = true
              max_surge       = 1
              max_unavailable = 0
              machine_type    = "e2-standard-8"
              node_locations  = "us-west1-a,us-west1-b,us-west1-c"
              auto_repair     = true
            },
          ]
          node_pools_labels = {
            all = {}
            pool-db = {
              "app.stateful/component" = "postgresql"
            }
            pool-sys = {
              "app.stateful/component" = "postgresql-pgpool"
            }
          }
          node_pools_taints = {
            all = []
            pool-db = [
              {
                key    = "app.stateful/component"
                value  = "postgresql"
                effect = "NO_SCHEDULE"
              },
            ],
            pool-sys = [
              {
                key    = "app.stateful/component"
                value  = "postgresql-pgpool"
                effect = "NO_SCHEDULE"
              },
            ],
          }
          gce_pd_csi_driver = true
        }

      Desplegar PostgreSQL en tu clúster

      En esta sección, desplegarás una instancia de base de datos PostgreSQL para que se ejecute en GKE mediante un gráfico de Helm.

      Instalar PostgreSQL

      Para instalar PostgreSQL en tu clúster, sigue estos pasos.

      1. Configura el acceso a Docker.

        gcloud auth configure-docker us-docker.pkg.dev
        
      2. Rellena Artifact Registry con las imágenes Docker de PostgreSQL necesarias.

        ./scripts/gcr.sh bitnami/postgresql-repmgr 15.1.0-debian-11-r0
        ./scripts/gcr.sh bitnami/postgres-exporter 0.11.1-debian-11-r27
        ./scripts/gcr.sh bitnami/pgpool 4.3.3-debian-11-r28
        

        La secuencia de comandos envía las siguientes imágenes de Bitnami a Artifact Registry para que Helm las instale:

        • postgresql-repmgr: Esta solución de clúster de PostgreSQL incluye el gestor de réplicas de PostgreSQL (repmgr), una herramienta de código abierto para gestionar la réplica y la conmutación por error en clústeres de PostgreSQL.
        • postgres-exporter: PostgreSQL Exporter recoge métricas de PostgreSQL para que las use Prometheus.
        • pgpool: Pgpool-II es el proxy de PostgreSQL. Proporciona un grupo de conexiones y balanceo de carga.
      3. Verifica que las imágenes correctas estén almacenadas en el repositorio.

        gcloud artifacts docker images list us-docker.pkg.dev/$PROJECT_ID/main \
            --format="flattened(package)"
        

        El resultado debería ser similar al siguiente:

        ---
        image: us-docker.pkg.dev/[PROJECT_ID]/main/bitnami/pgpool
        ---
        image: us-docker.pkg.dev/[PROJECT_ID]/main/bitnami/postgres-exporter
        ---
        image: us-docker.pkg.dev/h[PROJECT_ID]/main/bitnami/postgresql-repmgr
        
      4. Configura el acceso a la línea de comandos kubectl al clúster principal.

        gcloud container clusters get-credentials $SOURCE_CLUSTER \
        --location=$REGION --project=$PROJECT_ID
        
      5. Crea un espacio de nombres.

        export NAMESPACE=postgresql
        kubectl create namespace $NAMESPACE
        
      6. Si vas a implementar en un clúster de Autopilot, configura el aprovisionamiento de nodos en tres zonas. Puedes saltarte este paso si vas a implementar en un clúster estándar.

        De forma predeterminada, Autopilot aprovisiona recursos en solo dos zonas. La implementación definida en prepareforha.yaml asegura que Autopilot aprovisione nodos en tres zonas de tu clúster. Para ello, se definen los siguientes valores:

        • replicas:3
        • podAntiAffinity con requiredDuringSchedulingIgnoredDuringExecution y topologyKey: "topology.kubernetes.io/zone"
        kubectl -n $NAMESPACE apply -f scripts/prepareforha.yaml
        
        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: prepare-three-zone-ha
          labels:
            app: prepare-three-zone-ha
            app.kubernetes.io/name: postgresql-ha
        spec:
          replicas: 3
          selector:
            matchLabels:
              app: prepare-three-zone-ha
              app.kubernetes.io/name: postgresql-ha
          template:
            metadata:
              labels:
                app: prepare-three-zone-ha
                app.kubernetes.io/name: postgresql-ha
            spec:
              affinity:
                podAntiAffinity:
                  requiredDuringSchedulingIgnoredDuringExecution:
                  - labelSelector:
                      matchExpressions:
                      - key: app
                        operator: In
                        values:
                        - prepare-three-zone-ha
                    topologyKey: "topology.kubernetes.io/zone"
                nodeAffinity:
                  preferredDuringSchedulingIgnoredDuringExecution:
                  - preference:
                      matchExpressions:
                      - key: cloud.google.com/compute-class
                        operator: In
                        values:
                        - "Scale-Out"
                    weight: 1
              nodeSelector:
                app.stateful/component: postgresql
              tolerations:
              - effect: NoSchedule
                key: app.stateful/component
                operator: Equal
                value: postgresql
              containers:
              - name: prepare-three-zone-ha
                image: busybox:latest
                command:
                    - "/bin/sh"
                    - "-c"
                    - "while true; do sleep 3600; done"
                resources:
                  limits:
                    cpu: "500m"
                    ephemeral-storage: "10Mi"
                    memory: "0.5Gi"
                  requests:
                    cpu: "500m"
                    ephemeral-storage: "10Mi"
                    memory: "0.5Gi"
        
      7. Actualiza la dependencia de Helm.

        cd helm/postgresql-bootstrap
        helm dependency update
        
      8. Inspecciona y verifica los gráficos que instalará Helm.

        helm -n postgresql template postgresql . \
          --set global.imageRegistry="us-docker.pkg.dev/$PROJECT_ID/main"
        
      9. Instala el gráfico de Helm.

        helm -n postgresql upgrade --install postgresql . \
            --set global.imageRegistry="us-docker.pkg.dev/$PROJECT_ID/main"
        

        El resultado debería ser similar al siguiente:

        NAMESPACE: postgresql
        STATUS: deployed
        REVISION: 1
        TEST SUITE: None
        
      10. Comprueba que las réplicas de PostgreSQL se están ejecutando.

        kubectl get all -n $NAMESPACE
        

        El resultado debería ser similar al siguiente:

        NAME                                                          READY   STATUS    RESTARTS   AGE
        pod/postgresql-postgresql-bootstrap-pgpool-75664444cb-dkl24   1/1     Running   0          8m39s
        pod/postgresql-postgresql-ha-pgpool-6d86bf9b58-ff2bg          1/1     Running   0          8m39s
        pod/postgresql-postgresql-ha-postgresql-0                     2/2     Running   0          8m39s
        pod/postgresql-postgresql-ha-postgresql-1                     2/2     Running   0          8m39s
        pod/postgresql-postgresql-ha-postgresql-2                     2/2     Running   0          8m38s
        
        NAME                                                   TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)    AGE
        service/postgresql-postgresql-ha-pgpool                ClusterIP   192.168.99.236    <none>        5432/TCP   8m39s
        service/postgresql-postgresql-ha-postgresql            ClusterIP   192.168.90.20     <none>        5432/TCP   8m39s
        service/postgresql-postgresql-ha-postgresql-headless   ClusterIP   None              <none>        5432/TCP   8m39s
        service/postgresql-postgresql-ha-postgresql-metrics    ClusterIP   192.168.127.198   <none>        9187/TCP   8m39s
        
        NAME                                                     READY   UP-TO-DATE   AVAILABLE   AGE
        deployment.apps/postgresql-postgresql-bootstrap-pgpool   1/1     1            1           8m39s
        deployment.apps/postgresql-postgresql-ha-pgpool          1/1     1            1           8m39s
        
        NAME                                                                DESIRED   CURRENT   READY   AGE
        replicaset.apps/postgresql-postgresql-bootstrap-pgpool-75664444cb   1         1         1       8m39s
        replicaset.apps/postgresql-postgresql-ha-pgpool-6d86bf9b58          1         1         1       8m39s
        
        NAME                                                   READY   AGE
        statefulset.apps/postgresql-postgresql-ha-postgresql   3/3     8m39s
        

      Crear un conjunto de datos de prueba

      En esta sección, crearás una base de datos y una tabla con valores de ejemplo. La base de datos sirve como conjunto de datos de prueba para el proceso de conmutación por error que probarás más adelante en este tutorial.

      1. Conéctate a tu instancia de PostgreSQL.

        cd ../../
        ./scripts/launch-client.sh
        

        El resultado debería ser similar al siguiente:

        Launching Pod pg-client in the namespace postgresql ...
        pod/pg-client created
        waiting for the Pod to be ready
        Copying script files to the target Pod pg-client ...
        Pod: pg-client is healthy
        
      2. Inicia una sesión de shell.

        kubectl exec -it pg-client -n postgresql -- /bin/bash
        
      3. Crea una base de datos y una tabla, y luego inserta algunas filas de prueba.

        psql -h $HOST_PGPOOL -U postgres -a -q -f /tmp/scripts/generate-db.sql
        
      4. Verifica el número de filas de cada tabla.

        psql -h $HOST_PGPOOL -U postgres -a -q -f /tmp/scripts/count-rows.sql
        

        El resultado debería ser similar al siguiente:

        select COUNT(*) from tb01;
         count
        --------
         300000
        (1 row)
        
        select COUNT(*) from tb02;
         count
        --------
         300000
        (1 row)
        
      5. Genera datos de prueba.

        export DB=postgres
        pgbench -i -h $HOST_PGPOOL -U postgres $DB -s 50
        

        El resultado debería ser similar al siguiente:

        dropping old tables...
        creating tables...
        generating data (client-side)...
        5000000 of 5000000 tuples (100%) done (elapsed 29.85 s, remaining 0.00 s)
        vacuuming...
        creating primary keys...
        done in 36.86 s (drop tables 0.00 s, create tables 0.01 s, client-side generate 31.10 s, vacuum 1.88 s, primary keys 3.86 s).
        
      6. Sal del pod del cliente de postgres.

        exit
        

      Monitorizar PostgreSQL

      En esta sección, verá las métricas y configurará alertas para su instancia de PostgreSQL. Usarás Google Cloud Managed Service para Prometheus para monitorizar y enviar alertas.

      Ver métricas

      Tu implementación de PostgreSQL incluye un contenedor sidecar postgresql-exporter. Este contenedor expone un endpoint /metrics. Google Cloud Managed Service para Prometheus está configurado para monitorizar los pods de PostgreSQL en este endpoint. Puede ver estas métricas en los paneles de control de la consola de Google Cloud .

      La consola Google Cloud ofrece varias formas de crear y guardar la configuración de un panel de control:

      • Creación y exportación: puedes crear paneles de control directamente en la Google Cloud consola y, a continuación, exportarlos y almacenarlos en un repositorio de código. Para ello, en la barra de herramientas del panel de control, abre el editor de JSON y descarga el archivo JSON del panel de control.
      • Almacenamiento e importación: puedes importar un panel de control desde un archivo JSON haciendo clic en + Crear panel de control y subiendo el contenido JSON del panel de control mediante el menú Editor de JSON.

      Para visualizar los datos de tu aplicación PostgreSQL y tu clúster de GKE, sigue estos pasos:

      1. Crea los siguientes paneles de control.

        cd monitoring
        gcloud monitoring dashboards create \
                --config-from-file=dashboard/postgresql-overview.json \
                --project=$PROJECT_ID
        gcloud monitoring dashboards create \
                --config-from-file dashboard/gke-postgresql.json \
                --project $PROJECT_ID
        
      2. En la Google Cloud consola, ve al panel de control de Cloud Monitoring. Ir al panel de control de Cloud Monitoring

      3. Seleccione Personalizado en la lista de paneles de control. Aparecerán los siguientes paneles de control:

        • Resumen de PostgreSQL: muestra métricas de la aplicación PostgreSQL, como el tiempo de actividad de la base de datos, el tamaño de la base de datos y la latencia de las transacciones.
        • Clúster de PostgreSQL de GKE: muestra métricas del clúster de GKE en el que se ejecuta PostgreSQL, como el uso de CPU, el uso de memoria y la utilización del volumen.
      4. Haz clic en cada enlace para examinar los paneles de control generados.

      Configurar alertas

      Las alertas te permiten detectar los problemas de tus aplicaciones a tiempo para que puedas resolverlos rápidamente. Puedes crear una política de alertas para especificar las circunstancias en las que quieres recibir alertas y cómo quieres que se te notifique. También puedes crear canales de notificaciones para seleccionar dónde se envían las alertas.

      En esta sección, usarás Terraform para configurar las siguientes alertas de ejemplo:

      • db_max_transaction: monitoriza el retraso máximo de las transacciones en segundos. Se activará una alerta si el valor es superior a 10.
      • db_node_up: monitoriza el estado de los pods de la base de datos. El valor 0 significa que un pod está inactivo y activa una alerta.

      Para configurar alertas, sigue estos pasos:

      1. Configura alertas con Terraform.

        EMAIL=YOUR_EMAIL
        cd alerting/terraform
        terraform init
        terraform plan -var project_id=$PROJECT_ID -var email_address=$EMAIL
        terraform apply -var project_id=$PROJECT_ID -var email_address=$EMAIL
        

        Sustituye los siguientes valores:

        • YOUR_EMAIL: tu dirección de correo electrónico.

        La salida es similar a la siguiente :

        Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
        
      2. Conéctate al pod del cliente.

        cd ../../../
        kubectl exec -it --namespace postgresql pg-client -- /bin/bash
        
      3. Genera una prueba de carga para probar la alerta db_max_transaction.

        pgbench -i -h $HOST_PGPOOL -U postgres -s 200 postgres
        

        El resultado debería ser similar al siguiente:

        dropping old tables...
        creating tables...
        generating data (client-side)...
        20000000 of 20000000 tuples (100%) done (elapsed 163.22 s, remaining 0.00 s)
        vacuuming...
        creating primary keys...
        done in 191.30 s (drop tables 0.14 s, create tables 0.01 s, client-side generate 165.62 s, vacuum 4.52 s, primary keys 21.00 s).
        

        La alerta se activa y envía un correo a YOUR_EMAIL con un asunto que empieza por "[ALERT] Max Lag of transaction".

      4. En la Google Cloud consola, ve a la página Política de alertas.

        Ir a la política de alertas

      5. Selecciona db_max_transaction de las políticas que se muestran. En el gráfico, deberías ver un pico de la prueba de carga que supere el umbral de 10 de la métrica de Prometheus pg_stat_activity_max_tx_duration/gauge.

      6. Sal del pod del cliente de postgres.

        exit
        

      Gestionar las actualizaciones de PostgreSQL y GKE

      Las actualizaciones de las versiones de PostgreSQL y Kubernetes se publican de forma periódica. Sigue las prácticas recomendadas operativas para actualizar tu entorno de software con regularidad. De forma predeterminada, GKE gestiona las actualizaciones de clústeres y grupos de nodos.

      Actualizar PostgreSQL

      En esta sección se explica cómo puedes actualizar la versión de PostgreSQL. En este tutorial, usarás una estrategia de actualización continua para actualizar tus pods, de forma que nunca se interrumpa el servicio de todos los pods.

      Para actualizar una versión, sigue estos pasos:

      1. Envía una versión actualizada de la imagen postgresql-repmgr a Artifact Registry. Define la nueva versión (por ejemplo, postgresql-repmgr 15.1.0-debian-11-r1).

        NEW_IMAGE=us-docker.pkg.dev/$PROJECT_ID/main/bitnami/postgresql-repmgr:15.1.0-debian-11-r1
        ./scripts/gcr.sh bitnami/postgresql-repmgr 15.1.0-debian-11-r1
        
      2. Activa una actualización continua con kubectl.

        kubectl set image statefulset -n postgresql postgresql-postgresql-ha-postgresql postgresql=$NEW_IMAGE
        kubectl rollout restart statefulsets -n postgresql postgresql-postgresql-ha-postgresql
        kubectl rollout status statefulset -n postgresql postgresql-postgresql-ha-postgresql
        

        Verás que StatefulSet completa una actualización continua, empezando por la réplica ordinal más alta y terminando por la más baja.

        El resultado debería ser similar al siguiente:

        Waiting for 1 pods to be ready...
        waiting for statefulset rolling update to complete 1 pods at revision postgresql-postgresql-ha-postgresql-5c566ccf49...
        Waiting for 1 pods to be ready...
        Waiting for 1 pods to be ready...
        waiting for statefulset rolling update to complete 2 pods at revision postgresql-postgresql-ha-postgresql-5c566ccf49...
        Waiting for 1 pods to be ready...
        Waiting for 1 pods to be ready...
        statefulset rolling update complete 3 pods at revision postgresql-postgresql-ha-postgresql-5c566ccf49...
        

      Planificar las actualizaciones de GKE en clústeres Standard

      Esta sección se aplica si ejecutas clústeres estándar. Puedes tomar medidas proactivas y definir configuraciones para mitigar los riesgos y facilitar una actualización más fluida del clúster cuando ejecutes servicios con estado, como los siguientes:

      Verificar la disponibilidad de la base de datos durante las actualizaciones de clústeres estándar

      Esta sección se aplica si ejecutas clústeres estándar. Para verificar la disponibilidad de PostgreSQL durante las actualizaciones, el proceso general consiste en generar tráfico en la base de datos de PostgreSQL durante el proceso de actualización. A continuación, usa pgbench para comprobar que la base de datos puede gestionar un nivel de tráfico básico durante una actualización, en comparación con el momento en el que la base de datos está totalmente disponible.

      1. Conéctate a tu instancia de PostgreSQL.

        ./scripts/launch-client.sh
        

        El resultado debería ser similar al siguiente:

        Launching Pod pg-client in the namespace postgresql ...
        pod/pg-client created
        waiting for the Pod to be ready
        Copying script files to the target Pod pg-client ...
        Pod: pg-client is healthy
        
      2. En Cloud Shell, accede al Pod del cliente.

        kubectl exec -it -n postgresql pg-client -- /bin/bash
        
      3. Inicializa pgbench .

        pgbench -i -h $HOST_PGPOOL -U postgres postgres
        
      4. Usa el siguiente comando para obtener resultados de referencia que te permitan confirmar que tu aplicación PostgreSQL mantiene una alta disponibilidad durante el periodo de actualización. Para obtener un resultado de referencia, haz una prueba con varias conexiones a través de varios trabajos (hilos) durante 30 segundos.

        pgbench -h $HOST_PGPOOL -U postgres postgres -c10 -j4 -T 30 -R 200
        

        El resultado es similar al siguiente:

        pgbench (14.5)
        starting vacuum...end.
        transaction type: <builtin: TPC-B (sort of)>
        scaling factor: 1
        query mode: simple
        number of clients: 10
        number of threads: 4
        duration: 30 s
        number of transactions actually processed: 5980
        latency average = 7.613 ms
        latency stddev = 2.898 ms
        rate limit schedule lag: avg 0.256 (max 36.613) ms
        initial connection time = 397.804 ms
        tps = 201.955497 (without initial connection time)
        
      5. Para asegurar la disponibilidad durante las actualizaciones, puedes generar cierta carga en tu base de datos y comprobar que la aplicación PostgreSQL proporciona una tasa de respuesta coherente durante la actualización. Para hacer esta prueba, genera tráfico en la base de datos con el comando pgbench. El siguiente comando ejecutará pgbench durante una hora, con un objetivo de 200 TPS (transacciones por segundo) y mostrando la tasa de solicitudes cada 2 segundos.

        pgbench -h $HOST_PGPOOL -U postgres postgres --client=10 --jobs=4 --rate=200 --time=3600 --progress=2 --select-only
        

        Donde:

        • --client: número de clientes simulados, es decir, número de sesiones de base de datos simultáneas.
        • --jobs: número de hilos de trabajo en pgbench. Usar más de un hilo puede ser útil en máquinas con varias CPUs. Los clientes se distribuyen de la forma más uniforme posible entre los subprocesos disponibles. El valor predeterminado es 1.
        • --rate: la tasa se indica en transacciones por segundo.
        • --progress: muestra un informe de progreso cada segundo.

        El resultado debería ser similar al siguiente:

        pgbench (14.5)
        starting vacuum...end.
        progress: 5.0 s, 354.8 tps, lat 25.222 ms stddev 15.038
        progress: 10.0 s, 393.8 tps, lat 25.396 ms stddev 16.459
        progress: 15.0 s, 412.8 tps, lat 24.216 ms stddev 14.548
        progress: 20.0 s, 405.0 tps, lat 24.656 ms stddev 14.066
        
      6. En la Google Cloud consola, vuelve al panel de control Resumen de PostgreSQL en Cloud Monitoring. Observa el pico en los gráficos Conexión por base de datos y Conexión por pod.

      7. Sal del pod del cliente.

        exit
        
      8. Elimina el pod del cliente.

        kubectl delete pod -n postgresql pg-client
        

      Simular una interrupción del servicio PostgreSQL

      En esta sección, simularás una interrupción del servicio en una de las réplicas de PostgreSQL deteniendo el servicio del gestor de réplicas. De esta forma, el Pod no podrá servir tráfico a sus réplicas del mismo nivel y sus comprobaciones de actividad fallarán.

      1. Abre una nueva sesión de Cloud Shell y configura el acceso a la línea de comandos kubectl al clúster principal.

        gcloud container clusters get-credentials $SOURCE_CLUSTER \
        --location=$REGION --project=$PROJECT_ID
        
      2. Consulta los eventos de PostgreSQL emitidos en Kubernetes.

        kubectl get events -n postgresql --field-selector=involvedObject.name=postgresql-postgresql-ha-postgresql-0 --watch
        
      3. En la sesión anterior de Cloud Shell, simula un fallo del servicio deteniendo PostgreSQL repmgr.

        1. Adjunta tu sesión al contenedor de la base de datos.

          kubectl exec -it -n $NAMESPACE postgresql-postgresql-ha-postgresql-0 -c postgresql -- /bin/bash
          
        2. Detén el servicio con repmgr y elimina el punto de control y el argumento dry-run.

          export ENTRY='/opt/bitnami/scripts/postgresql-repmgr/entrypoint.sh'
          export RCONF='/opt/bitnami/repmgr/conf/repmgr.conf'
          $ENTRY repmgr -f $RCONF node service --action=stop --checkpoint
          

      La sonda de vivacidad configurada para el contenedor de PostgreSQL empezará a fallar en un plazo de cinco segundos. Este proceso se repite cada diez segundos hasta que se alcanza el umbral de seis fallos. Cuando se alcanza el valor failureThreshold, se reinicia el contenedor. Puede configurar estos parámetros para reducir la tolerancia de la prueba de actividad y ajustar los requisitos de SLO de su implementación.

      En el flujo de eventos, verás que las sondas de vivacidad y de disponibilidad del pod fallan, así como un mensaje que indica que el contenedor debe reiniciarse. La salida es similar a la siguiente:

      0s          Normal    Killing                pod/postgresql-postgresql-ha-postgresql-0   Container postgresql failed liveness probe, will be restarted
      0s          Warning   Unhealthy              pod/postgresql-postgresql-ha-postgresql-0   Readiness probe failed: psql: error: connection to server at "127.0.0.1", port 5432 failed: Connection refused...
      0s          Normal    Pulled                 pod/postgresql-postgresql-ha-postgresql-0   Container image "us-docker.pkg.dev/psch-gke-dev/main/bitnami/postgresql-repmgr:14.5.0-debian-11-r10" already present on machine
      0s          Normal    Created                pod/postgresql-postgresql-ha-postgresql-0   Created container postgresql
      0s          Normal    Started                pod/postgresql-postgresql-ha-postgresql-0   Started container postgresql
      

      Prepararse para la recuperación tras fallos

      Para asegurarte de que tus cargas de trabajo de producción sigan estando disponibles en caso de que se produzca un evento que interrumpa el servicio, debes preparar un plan de recuperación tras fallos. Para obtener más información sobre la planificación de la recuperación tras fallos, consulta la guía de planificación de la recuperación tras fallos.

      La recuperación tras desastres de Kubernetes se puede implementar en dos fases:

      • La copia de seguridad consiste en crear una captura de un momento concreto de tu estado o datos antes de que se produzca un evento que interrumpa el servicio.
      • La recuperación consiste en restaurar el estado o los datos a partir de una copia de seguridad después de que se haya producido un desastre.

      Para crear copias de seguridad de tus cargas de trabajo en clústeres de GKE y restaurarlas, puedes usar Copia de seguridad de GKE. Puedes habilitar este servicio en clústeres nuevos y disponibles. De esta forma, se implementa un agente de copia de seguridad de GKE que se ejecuta en tus clústeres. Este agente se encarga de capturar los datos de configuración y de copia de seguridad de los volúmenes, así como de coordinar la recuperación.

      .

      Las copias de seguridad y las restauraciones se pueden limitar a un clúster completo, un espacio de nombres o una aplicación (definida por selectores como matchLabels).

      Ejemplo de situación de copia de seguridad y restauración de PostgreSQL

      En el ejemplo de esta sección se muestra cómo realizar una operación de copia de seguridad y restauración en el ámbito de la aplicación mediante el recurso personalizado ProtectedApplication.

      En el siguiente diagrama se muestran los recursos de componentes de ProtectedApplication, concretamente un StatefulSet que representa la aplicación postgresql-ha y una implementación de pgpool, que usan la misma etiqueta (app.kubernetes.io/name: postgresql-ha).

      En el diagrama se muestra un ejemplo de solución de copia de seguridad y recuperación para un clúster de PostgreSQL de alta disponibilidad.
      Imagen 2: ejemplo de solución de copia de seguridad y recuperación para un clúster de PostgreSQL de alta disponibilidad.

      Para preparar la copia de seguridad y la restauración de tu carga de trabajo de PostgreSQL, sigue estos pasos:

      1. Configura las variables de entorno. En este ejemplo, usarás un ProtectedApplication para restaurar la carga de trabajo de PostgreSQL y sus volúmenes desde el clúster de GKE de origen (us-central1) y, a continuación, restaurarás otro clúster de GKE en otra región (us-west1).

        export SOURCE_CLUSTER=cluster-db1
        export TARGET_CLUSTER=cluster-db2
        export REGION=us-central1
        export DR_REGION=us-west1
        export NAME_PREFIX=g-db-protected-app
        export BACKUP_PLAN_NAME=$NAME_PREFIX-bkp-plan-01
        export BACKUP_NAME=bkp-$BACKUP_PLAN_NAME
        export RESTORE_PLAN_NAME=$NAME_PREFIX-rest-plan-01
        export RESTORE_NAME=rest-$RESTORE_PLAN_NAME
        
      2. Comprueba que la función de copia de seguridad de GKE esté habilitada en tus clústeres. Debería estar habilitado como parte de la configuración de Terraform que has realizado anteriormente.

        gcloud container clusters describe $SOURCE_CLUSTER \
            --project=$PROJECT_ID  \
            --location=$REGION \
            --format='value(addonsConfig.gkeBackupAgentConfig)'
        

        Si la función de copia de seguridad de GKE está habilitada, el resultado del comando muestra enabled=True.

      Configurar un plan de copias de seguridad y realizar una restauración

      Copia de seguridad de GKE te permite crear un plan de copias de seguridad como tarea cron. Un plan de copia de seguridad contiene una configuración de copia de seguridad que incluye el clúster de origen, la selección de las cargas de trabajo de las que se va a crear una copia de seguridad y la región en la que se almacenan los artefactos de copia de seguridad creados con este plan.

      Para hacer una copia de seguridad y restaurarla, sigue estos pasos:

      1. Verifica el estado de ProtectedApplication en cluster-db1.

        kubectl get ProtectedApplication -A
        

        El resultado es similar al siguiente:

        NAMESPACE    NAME            READY TO BACKUP
        postgresql   postgresql-ha   true
        
      2. Crea un plan de copia de seguridad para ProtectedApplication.

        export NAMESPACE=postgresql
        export PROTECTED_APP=$(kubectl get ProtectedApplication -n $NAMESPACE | grep -v 'NAME' | awk '{ print $1 }')
        
        gcloud beta container backup-restore backup-plans create $BACKUP_PLAN_NAME \
        --project=$PROJECT_ID \
        --location=$DR_REGION \
        --cluster=projects/$PROJECT_ID/locations/$REGION/clusters/$SOURCE_CLUSTER \
        --selected-applications=$NAMESPACE/$PROTECTED_APP \
        --include-secrets \
        --include-volume-data \
        --cron-schedule="0 3 * * *" \
        --backup-retain-days=7 \
        --backup-delete-lock-days=0
        
      3. Crea una copia de seguridad manualmente.

        gcloud beta container backup-restore backups create $BACKUP_NAME \
        --project=$PROJECT_ID \
        --location=$DR_REGION \
        --backup-plan=$BACKUP_PLAN_NAME \
        --wait-for-completion
        
      4. Configura un plan de restauración.

        gcloud beta container backup-restore restore-plans create $RESTORE_PLAN_NAME \
          --project=$PROJECT_ID \
          --location=$DR_REGION \
          --backup-plan=projects/$PROJECT_ID/locations/$DR_REGION/backupPlans/$BACKUP_PLAN_NAME \
          --cluster=projects/$PROJECT_ID/locations/$DR_REGION/clusters/$TARGET_CLUSTER \
          --cluster-resource-conflict-policy=use-existing-version \
          --namespaced-resource-restore-mode=delete-and-restore \
          --volume-data-restore-policy=restore-volume-data-from-backup \
          --selected-applications=$NAMESPACE/$PROTECTED_APP \
          --cluster-resource-scope-selected-group-kinds="storage.k8s.io/StorageClass","scheduling.k8s.io/PriorityClass"
        
      5. Restaura los datos a partir de la copia de seguridad.

        gcloud beta container backup-restore restores create $RESTORE_NAME \
          --project=$PROJECT_ID \
          --location=$DR_REGION \
          --restore-plan=$RESTORE_PLAN_NAME \
          --backup=projects/$PROJECT_ID/locations/$DR_REGION/backupPlans/$BACKUP_PLAN_NAME/backups/$BACKUP_NAME \
          --wait-for-completion
        

      Verificar que el clúster se ha restaurado

      Para verificar que el clúster restaurado tiene todos los recursos Pods, PersistentVolume y StorageClass esperados, sigue estos pasos:

      1. Configura el acceso a la línea de comandos kubectl del clúster de copia de seguridad cluster-db2.

        gcloud container clusters get-credentials $TARGET_CLUSTER --location $DR_REGION --project $PROJECT_ID
        
      2. Verifica que el StatefulSet esté listo con 3/3 pods.

        kubectl get all -n $NAMESPACE
        

        El resultado debería ser similar al siguiente:

        NAME                                                   READY   STATUS    RESTARTS        AGE
        pod/postgresql-postgresql-ha-pgpool-778798b5bd-k2q4b   1/1     Running   0               4m49s
        pod/postgresql-postgresql-ha-postgresql-0              2/2     Running   2 (4m13s ago)   4m49s
        pod/postgresql-postgresql-ha-postgresql-1              2/2     Running   0               4m49s
        pod/postgresql-postgresql-ha-postgresql-2              2/2     Running   0               4m49s
        
        NAME                                                   TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)    AGE
        service/postgresql-postgresql-ha-pgpool                ClusterIP   192.168.241.46    <none>        5432/TCP   4m49s
        service/postgresql-postgresql-ha-postgresql            ClusterIP   192.168.220.20    <none>        5432/TCP   4m49s
        service/postgresql-postgresql-ha-postgresql-headless   ClusterIP   None              <none>        5432/TCP   4m49s
        service/postgresql-postgresql-ha-postgresql-metrics    ClusterIP   192.168.226.235   <none>        9187/TCP   4m49s
        
        NAME                                              READY   UP-TO-DATE   AVAILABLE   AGE
        deployment.apps/postgresql-postgresql-ha-pgpool   1/1     1            1           4m49s
        
        NAME                                                         DESIRED   CURRENT   READY   AGE
        replicaset.apps/postgresql-postgresql-ha-pgpool-778798b5bd   1         1         1       4m49s
        
        NAME                                                   READY   AGE
        statefulset.apps/postgresql-postgresql-ha-postgresql   3/3     4m49s
        
      3. Verifica que todos los pods del espacio de nombres postgres se estén ejecutando.

        kubectl get pods -n $NAMESPACE
        

        El resultado debería ser similar al siguiente:

        postgresql-postgresql-ha-pgpool-569d7b8dfc-2f9zx   1/1     Running   0          7m56s
        postgresql-postgresql-ha-postgresql-0              2/2     Running   0          7m56s
        postgresql-postgresql-ha-postgresql-1              2/2     Running   0          7m56s
        postgresql-postgresql-ha-postgresql-2              2/2     Running   0          7m56s
        
      4. Verifica los PersistentVolumes y StorageClass. Durante el proceso de restauración, Copia de seguridad de GKE crea una clase proxy en la carga de trabajo de destino para sustituir la clase de almacenamiento aprovisionada en la carga de trabajo de origen (gce-pd-gkebackup-dn en el ejemplo de salida).

        kubectl get pvc -n $NAMESPACE
        

        El resultado debería ser similar al siguiente:

        NAME                                         STATUS   VOLUME                 CAPACITY   ACCESS MODES   STORAGECLASS          AGE
        data-postgresql-postgresql-ha-postgresql-0   Bound    pvc-be91c361e9303f96   8Gi        RWO            gce-pd-gkebackup-dn   10m
        data-postgresql-postgresql-ha-postgresql-1   Bound    pvc-6523044f8ce927d3   8Gi        RWO            gce-pd-gkebackup-dn   10m
        data-postgresql-postgresql-ha-postgresql-2   Bound    pvc-c9e71a99ccb99a4c   8Gi        RWO            gce-pd-gkebackup-dn   10m
        

      Validar que se han restaurado los datos esperados

      Para comprobar que se han restaurado los datos esperados, sigue estos pasos:

      1. Conéctate a tu instancia de PostgreSQL.

        ./scripts/launch-client.sh
        kubectl exec -it pg-client -n postgresql -- /bin/bash
        
      2. Verifica el número de filas de cada tabla.

        psql -h $HOST_PGPOOL -U postgres -a -q -f /tmp/scripts/count-rows.sql
        select COUNT(*) from tb01;
        

        Deberías ver un resultado similar a los datos que has escrito antes en la sección Crear un conjunto de datos de prueba. El resultado debería ser similar al siguiente:

        300000
        (1 row)
        
      3. Sal del pod del cliente.

        exit
        

      Limpieza

      Para evitar que los recursos utilizados en este tutorial se cobren en tu cuenta de Google Cloud, elimina el proyecto que contiene los recursos o conserva el proyecto y elimina los recursos.

      Eliminar el proyecto

      La forma más fácil de evitar que te cobren es eliminar el proyecto que has creado para el tutorial.

    2. In the Google Cloud console, go to the Manage resources page.

      Go to Manage resources

    3. In the project list, select the project that you want to delete, and then click Delete.
    4. In the dialog, type the project ID, and then click Shut down to delete the project.
    5. Siguientes pasos