Implementa PostgreSQL en GKE con CloudNativePG

En la guía, se muestra cómo implementar clústeres de PostgreSQL en Google Kubernetes Engine (GKE) mediante el operador CloudNativePG.

PostgreSQL es una base de datos relacional de objetos de código abierto con varias décadas de desarrollo activo, lo que garantiza un rendimiento estable del cliente. Ofrece una variedad de funciones, incluidas la replicación, la recuperación de un momento determinado, las funciones de seguridad y la extensión. PostgreSQL es compatible con los principales sistemas operativos y cumple por completo con los estándares ACID (atomicidad, coherencia, aislamiento y durabilidad).

Esta guía está dirigida a administradores de plataformas, arquitectos de nube y profesionales de operaciones interesados en implementar clústeres de Postgres en GKE. Ejecutar Postgres en GKE en lugar de usar Cloud SQL puede brindar más flexibilidad y control de configuración a los administradores de bases de datos experimentados.

Ventajas

CloudNativePG es un operador de código abierto desarrollado por EDB con una licencia Apache 2. Brinda las siguientes funciones en la implementación de PostgreSQL:

  • Una forma declarativa y nativa de Kubernetes de administrar, configurar los clústeres de PostgreSQL
  • Administración de copias de seguridad mediante instantáneas de volumen o Cloud Storage
  • La conexión de encriptado en tránsito TLS, la capacidad de usar tu propia autoridad certificadora e integrarse en el Administrador de certificados para la rotación y emisión de certificados TLS automatizada
  • Actualizaciones progresivas para versiones secundarias de PostgreSQL
  • Uso del servidor de la API de Kubernetes para mantener el estado del clúster de PostgreSQL y conmutaciones por error para lograr una alta disponibilidad sin necesidad de herramientas adicionales
  • Una configuración integrada de exportador de Prometheus a través de métricas definidas por el usuario escritas en SQL

Objetivos

  • Planificar y, además, implementar la infraestructura de GKE para Postgres
  • Implementa y configura el operador de CloudNativePG Postgres con Helm
  • Implementa un clúster de PostgreSQL
  • Configura la autenticación y la observabilidad de PostgreSQL

Arquitectura de implementación

PostgreSQL tiene varias opciones de implementación desde un servidor de base de datos independiente hasta un clúster replicado con alta disponibilidad. Este instructivo se centra en la implementación del clúster con alta disponibilidad en GKE.

En esta implementación, las cargas de trabajo del clúster de PostgreSQL se distribuyen en varias zonas de disponibilidad dentro del clúster de GKE regional, lo que garantiza una alta disponibilidad y redundancia. Para obtener más información, consulta Clústeres regionales.

En el siguiente diagrama, se muestra un clúster de Postgres que se ejecuta en varios nodos y zonas en un clúster de GKE:

Clúster de Postgres en GKE

  • La configuración predeterminada incluye un servidor principal de PostgreSQL y dos servidores de copia de seguridad listos para actuar en caso de que el servidor principal falle, lo que garantiza una disponibilidad continua de la base de datos.

  • Los recursos del operador CloudNativePG usan un espacio de nombres independiente del clúster de GKE para obtener un mejor aislamiento de recursos y el enfoque de microservicios recomendado de una base de datos por clúster de PostgreSQL. La base de datos y su usuario correspondiente (usuario de la app) se definen en el recurso personalizado de Kubernetes que representa el clúster.

  • El almacenamiento es un componente fundamental cuando se analizan las bases de datos. El almacenamiento debe tener un rendimiento eficiente, garantizar la disponibilidad continua y la coherencia de los datos. Por estos motivos, recomendamos la clase de almacenamiento premium-rwo, que se basa en discos SSD. El operador CloudNativePG crea automáticamente PersistentVolumeClaims según sea necesario cuando se configuran Pods para el Clúster de PostgreSQL.

Costos

En este documento, usarás los siguientes componentes facturables de Google Cloud:

Para obtener una estimación de costos en función del uso previsto, usa la calculadora de precios.

Es posible que los usuarios de Google Cloud nuevos cumplan con los requisitos para acceder a una prueba gratuita.

Cuando completes las tareas que se describen en este documento, podrás borrar los recursos que creaste para evitar que se te siga facturando. Para obtener más información, consulta Realiza una limpieza.

Antes de comenzar

Cloud Shell tiene preinstalado el software que necesitas para este instructivo, incluido kubectl, gcloud CLI, Helm y Terraform. Si no usas Cloud Shell, debes instalar gcloud CLI.

  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. Install the Google Cloud CLI.

  3. Si usas un proveedor de identidad externo (IdP), primero debes Acceder a la gcloud CLI con tu identidad federada.

  4. Para inicializar gcloud CLI, ejecuta el siguiente comando:

    gcloud init
  5. Create or select a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.
    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

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

  7. Enable the Compute Engine, IAM, GKE, Resource Manager 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.

    gcloud services enable compute.googleapis.com iam.googleapis.com container.googleapis.com cloudresourcemanager.googleapis.com
  8. Install the Google Cloud CLI.

  9. Si usas un proveedor de identidad externo (IdP), primero debes Acceder a la gcloud CLI con tu identidad federada.

  10. Para inicializar gcloud CLI, ejecuta el siguiente comando:

    gcloud init
  11. Create or select a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.
    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

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

  13. Enable the Compute Engine, IAM, GKE, Resource Manager 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.

    gcloud services enable compute.googleapis.com iam.googleapis.com container.googleapis.com cloudresourcemanager.googleapis.com
  14. Grant roles to your user account. Run the following command once for each of the following IAM roles: roles/compute.securityAdmin, roles/compute.viewer, roles/container.clusterAdmin, roles/container.admin, roles/iam.serviceAccountAdmin, roles/iam.serviceAccountUser

    gcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE

    Replace the following:

    • PROJECT_ID: Your project ID.
    • USER_IDENTIFIER: The identifier for your user account. For example, myemail@example.com.
    • ROLE: The IAM role that you grant to your user account.
  15. Configura tu entorno

    Para configurar tu entorno, sigue estos pasos:

    1. Establece las variables de entorno:

      export PROJECT_ID=PROJECT_ID
      export KUBERNETES_CLUSTER_PREFIX=postgres
      export REGION=us-central1
      

      Reemplaza PROJECT_ID por tu Google Cloud ID del proyecto.

    2. Clona el repositorio de GitHub:

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

      cd kubernetes-engine-samples/databases/postgresql-cloudnativepg
      

    Crea la infraestructura del clúster

    En esta sección, debes ejecutar una secuencia de comandos de Terraform para crear un clúster de GKE privado, regional y con alta disponibilidad.

    Puedes instalar el operador mediante un clúster de Standard o Autopilot.

    Estándar

    En el siguiente diagrama, se muestra un clúster de GKE estándar regional privado implementado en tres zonas diferentes:

    Para implementar esta infraestructura, ejecuta los siguientes comandos:

    export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
    terraform -chdir=terraform/gke-standard init
    terraform -chdir=terraform/gke-standard apply \
    -var project_id=${PROJECT_ID}   \
    -var region=${REGION}  \
    -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}
    

    Cuando se te solicite, escribe yes. Es posible que este comando tarde varios minutos en completarse y que el clúster muestre un estado de preparación.

    Terraform crea los siguientes recursos:

    • Una red de VPC y una subred privada para los nodos de Kubernetes
    • Un router para acceder a Internet a través de NAT
    • Un clúster de GKE privado en la región us-central1
    • Un grupo de nodos con ajuste de escala automático habilitado (de uno a dos nodos por zona y un nodo por zona como mínimo)

    El resultado es similar al siguiente:

    ...
    Apply complete! Resources: 14 added, 0 changed, 0 destroyed.
    ...
    

    Autopilot

    En el siguiente diagrama, se muestra un clúster de GKE de Autopilot regional privado:

    Para implementar la infraestructura, ejecuta los siguientes comandos:

    export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
    terraform -chdir=terraform/gke-autopilot init
    terraform -chdir=terraform/gke-autopilot apply \
    -var project_id=${PROJECT_ID} \
    -var region=${REGION} \
    -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}
    

    Cuando se te solicite, escribe yes. Es posible que este comando tarde varios minutos en completarse y que el clúster muestre un estado de preparación.

    Terraform crea los siguientes recursos:

    • Una red de VPC y una subred privada para los nodos de Kubernetes
    • Un router para acceder a Internet a través de NAT
    • Un clúster de GKE privado en la región us-central1
    • Un ServiceAccount con permiso de registro y supervisión
    • Google Cloud Managed Service para Prometheus para la supervisión de clústeres

    El resultado es similar al siguiente:

    ...
    Apply complete! Resources: 12 added, 0 changed, 0 destroyed.
    ...
    

    Conéctate al clúster

    Configura kubectl para comunicarse con el clúster:

    gcloud container clusters get-credentials ${KUBERNETES_CLUSTER_PREFIX}-cluster --location ${REGION}
    

    Implementa el operador CloudNativePG

    Implementa CloudNativePG en tu clúster de Kubernetes con un gráfico de Helm:

    1. Agrega el repositorio de gráficos de Helm para operadores de CloudNativePG:

      helm repo add cnpg https://cloudnative-pg.github.io/charts
      
    2. Implementa el operador de CloudNativePG con la herramienta de línea de comandos de Helm:

      helm upgrade --install cnpg \
          --namespace cnpg-system \
          --create-namespace \
          cnpg/cloudnative-pg
      

      El resultado es similar al siguiente:

      Release "cnpg" does not exist. Installing it now.
      NAME: cnpg
      LAST DEPLOYED: Fri Oct 13 13:52:36 2023
      NAMESPACE: cnpg-system
      STATUS: deployed
      REVISION: 1
      TEST SUITE: None
      ...
      

    Implementa Postgres

    En el siguiente manifiesto, se describe un clúster de PostgreSQL, tal como se define en el recurso personalizado del operador CloudNativePG:

    apiVersion: postgresql.cnpg.io/v1
    kind: Cluster
    metadata:
      name: gke-pg-cluster
    spec:
      description: "Standard GKE PostgreSQL cluster"
      imageName: ghcr.io/cloudnative-pg/postgresql:16.2
      enableSuperuserAccess: true
      instances: 3
      startDelay: 300
      primaryUpdateStrategy: unsupervised
      postgresql:
        pg_hba:
          - host all all 10.48.0.0/20 md5
      bootstrap:
        initdb:
          database: app
      storage:
        storageClass: premium-rwo
        size: 2Gi
      resources:
        requests:
          memory: "1Gi"
          cpu: "1000m"
        limits:
          memory: "1Gi"
          cpu: "1000m"
      affinity:
        enablePodAntiAffinity: true
        tolerations:
        - key: cnpg.io/cluster
          effect: NoSchedule
          value: gke-pg-cluster
          operator: Equal
        additionalPodAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app.component
                  operator: In
                  values:
                  - "pg-cluster"
              topologyKey: topology.kubernetes.io/zone
      monitoring:
        enablePodMonitor: true

    Este manifiesto tiene los siguientes campos:

    • spec.instances: la cantidad de Pods del clúster
    • spec.primaryUpdateStrategy: la estrategia de actualización progresiva:
      • Unsupervised: actualiza de forma autónoma el nodo del clúster principal después de los nodos de réplica
      • Supervised: se requiere un cambio manual para el nodo del clúster principal
    • spec.postgresql: Anulaciones de parámetros del archivo postgres.conf, como las reglas pg-hba, LDAP y los requisitos para que se cumplan las réplicas de sincronización.
    • spec.storage: la configuración relacionada con el almacenamiento, como la clase de almacenamiento, el tamaño del volumen y la configuración de registro de escritura por adelantado.
    • spec.bootstrap: parámetros de la base de datos inicial creada en el clúster, credenciales de usuario y opciones de restablecimiento de la base de datos
    • spec.resources: solicitudes y límites para Pods del clúster
    • spec.affinity: reglas de afinidad y antiafinidad de las cargas de trabajo del clúster

    Crea un clúster básico de Postgres

    1. Crea un espacio de nombres:

      kubectl create ns pg-ns
      
    2. Crea el clúster de PostgreSQL mediante el recurso personalizado:

      kubectl apply -n pg-ns -f manifests/01-basic-cluster/postgreSQL_cluster.yaml
      

      Este comando puede tardar varios minutos en completarse.

    3. Verifica el estado del clúster:

      kubectl get cluster -n pg-ns --watch
      

      Espera a que el resultado muestre un estado de Cluster in healthy state antes de continuar con el siguiente paso.

      NAME             AGE     INSTANCES   READY   STATUS                     PRIMARY
      gke-pg-cluster   2m53s   3           3       Cluster in healthy state   gke-pg-cluster-1
      

    Inspecciona los recursos

    Confirma que GKE creó los recursos para el clúster:

    kubectl get cluster,pod,svc,pvc,pdb,secret,cm -n pg-ns
    

    El resultado es similar al siguiente:

    NAME                                        AGE   INSTANCES   READY   STATUS                     PRIMARY
    cluster.postgresql.cnpg.io/gke-pg-cluster   32m   3           3       Cluster in healthy state   gke-pg-cluster-1
    
    NAME                   READY   STATUS    RESTARTS   AGE
    pod/gke-pg-cluster-1   1/1     Running   0          31m
    pod/gke-pg-cluster-2   1/1     Running   0          30m
    pod/gke-pg-cluster-3   1/1     Running   0          29m
    
    NAME                        TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
    service/gke-pg-cluster-r    ClusterIP   10.52.11.24   <none>        5432/TCP   32m
    service/gke-pg-cluster-ro   ClusterIP   10.52.9.233   <none>        5432/TCP   32m
    service/gke-pg-cluster-rw   ClusterIP   10.52.1.135   <none>        5432/TCP   32m
    
    NAME                                     STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    persistentvolumeclaim/gke-pg-cluster-1   Bound    pvc-bbdd1cdd-bdd9-4e7c-8f8c-1a14a87e5329   2Gi        RWO            standard       32m
    persistentvolumeclaim/gke-pg-cluster-2   Bound    pvc-e7a8b4df-6a3e-43ce-beb0-b54ec1d24011   2Gi        RWO            standard       31m
    persistentvolumeclaim/gke-pg-cluster-3   Bound    pvc-dac7f931-6ac5-425f-ac61-0cfc55aae72f   2Gi        RWO            standard       30m
    
    NAME                                                MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
    poddisruptionbudget.policy/gke-pg-cluster           1               N/A               1                     32m
    poddisruptionbudget.policy/gke-pg-cluster-primary   1               N/A               0                     32m
    
    NAME                                TYPE                       DATA   AGE
    secret/gke-pg-cluster-app           kubernetes.io/basic-auth   3      32m
    secret/gke-pg-cluster-ca            Opaque                     2      32m
    secret/gke-pg-cluster-replication   kubernetes.io/tls          2      32m
    secret/gke-pg-cluster-server        kubernetes.io/tls          2      32m
    secret/gke-pg-cluster-superuser     kubernetes.io/basic-auth   3      32m
    
    NAME                                DATA   AGE
    configmap/cnpg-default-monitoring   1      32m
    configmap/kube-root-ca.crt          1      135m
    

    El operador crea los siguientes recursos:

    • Un recurso de clúster personalizado que representa el clúster de PostgreSQL y que controla el operador
    • Recursos PersistentVolumeClaim con Volúmenes persistentes correspondientes
    • Secrets con credenciales de usuario para acceder a la base de datos y replicación entre los nodos de Postgres.
    • Tres servicios de extremo de base de datos: <name>-rw, <name>-ro y <name>-r para conectarse al clúster. Para obtener más información, consulta Arquitectura de PostgreSQL.

    Autentícate en Postgres

    Puedes conectarte a la base de datos de PostgreSQL y verificar el acceso a través de diferentes extremos de servicio creados por el operador. Para hacerlo, usa un pod adicional con un cliente PostgreSQL y credenciales de usuario de la aplicación sincronizadas activadas como variables de entorno.

    1. Ejecuta el Pod de cliente para interactuar con tu clúster de Postgres:

      kubectl apply -n pg-ns -f manifests/02-auth/pg-client.yaml
      
    2. Ejecuta un comando exec en el Pod pg-client y accede al Service gke-pg-cluster-rw:

      kubectl wait --for=condition=Ready -n pg-ns pod/pg-client --timeout=300s
      kubectl exec -n pg-ns -i -t pg-client -- /bin/sh
      
    3. Accede a la base de datos con el servicio gke-pg-cluster-rw para establecer una conexión con privilegios de lectura y escritura:

      psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-rw.pg-ns/app
      

      La terminal empieza con el nombre de tu base de datos:

      app=>
      
    4. Crear una tabla:

      CREATE TABLE travel_agency_clients (
      client VARCHAR ( 50 ) UNIQUE NOT NULL,
      address VARCHAR ( 50 ) UNIQUE NOT NULL,
      phone VARCHAR ( 50 ) UNIQUE NOT NULL);
      
    5. Inserta datos en la tabla:

      INSERT INTO travel_agency_clients(client, address, phone)
      VALUES ('Tom', 'Warsaw', '+55555')
      RETURNING *;
      
    6. Visualiza los datos que creaste:

      SELECT * FROM travel_agency_clients ;
      

      El resultado es similar al siguiente:

      client | address |  phone
      --------+---------+---------
      Tom    | Warsaw  | +55555
      (1 row)
      
    7. Sal de la sesión actual de la base de datos:

      exit
      
    8. Accede a la base de datos con el servicio gke-pg-cluster-ro para la verificación del acceso de solo lectura. Este servicio permite consultar datos, pero restringe las operaciones de escritura:

      psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-ro.pg-ns/app
      
    9. Intenta insertar datos nuevos:

      INSERT INTO travel_agency_clients(client, address, phone)
      VALUES ('John', 'Paris', '+55555')
      RETURNING *;
      

      El resultado es similar al siguiente:

      ERROR:  cannot execute INSERT in a read-only transaction
      
    10. Intenta leer datos:

      SELECT * FROM travel_agency_clients ;
      

      El resultado es similar al siguiente:

      client | address |  phone
      --------+---------+---------
      Tom    | Warsaw  | +55555
      (1 row)
      
    11. Sal de la sesión actual de la base de datos:

      exit
      
    12. Sal de la shell del Pod:

      exit
      

    Comprende cómo Prometheus recopila métricas para tu clúster de Postgres

    En el siguiente diagrama, se muestra cómo funciona la recopilación de métricas de Prometheus:

    En el diagrama, un clúster privado de GKE contiene lo siguiente:

    • Un Pod de Postgres que recopila métricas en la ruta de acceso / y el puerto 9187
    • Recopiladores basados en Prometheus que procesan las métricas del Pod de Postgres
    • Un recurso PodMonitoring que envía métricas a Cloud Monitoring

    Para habilitar la recopilación de métricas de tus Pods, sigue estos pasos:

    1. Crea el recurso PodMonitoring:

      kubectl apply -f manifests/03-observability/pod-monitoring.yaml -n pg-ns
      
    2. En la consola de Google Cloud , ve a la página Explorador de métricas:

      Dirígete al Explorador de métricas

      En el panel, se muestra una tasa de transferencia de métricas distinta de cero.

    3. En Selecciona una métrica, ingresa Prometheus Target.

    4. En la sección Categorías de métricas activas, selecciona Cnpg.

    Crea un panel de métricas

    Para visualizar las métricas exportadas, crea un panel de métricas.

    1. Implementa un panel:

      gcloud --project "${PROJECT_ID}" monitoring dashboards create --config-from-file manifests/03-observability/gcp-pg.json
      
    2. En la consola de Google Cloud , ve a la página Paneles.

      Ir a Paneles

    3. Selecciona el panel PostgreSQL Prometheus Overview.

      Para revisar cómo los paneles supervisan las funciones, puedes reutilizar las acciones de la Autenticación de base de datos y aplicar solicitudes de lectura y escritura en la base de datos y, luego, revisa la visualización de las métricas recopiladas en un panel.

    4. Conéctate al Pod cliente:

      kubectl exec -n pg-ns -i -t pg-client -- /bin/sh
      
    5. Inserta datos aleatorios:

      psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-rw.pg-ns/app -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);INSERT INTO test (randomdata) VALUES (generate_series(1, 1000));"
      
    6. Actualiza el panel. Los grafos se actualizan con métricas actualizadas.

    7. Sal de la shell del Pod:

      exit
      

    Realiza una limpieza

    Borra el proyecto

      Delete a Google Cloud project:

      gcloud projects delete PROJECT_ID

    Borra los recursos individuales

    1. Configurar variables de entorno

      export PROJECT_ID=${PROJECT_ID}
      export KUBERNETES_CLUSTER_PREFIX=postgres
      export REGION=us-central1
      
    2. Ejecuta el comando terraform destroy:

      export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
      terraform  -chdir=terraform/FOLDER destroy \
        -var project_id=${PROJECT_ID} \
        -var region=${REGION} \
        -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}
      

      Reemplaza FOLDER por gke-autopilot o gke-standard.

      Cuando se te solicite, escribe yes.

    3. Busca todos los discos no conectados:

      export disk_list=$(gcloud compute disks list --filter="-users:* AND labels.name=${KUBERNETES_CLUSTER_PREFIX}-cluster" --format "value[separator=|](name,zone)")
      
    4. Borra los discos:

      for i in $disk_list; do
        disk_name=$(echo $i| cut -d'|' -f1)
        disk_zone=$(echo $i| cut -d'|' -f2|sed 's|.*/||')
        echo "Deleting $disk_name"
        gcloud compute disks delete $disk_name --zone $disk_zone --quiet
      done
      

    ¿Qué sigue?

    • Explora arquitecturas de referencia, diagramas y prácticas recomendadas sobre Google Cloud. Consulta nuestro Cloud Architecture Center.