Desplegar un clúster de MySQL con reconocimiento del estado en GKE


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

Sigue este tutorial para aprender a desplegar un clúster InnoDB de MySQL y un conjunto de clústeres InnoDB de MySQL, así como el middleware MySQL Router en tu clúster de GKE, y a realizar actualizaciones.

Objetivos

En este tutorial aprenderás a:

  • Crea y despliega un servicio de Kubernetes con estado.
  • Despliega un clúster InnoDB de MySQL para conseguir alta disponibilidad.
  • Implementa el middleware Router para enrutar las operaciones de la base de datos.
  • Despliega un InnoDB ClusterSet de MySQL para tolerar fallos.
  • Simula una conmutación por error de un clúster de MySQL.
  • Actualiza la versión de MySQL.

En las siguientes secciones se describe la arquitectura de la solución que crearás en este tutorial.

Clúster InnoDB de MySQL

En tu clúster regional de GKE, mediante un StatefulSet, implementas una instancia de base de datos MySQL con la nomenclatura y la configuración necesarias para crear un clúster InnoDB de MySQL. Para ofrecer tolerancia a fallos y alta disponibilidad, debes desplegar tres pods de instancias de base de datos. De esta forma, se asegura de que la mayoría de los pods de diferentes zonas estén disponibles en cualquier momento para que se pueda elegir un primario correctamente mediante un protocolo de consenso, y hace que tu clúster InnoDB de MySQL sea tolerante a los fallos de una sola zona.

Diagrama de arquitectura que muestra la relación entre las aplicaciones, MySQL Router y MySQL Cluster
Imagen 1: Arquitectura de ejemplo de un clúster InnoDB de MySQL

Una vez implementado, designa un pod como instancia principal para que gestione las operaciones de lectura y escritura. Los otros dos pods son réplicas secundarias de solo lectura. Si la instancia principal sufre un fallo en la infraestructura, puedes ascender uno de estos dos pods de réplica para que se convierta en el principal.

En un espacio de nombres independiente, despliega tres pods de MySQL Router para proporcionar enrutamiento de conexiones y mejorar la resiliencia. En lugar de conectarse directamente al servicio de base de datos, tus aplicaciones se conectan a pods de MySQL Router. Cada pod de Router conoce el estado y el propósito de cada pod de clúster InnoDB de MySQL y dirige las operaciones de la aplicación al pod correspondiente que esté en buen estado. El estado de enrutamiento se almacena en caché en los pods de Router y se actualiza a partir de los metadatos del clúster almacenados en cada nodo del clúster MySQL InnoDB. En caso de que falle una instancia de, el router ajusta el enrutamiento de la conexión a una instancia activa.

MySQL InnoDB ClusterSet

Puedes crear un conjunto de clústeres InnoDB de MySQL a partir de un clúster InnoDB de MySQL inicial. De esta forma, puedes aumentar la tolerancia a fallos si el clúster principal deja de estar disponible.

El diagrama muestra cómo se sincronizan los clústeres InnoDB de MySQL principal y de réplica mediante la replicación asíncrona.
Figura 2: Ejemplo de arquitectura de ClusterSet multirregional que contiene un clúster principal y un clúster de réplica

Si la instancia principal del clúster InnoDB de MySQL ya no está disponible, puedes ascender a principal un clúster de réplica del ClusterSet. Cuando se usa el middleware MySQL Router, tu aplicación no tiene que monitorizar el estado de la instancia de base de datos principal. El enrutamiento se ajusta para enviar las conexiones al nuevo primario una vez que se haya producido la elección. Sin embargo, es tu responsabilidad asegurarte de que las aplicaciones que se conecten a tu middleware MySQL Router sigan las prácticas recomendadas para la resiliencia, de forma que se reintenten las conexiones si se produce un error durante la conmutación por error del clúster.

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 GKE API.

    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 API

  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 GKE API.

    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 API

  8. Configurar roles

    1. Make sure that you have the following role or roles on the project: role/storage.objectViewer, role/logging.logWriter, role/artifactregistry.Admin, roles/container.clusterAdmin, role/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 tiene preinstalados Docker y las CLIs kubectl y gcloud.

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

      1. Define las variables de entorno.

        export PROJECT_ID=PROJECT_ID
        export CLUSTER_NAME=gkemulti-west
        export CONTROL_PLANE_LOCATION=CONTROL_PLANE_LOCATION
        

        Sustituye los siguientes valores:

        • PROJECT_ID: tu Google Cloud ID de proyecto.
        • CONTROL_PLANE_LOCATION: la región de Compute Engine del plano de control de tu clúster. En este tutorial, la región es us-west1. Normalmente, te interesa una región que esté cerca de ti.
      2. Define las variables de entorno predeterminadas.

         gcloud config set project PROJECT_ID
         gcloud config set compute/region CONTROL_PLANE_LOCATION
        
      3. Clona el repositorio de código.

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

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

        Crear un clúster de GKE

        En esta sección, crearás un clúster de GKE regional. A diferencia de los clústeres zonales, el plano de control de los clústeres regionales se replica en varias zonas, por lo que una interrupción en una sola zona no provoca que el plano de control deje de estar disponible.

        Para crear un clúster de GKE, sigue estos pasos:

        Autopilot

        1. En Cloud Shell, crea un clúster de Autopilot de GKE en la región us-west1.

          gcloud container clusters create-auto $CLUSTER_NAME \
              --location=$CONTROL_PLANE_LOCATION
          
        2. Obtén las credenciales del clúster de GKE.

          gcloud container clusters get-credentials $CLUSTER_NAME \
            --location=$CONTROL_PLANE_LOCATION
          
        3. Despliega un servicio en tres zonas. En este tutorial se usa un Deployment de Kubernetes. Un Deployment es un objeto de la API de Kubernetes que te permite ejecutar varias réplicas de pods distribuidas entre los nodos de un clúster.

          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: prepare-three-zone-ha
            labels:
              app: prepare-three-zone-ha
          spec:
            replicas: 3
            selector:
              matchLabels:
                app: prepare-three-zone-ha
            template:
              metadata:
                labels:
                  app: prepare-three-zone-ha
              spec:
                affinity:
                  # Tell Kubernetes to avoid scheduling a replica in a zone where there
                  # is already a replica with the label "app: prepare-three-zone-ha"
                  podAntiAffinity:
                    requiredDuringSchedulingIgnoredDuringExecution:
                    - labelSelector:
                        matchExpressions:
                        - key: app
                          operator: In
                          values:
                          - prepare-three-zone-ha
                      topologyKey: "topology.kubernetes.io/zone"
                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"
          kubectl apply -f prepare-for-ha.yaml
          

          De forma predeterminada, Autopilot aprovisiona recursos en dos zonas. El Deployment definido en prepare-for-ha.yaml asegura que Autopilot aprovisione nodos en tres zonas de tu clúster. Para ello, se definen replicas:3 y podAntiAffinity con requiredDuringSchedulingIgnoredDuringExecution y topologyKey: "topology.kubernetes.io/zone".

        4. Comprueba el estado del despliegue.

          kubectl get deployment prepare-three-zone-ha --watch
          

          Cuando veas tres pods en estado listo, cancela este comando con CTRL+C. El resultado debería ser similar al siguiente:

          NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
          prepare-three-zone-ha   0/3     3            0           9s
          prepare-three-zone-ha   1/3     3            1           116s
          prepare-three-zone-ha   2/3     3            2           119s
          prepare-three-zone-ha   3/3     3            3           2m16s
          
        5. Ejecuta esta secuencia de comandos para validar que tus pods se han desplegado en tres zonas.

          bash ../scripts/inspect_pod_node.sh default
          

          Cada línea del resultado corresponde a un pod y la segunda columna indica la zona. El resultado debería ser similar al siguiente:

          gk3-gkemulti-west1-default-pool-eb354e2d-z6mv us-west1-b prepare-three-zone-ha-7885d77d9c-8f7qb
          gk3-gkemulti-west1-nap-25b73chq-739a9d40-4csr us-west1-c prepare-three-zone-ha-7885d77d9c-98fpn
          gk3-gkemulti-west1-default-pool-160c3578-bmm2 us-west1-a prepare-three-zone-ha-7885d77d9c-phmhj
          

        Estándar

        1. En Cloud Shell, crea un clúster estándar de GKE en la región us-west1.

          gcloud container clusters create $CLUSTER_NAME \
            --location=$CONTROL_PLANE_LOCATION \
            --machine-type="e2-standard-2" \
            --disk-type="pd-standard" \
            --num-nodes="5"
          
        2. Obtén las credenciales del clúster de GKE.

          gcloud container clusters get-credentials $CLUSTER_NAME \
            --location=$CONTROL_PLANE_LOCATION
          

        Desplegar StatefulSets de MySQL

        En esta sección, desplegarás un StatefulSet de MySQL. Un StatefulSet es un controlador de Kubernetes que mantiene una identidad única y persistente para cada uno de sus pods.

        Cada StatefulSet consta de tres réplicas de MySQL.

        Para implementar el StatefulSet de MySQL, sigue estos pasos:

        1. Crea un espacio de nombres para el StatefulSet.

          kubectl create namespace mysql1
          
        2. Crea el secreto de MySQL.

          apiVersion: v1
          kind: Secret
          metadata:
            name: mysql-secret
          type: Opaque
          data:
            password: UGFzc3dvcmQkMTIzNDU2 # Password$123456
            admin-password: UGFzc3dvcmQkMTIzNDU2 # Password$123456
          kubectl apply -n mysql1 -f secret.yaml
          

          La contraseña se implementa con cada pod y la usan los comandos y las secuencias de comandos de gestión para la implementación de clústeres y ClusterSet de MySQL InnoDB en este tutorial.

        3. Crea el objeto StorageClass.

          apiVersion: storage.k8s.io/v1
          kind: StorageClass
          metadata:
            name: fast-storageclass
          provisioner: pd.csi.storage.gke.io
          volumeBindingMode: WaitForFirstConsumer
          reclaimPolicy: Retain
          allowVolumeExpansion: true
          parameters:
            type: pd-balanced
          kubectl apply -n mysql1 -f storageclass.yaml
          

          Esta clase de almacenamiento usa el tipo de disco persistente pd-balanced, que equilibra el rendimiento y el coste. El campo volumeBindingMode se define como WaitForFirstConsumer, lo que significa que GKE retrasa el aprovisionamiento de un PersistentVolume hasta que se crea el pod. Este ajuste asegura que el disco se aprovisione en la misma zona en la que se ha programado el pod.

        4. Despliega el StatefulSet de los pods de la instancia de MySQL.

          apiVersion: apps/v1
          kind: StatefulSet
          metadata:
            name: dbc1
            labels:
              app: mysql
          spec:
            replicas: 3
            selector:
              matchLabels:
                app: mysql
            serviceName: mysql
            template:
              metadata:
                labels:
                  app: mysql
              spec:
                topologySpreadConstraints:
                - maxSkew: 1
                  topologyKey: "topology.kubernetes.io/zone"
                  whenUnsatisfiable: DoNotSchedule
                  labelSelector:
                    matchLabels:
                      app: mysql
                affinity:
                  podAntiAffinity:
                    requiredDuringSchedulingIgnoredDuringExecution:
                    - labelSelector:
                        matchExpressions:
                        - key: app
                          operator: In
                          values:
                          - mysql
                      topologyKey: "kubernetes.io/hostname"
                containers:
                - name: mysql
                  image: mysql/mysql-server:8.0.28
                  command:
                  - /bin/bash
                  args:
                  - -c
                  - >-
                    /entrypoint.sh
                    --server-id=$((20 +  $(echo $HOSTNAME | grep -o '[^-]*$') + 1))
                    --report-host=${HOSTNAME}.mysql.mysql1.svc.cluster.local
                    --binlog-checksum=NONE
                    --enforce-gtid-consistency=ON
                    --gtid-mode=ON
                    --default-authentication-plugin=mysql_native_password
                  env:
                  - name: MYSQL_ROOT_PASSWORD
                    valueFrom:
                      secretKeyRef:
                        name: mysql-secret
                        key: password
                  - name: MYSQL_ADMIN_PASSWORD
                    valueFrom:
                      secretKeyRef:
                        name: mysql-secret
                        key: admin-password
                  - name: MYSQL_ROOT_HOST
                    value: '%'
                  ports:
                  - name: mysql
                    containerPort: 3306
                  - name: mysqlx
                    containerPort: 33060
                  - name: xcom
                    containerPort: 33061
                  resources:
                    limits:
                      cpu: "500m"
                      ephemeral-storage: "1Gi"
                      memory: "1Gi"
                    requests:
                      cpu: "500m"
                      ephemeral-storage: "1Gi"
                      memory: "1Gi"
                  volumeMounts:
                  - name: mysql
                    mountPath: /var/lib/mysql
                    subPath: mysql
                  readinessProbe:
                    exec:
                      command:
                      - bash
                      - "-c"
                      - |
                        mysql -h127.0.0.1 -uroot -p$MYSQL_ROOT_PASSWORD -e'SELECT 1'
                    initialDelaySeconds: 30
                    periodSeconds: 2
                    timeoutSeconds: 1
                  livenessProbe:
                    exec:
                      command:
                      - bash
                      - "-c"
                      - |
                        mysqladmin -uroot -p$MYSQL_ROOT_PASSWORD ping
                    initialDelaySeconds: 30
                    periodSeconds: 10
                    timeoutSeconds: 5
            updateStrategy:
              rollingUpdate:
                partition: 0
              type: RollingUpdate
            volumeClaimTemplates:
            - metadata:
                name: mysql
                labels:
                  app: mysql
              spec:
                storageClassName: fast-storageclass
                volumeMode: Filesystem
                accessModes:
                - ReadWriteOnce
                resources:
                  requests:
                    storage: 10Gi
          kubectl apply -n mysql1 -f c1-mysql.yaml
          

          Este comando implementa el StatefulSet que consta de tres réplicas. En este tutorial, el clúster de MySQL principal se despliega en tres zonas de us-west1. El resultado debería ser similar al siguiente:

          service/mysql created
          statefulset.apps/dbc1 created
          

          En este tutorial, los límites y las solicitudes de recursos se han definido con valores mínimos para ahorrar costes. Cuando planifiques una carga de trabajo de producción, asegúrate de definir estos valores de forma adecuada para las necesidades de tu organización.

        5. Verifica que el StatefulSet se ha creado correctamente.

          kubectl get statefulset -n mysql1 --watch
          

          El StatefulSet puede tardar unos 10 minutos en estar listo.

        6. Cuando los tres pods estén en estado Ready, sal del comando con Ctrl+C. Si aparecen errores PodUnscheduleable debido a que no hay suficiente CPU o memoria, espera unos minutos a que el plano de control cambie de tamaño para adaptarse a la carga de trabajo grande.

          El resultado debería ser similar al siguiente:

          NAME   READY   AGE
          dbc1   1/3     39s
          dbc1   2/3     50s
          dbc1   3/3     73s
          
        7. Para inspeccionar la colocación de tus pods en los nodos del clúster de GKE, ejecuta esta secuencia de comandos:

          bash ../scripts/inspect_pod_node.sh mysql1 mysql
          

          El resultado muestra el nombre del pod, el nombre del nodo de GKE y la zona en la que se aprovisiona el nodo. Es similar al siguiente:

          gke-gkemulti-west-5-default-pool-4bcaca65-jch0 us-west1-b dbc1-0
          gke-gkemulti-west-5-default-pool-1ac6e8b5-ddjx us-west1-c dbc1-1
          gke-gkemulti-west-5-default-pool-1f5baa66-bf8t us-west1-a dbc1-2
          

          Las columnas de la salida representan el nombre de host, la zona de nube y el nombre del pod, respectivamente.

          La política topologySpreadConstraints de la especificación de StatefulSet (c1-mysql.yaml) indica al programador que coloque los pods de forma uniforme en el dominio de errores (topology.kubernetes.io/zone).

          La política podAntiAffinity aplica la restricción de que los pods no se coloquen en el mismo nodo de clúster de GKE (kubernetes.io/hostname). En el caso de los pods de la instancia de MySQL, esta política hace que los pods se implementen de forma uniforme en las tres zonas de la región Google Cloud . Esta colocación permite la alta disponibilidad del clúster InnoDB de MySQL colocando cada instancia de base de datos en un dominio de errores independiente.

        Preparar el clúster InnoDB de MySQL principal

        Para configurar un clúster InnoDB de MySQL, sigue estos pasos:

        1. En la terminal Cloud Shell, define las configuraciones de replicación de grupos de las instancias de MySQL que se añadirán al clúster.

          bash ../scripts/c1-clustersetup.sh
          
          POD_ORDINAL_START=${1:-0}
          POD_ORDINAL_END=${2:-2}
          for i in $(seq ${POD_ORDINAL_START} ${POD_ORDINAL_END}); do
            echo "Configuring pod mysql1/dbc1-${i}"
            cat <<'  EOF' | kubectl -n mysql1 exec -i dbc1-${i} -- bash -c 'mysql -uroot -proot --password=${MYSQL_ROOT_PASSWORD}'
          INSTALL PLUGIN group_replication SONAME 'group_replication.so';
          RESET PERSIST IF EXISTS group_replication_ip_allowlist;
          RESET PERSIST IF EXISTS binlog_transaction_dependency_tracking;
          SET @@PERSIST.group_replication_ip_allowlist = 'mysql.mysql1.svc.cluster.local';
          SET @@PERSIST.binlog_transaction_dependency_tracking = 'WRITESET';
            EOF
          done

          El script se conectará de forma remota a cada una de las tres instancias de MySQL para definir y conservar las siguientes variables de entorno:

          • group_replication_ip_allowlist: permite que la instancia del clúster se conecte a cualquier instancia del grupo.
          • binlog_transaction_dependency_tracking='WRITESET': permite transacciones paralelas que no entran en conflicto.

          En las versiones de MySQL anteriores a la 8.0.22, usa group_replication_ip_whitelist en lugar de group_replication_ip_allowlist.

        2. Abre una segunda terminal para no tener que crear un shell para cada pod.

        3. Conéctate a MySQL Shell en el pod dbc1-0.

          kubectl -n mysql1 exec -it dbc1-0 -- \
              /bin/bash \
              -c 'mysqlsh --uri="root:$MYSQL_ROOT_PASSWORD@dbc1-0.mysql.mysql1.svc.cluster.local"'
          
        4. Verifica la lista de permitidos de la replicación de grupo de MySQL para conectarte a otras instancias.

          \sql SELECT @@group_replication_ip_allowlist;
          

          El resultado debería ser similar al siguiente:

          +----------------------------------+
          | @@group_replication_ip_allowlist |
          +----------------------------------+
          | mysql.mysql1.svc.cluster.local   |
          +----------------------------------+
          
        5. Verifica que el server-id sea único en cada una de las instancias.

          \sql SELECT @@server_id;
          

          El resultado debería ser similar al siguiente:

          +-------------+
          | @@server_id |
          +-------------+
          |          21 |
          +-------------+
          
        6. Configura cada instancia para usar el clúster InnoDB de MySQL y crea una cuenta de administrador en cada instancia.

          \js
          dba.configureInstance('root@dbc1-0.mysql.mysql1.svc.cluster.local', {password: os.getenv("MYSQL_ROOT_PASSWORD"),clusterAdmin: 'icadmin', clusterAdminPassword: os.getenv("MYSQL_ADMIN_PASSWORD")});
          dba.configureInstance('root@dbc1-1.mysql.mysql1.svc.cluster.local', {password: os.getenv("MYSQL_ROOT_PASSWORD"),clusterAdmin: 'icadmin', clusterAdminPassword: os.getenv("MYSQL_ADMIN_PASSWORD")});
          dba.configureInstance('root@dbc1-2.mysql.mysql1.svc.cluster.local', {password: os.getenv("MYSQL_ROOT_PASSWORD"),clusterAdmin: 'icadmin', clusterAdminPassword: os.getenv("MYSQL_ADMIN_PASSWORD")});
          

          Todas las instancias deben tener el mismo nombre de usuario y la misma contraseña para que el clúster InnoDB de MySQL funcione correctamente. Cada comando genera un resultado similar al siguiente:

          ...
          
          The instance 'dbc1-2.mysql:3306' is valid to be used in an InnoDB cluster.
          
          Cluster admin user 'icadmin'@'%' created.
          The instance 'dbc1-2.mysql.mysql1.svc.cluster.local:3306' is already
          ready to be used in an InnoDB cluster.
          
          Successfully enabled parallel appliers.
          
        7. Verifica que la instancia esté lista para usarse en un clúster InnoDB de MySQL.

          dba.checkInstanceConfiguration()
          

          El resultado debería ser similar al siguiente:

          ...
          
          The instance 'dbc1-0.mysql.mysql1.svc.cluster.local:3306' is valid to be used in an InnoDB cluster.
          
          {
              "status": "ok"
          }
          

          También puedes conectarte a cada instancia de MySQL y repetir este comando. Por ejemplo, ejecuta este comando para comprobar el estado de la instancia dbc1-1:

          kubectl -n mysql1 exec -it dbc1-0 -- \
              /bin/bash \
              -c 'mysqlsh --uri="root:$MYSQL_ROOT_PASSWORD@dbc1-1.mysql.mysql1.svc.cluster.local" \
              --js --execute "dba.checkInstanceConfiguration()"'
          

        Crear el clúster InnoDB de MySQL principal

        A continuación, crea el clúster InnoDB de MySQL con el comando MySQL Admin createCluster. Empieza con la instancia dbc1-0, que será la instancia principal del clúster, y, a continuación, añade dos réplicas más al clúster.

        Para inicializar el clúster InnoDB de MySQL, sigue estos pasos:

        1. Crea el clúster InnoDB de MySQL.

          var cluster=dba.createCluster('mycluster');
          

          Al ejecutar el comando createCluster, se activan estas operaciones:

          • Implementa el esquema de metadatos.
          • Verifica que la configuración sea correcta para la replicación de grupo.
          • Regístrala como instancia inicial del nuevo clúster.
          • Crea las cuentas internas necesarias, como la cuenta de usuario de replicación.
          • Inicia la replicación de grupo.

          Este comando inicializa un clúster InnoDB de MySQL con el host dbc1-0 como principal. La referencia del clúster se almacena en la variable del clúster.

          El resultado es similar al siguiente:

          A new InnoDB cluster will be created on instance 'dbc1-0.mysql:3306'.
          
          Validating instance configuration at dbc1-0.mysql:3306...
          
          This instance reports its own address as dbc1-0.mysql.mysql1.svc.cluster.local:3306
          
          Instance configuration is suitable.
          NOTE: Group Replication will communicate with other instances using
          'dbc1-0.mysql:33061'. Use the localAddress
          option to override.
          
          Creating InnoDB cluster 'mycluster' on
          'dbc1-0.mysql.mysql1.svc.cluster.local:3306'...
          
          Adding Seed Instance...
          Cluster successfully created. Use Cluster.addInstance() to add MySQL
          instances.
          At least 3 instances are needed for the cluster to be able to withstand
          up to one server failure.
          
        2. Añade la segunda instancia al clúster.

          cluster.addInstance('icadmin@dbc1-1.mysql', {password: os.getenv("MYSQL_ROOT_PASSWORD"), recoveryMethod: 'clone'});
          
        3. Añade la instancia restante al clúster.

          cluster.addInstance('icadmin@dbc1-2.mysql', {password: os.getenv("MYSQL_ROOT_PASSWORD"), recoveryMethod: 'clone'});
          

          El resultado debería ser similar al siguiente:

          ...
          The instance 'dbc1-2.mysql:3306' was successfully added to the cluster.
          
        4. Verifica el estado del clúster.

          cluster.status()
          

          Este comando muestra el estado del clúster. La topología consta de tres hosts: una instancia principal y dos secundarias. También puedes llamar a cluster.status({extended:1}).

          El resultado debería ser similar al siguiente:

          {
              "clusterName": "mysql1",
              "defaultReplicaSet": {
                  "name": "default",
                  "primary": "dbc1-0.mysql:3306",
                  "ssl": "REQUIRED",
                  "status": "OK",
                  "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
                  "topology": {
                      "dbc1-0.mysql:3306": {
                          "address": "dbc1-0.mysql:3306",
                          "memberRole": "PRIMARY",
                          "mode": "R/W",
                          "readReplicas": {},
                          "replicationLag": null,
                          "role": "HA",
                          "status": "ONLINE",
                          "version": "8.0.28"
                      },
                      "dbc1-1.mysql:3306": {
                          "address": "dbc1-1.mysql:3306",
                          "memberRole": "SECONDARY",
                          "mode": "R/O",
                          "readReplicas": {},
                          "replicationLag": null,
                          "role": "HA",
                          "status": "ONLINE",
                          "version": "8.0.28"
                      },
                      "dbc1-2.mysql:3306": {
                          "address": "dbc1-2.mysql:3306",
                          "memberRole": "SECONDARY",
                          "mode": "R/O",
                          "readReplicas": {},
                          "replicationLag": null,
                          "role": "HA",
                          "status": "ONLINE",
                          "version": "8.0.28"
                      }
                  },
                  "topologyMode": "Single-Primary"
              },
              "groupInformationSourceMember": "dbc1-0.mysql:3306"
          }
          

          Si quieres, puedes llamar al cluster.status({extended:1}) para obtener más información sobre el estado.

        Crear una base de datos de muestra

        Para crear una base de datos de ejemplo, sigue estos pasos:

        1. Crea una base de datos y carga datos en ella.

          \sql
          create database loanapplication;
          use loanapplication
          CREATE TABLE loan (loan_id INT unsigned AUTO_INCREMENT PRIMARY KEY, firstname VARCHAR(30) NOT NULL, lastname VARCHAR(30) NOT NULL , status VARCHAR(30) );
          
        2. Inserta datos de muestra en la base de datos. Para insertar datos, debes conectarte a la instancia principal del clúster.

          INSERT INTO loan (firstname, lastname, status) VALUES ( 'Fred','Flintstone','pending');
          INSERT INTO loan (firstname, lastname, status) VALUES ( 'Betty','Rubble','approved');
          
        3. Verifica que la tabla contenga las tres filas insertadas en el paso anterior.

          SELECT * FROM loan;
          

          El resultado debería ser similar al siguiente:

          +---------+-----------+------------+----------+
          | loan_id | firstname | lastname   | status   |
          +---------+-----------+------------+----------+
          |       1 | Fred      | Flintstone | pending  |
          |       2 | Betty     | Rubble     | approved |
          +---------+-----------+------------+----------+
          2 rows in set (0.0010 sec)
          

        Crear un ClusterSet de InnoDB de MySQL

        Puedes crear un ClusterSet de MySQL InnoDB para gestionar la replicación desde tu clúster principal a los clústeres de réplica mediante un canal de replicación de ClusterSet específico.

        Un conjunto de clústeres InnoDB de MySQL proporciona tolerancia a desastres para las implementaciones de clústeres InnoDB de MySQL. Para ello, vincula un clúster InnoDB de MySQL principal con una o varias réplicas de sí mismo en ubicaciones alternativas, como varias zonas y varias regiones.

        Si has cerrado MySQL Shell, crea uno nuevo ejecutando este comando en un nuevo terminal de Cloud Shell:

          kubectl -n mysql1 exec -it dbc1-0 -- \
              /bin/bash -c 'mysqlsh \
              --uri="root:$MYSQL_ROOT_PASSWORD@dbc1-0.mysql.mysql1.svc.cluster.local"'
        

        Para crear un conjunto de clústeres InnoDB de MySQL, siga estos pasos:

        1. En el terminal de MySQL Shell, obtén un objeto de clúster.

          \js
          cluster=dba.getCluster()
          

          El resultado debería ser similar al siguiente:

          <Cluster:mycluster>
          
        2. Inicializa un ClusterSet de MySQL InnoDB con el clúster de MySQL InnoDB almacenado en el objeto de clúster como principal.

          clusterset=cluster.createClusterSet('clusterset')
          

          El resultado debería ser similar al siguiente:

          A new ClusterSet will be created based on the Cluster 'mycluster'.
          
          * Validating Cluster 'mycluster' for ClusterSet compliance.
          
          * Creating InnoDB ClusterSet 'clusterset' on 'mycluster'...
          
          * Updating metadata...
          
          ClusterSet successfully created. Use ClusterSet.createReplicaCluster() to add Replica Clusters to it.
          
          <ClusterSet:clusterset>
          
        3. Consulta el estado de tu conjunto de clústeres InnoDB de MySQL.

          clusterset.status()
          

          El resultado debería ser similar al siguiente:

          {
              "clusters": {
                  "mycluster": {
                      "clusterRole": "PRIMARY",
                      "globalStatus": "OK",
                      "primary": "dbc1-0.mysql:3306"
                  }
              },
              "domainName": "clusterset",
              "globalPrimaryInstance": "dbc1-0.mysql:3306",
              "primaryCluster": "mycluster",
              "status": "HEALTHY",
              "statusText": "All Clusters available."
          }
          

          Si quieres, puedes llamar a clusterset.status({extended:1}) para obtener más detalles sobre el estado, incluida información sobre el clúster.

        4. Sal de MySQL Shell.

          \q
          

        Desplegar un enrutador MySQL

        Puedes desplegar un router MySQL para dirigir el tráfico de la aplicación cliente a los clústeres adecuados. El enrutamiento se basa en el puerto de conexión de la aplicación que emite una operación de base de datos:

        • Las escrituras se dirigen a la instancia de clúster principal del ClusterSet principal.
        • Las lecturas se pueden dirigir a cualquier instancia del clúster principal.

        Cuando inicias un MySQL Router, se inicia en la implementación de MySQL InnoDB ClusterSet. Las instancias de MySQL Router conectadas con el conjunto de clústeres InnoDB de MySQL detectan cualquier cambio controlado o conmutación por error de emergencia y dirigen el tráfico al nuevo clúster principal.

        Para implementar un MySQL Router, sigue estos pasos:

        1. En el terminal de Cloud Shell, implementa MySQL Router.

          kubectl apply -n mysql1 -f c1-router.yaml
          

          El resultado debería ser similar al siguiente:

          configmap/mysql-router-config created
          service/mysql-router created
          deployment.apps/mysql-router created
          
        2. Comprueba si el despliegue de MySQL Router está listo.

          kubectl -n mysql1 get deployment mysql-router --watch
          

          Cuando los tres pods estén listos, el resultado será similar al siguiente:

          NAME           READY   UP-TO-DATE   AVAILABLE   AGE
          mysql-router   3/3     3            0           3m36s
          

          Si ves un error PodUnschedulable en la consola, espera uno o dos minutos mientras GKE aprovisiona más nodos. Actualiza la página y deberías ver 3/3 OK.

        3. Inicia MySQL Shell en cualquier miembro del clúster.

          kubectl -n mysql1 exec -it dbc1-0 -- \
              /bin/bash -c 'mysqlsh --uri="root:$MYSQL_ROOT_PASSWORD@dbc1-0.mysql"'
          

          Este comando se conecta al pod dbc1-0 y, a continuación, inicia un shell conectado a la instancia de MySQL dbc1-0.

        4. Verifica la configuración del router.

          clusterset=dba.getClusterSet()
          clusterset.listRouters()
          

          El resultado debería ser similar al siguiente:

          {
            "domainName": "clusterset",
            "routers": {
              "mysql-router-7cd8585fbc-74pkm::": {
                  "hostname": "mysql-router-7cd8585fbc-74pkm",
                  "lastCheckIn": "2022-09-22 23:26:26",
                  "roPort": 6447,
                  "roXPort": 6449,
                  "rwPort": 6446,
                  "rwXPort": 6448,
                  "targetCluster": null,
                  "version": "8.0.27"
              },
              "mysql-router-7cd8585fbc-824d4::": {
                ...
              },
              "mysql-router-7cd8585fbc-v2qxz::": {
                ...
              }
            }
          }
          
        5. Sal de MySQL Shell.

          \q
          
        6. Ejecuta esta secuencia de comandos para inspeccionar la colocación de los pods de MySQL Router.

          bash ../scripts/inspect_pod_node.sh mysql1 | sort
          

          La secuencia de comandos muestra la colocación de nodos y zonas de Cloud de todos los pods del espacio de nombres mysql1, donde la salida es similar a la siguiente:

          gke-gkemulti-west-5-default-pool-1ac6e8b5-0h9v us-west1-c mysql-router-6654f985f5-df97q
          gke-gkemulti-west-5-default-pool-1ac6e8b5-ddjx us-west1-c dbc1-1
          gke-gkemulti-west-5-default-pool-1f5baa66-bf8t us-west1-a dbc1-2
          gke-gkemulti-west-5-default-pool-1f5baa66-kt03 us-west1-a mysql-router-6654f985f5-qlfj9
          gke-gkemulti-west-5-default-pool-4bcaca65-2l6s us-west1-b mysql-router-6654f985f5-5967d
          gke-gkemulti-west-5-default-pool-4bcaca65-jch0 us-west1-b dbc1-0
          

          Puedes observar que los pods de MySQL Router se distribuyen de forma equitativa entre las zonas, es decir, no se colocan en el mismo nodo que un pod de MySQL ni en el mismo nodo que otro pod de MySQL Router.

        Gestionar las actualizaciones de GKE y MySQL InnoDB Cluster

        Las actualizaciones de MySQL 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. Kubernetes y GKE también ofrecen funciones adicionales para facilitar las actualizaciones del software MySQL.

        Planificar las actualizaciones de GKE

        Puedes tomar medidas proactivas y definir configuraciones para reducir los riesgos y facilitar una actualización del clúster más fluida cuando ejecutes servicios con estado, como los siguientes:

        • Clústeres estándar: sigue las prácticas recomendadas de GKE para actualizar clústeres. Elige una estrategia de actualización adecuada para asegurarte de que las actualizaciones se realicen durante el periodo de la ventana de mantenimiento:

          • Elige actualizaciones de picos si la optimización de costes es importante y si tus cargas de trabajo pueden tolerar un cierre gradual en menos de 60 minutos.
          • Elige las actualizaciones azul-verde si tus cargas de trabajo toleran menos las interrupciones y puedes asumir un aumento temporal de los costes debido a un mayor uso de los recursos.

          Para obtener más información, consulta Actualizar un clúster en el que se ejecuta una carga de trabajo con reconocimiento del estado. Los clústeres de Autopilot se actualizan automáticamente en función del canal de lanzamiento que hayas seleccionado.

        • Usa las ventanas de mantenimiento para asegurarte de que las actualizaciones se realicen cuando quieras. Antes de la ventana de mantenimiento, asegúrate de que las copias de seguridad de tu base de datos se hayan creado correctamente.

        • Antes de permitir el tráfico a los nodos de MySQL actualizados, usa las sondas de disponibilidad y las sondas de actividad para asegurarte de que están listos para recibir tráfico.

        • Crea sondas que evalúen si la replicación está sincronizada antes de aceptar el tráfico. Esto se puede hacer mediante secuencias de comandos personalizadas, en función de la complejidad y la escala de tu base de datos.

        Definir una política de cobertura para interrupciones de pods (PDB)

        Cuando un clúster de MySQL InnoDB se ejecuta en GKE, debe haber un número suficiente de instancias en ejecución en cualquier momento para cumplir el requisito de quórum.

        En este tutorial, dado un clúster de MySQL de tres instancias, dos instancias deben estar disponibles para formar un quórum. Una política de PodDisruptionBudget te permite limitar el número de pods que se pueden finalizar en un momento dado. Esto es útil tanto para las operaciones de estado estable de tus servicios con estado como para las actualizaciones de clústeres.

        Para asegurarte de que solo se interrumpa un número limitado de pods simultáneamente, define el PDB de tu carga de trabajo en maxUnavailable: 1. De esta forma, se asegura de que, en cualquier momento de la operación del servicio, no haya más de un pod sin ejecutar.

        El siguiente manifiesto de la política PodDisruptionBudget define el número máximo de pods no disponibles en uno para tu aplicación MySQL.

        apiVersion: policy/v1
        kind: PodDisruptionBudget
        metadata:
          name: mysql-pdb
        spec:
          maxUnavailable: 1
          selector:
            matchLabels:
              app: mysql

        Para aplicar la política de PDB a tu clúster, sigue estos pasos:

        1. Aplica la política de PDB con kubectl.

          kubectl apply -n mysql1 -f mysql-pdb-maxunavailable.yaml
          
        2. Consulta el estado de la PDB.

          kubectl get poddisruptionbudgets -n mysql1 mysql-pdb -o yaml
          

          En la sección status del resultado, consulta los recuentos de currentHealthy y desiredHealthy Pods. El resultado debería ser similar al siguiente:

          status:
          ...
            currentHealthy: 3
            desiredHealthy: 2
            disruptionsAllowed: 1
            expectedPods: 3
          ...
          

        Planificar las actualizaciones binarias de MySQL

        Kubernetes y GKE ofrecen funciones para facilitar las actualizaciones del binario de MySQL. Sin embargo, debe realizar algunas operaciones para preparar las actualizaciones.

        Antes de empezar el proceso de actualización, ten en cuenta lo siguiente:

        • Las actualizaciones deben realizarse primero en un entorno de prueba. En el caso de los sistemas de producción, debes realizar más pruebas en un entorno de preproducción.
        • En algunas versiones binarias, no puedes cambiar a una versión anterior una vez que se haya realizado una actualización. Dedica tiempo a comprender las implicaciones de una actualización.
        • Las fuentes de replicación pueden replicarse en una versión más reciente. Sin embargo, normalmente no se admite la copia de una versión más reciente a una anterior.
        • Asegúrate de tener una copia de seguridad completa de la base de datos antes de implementar la versión actualizada.
        • Ten en cuenta la naturaleza efímera de los pods de Kubernetes. Cualquier estado de configuración que almacene el pod y que no esté en el volumen persistente se perderá cuando se vuelva a implementar el pod.
        • Para las actualizaciones binarias de MySQL, usa la misma PDB, estrategia de actualización del grupo de nodos y sondas que se han descrito anteriormente.

        En un entorno de producción, debe seguir estas prácticas recomendadas:

        • Crea una imagen de contenedor con la nueva versión de MySQL.
        • Conserva las instrucciones de compilación de la imagen en un repositorio de control de versiones.
        • Usa una canalización automatizada de compilación y pruebas de imágenes, como Cloud Build, y almacena el archivo binario de la imagen en un registro de imágenes, como Artifact Registry.

        Para que este tutorial sea sencillo, no crearás ni conservarás una imagen de contenedor, sino que usarás las imágenes públicas de MySQL.

        Desplegar el archivo binario de MySQL actualizado

        Para llevar a cabo la actualización binaria de MySQL, debes ejecutar un comando declarativo que modifique la versión de la imagen del recurso StatefulSet. GKE lleva a cabo los pasos necesarios para detener el pod actual, implementar un nuevo pod con el binario actualizado y adjuntar el disco persistente al nuevo pod.

        1. Verifica que se haya creado la PDB.

          kubectl get poddisruptionbudgets -n mysql1
          
        2. Obtén la lista de conjuntos con reconocimiento del estado.

          kubectl get statefulsets -n mysql1
          
        3. Obtén la lista de pods en ejecución con la etiqueta app.

          kubectl get pods --selector=app=mysql -n mysql1
          
        4. Actualiza la imagen de MySQL en el conjunto con estado.

          kubectl  -n mysql1 \
              set image statefulset/dbc1 \
              mysql=mysql/mysql-server:8.0.30
          

          El resultado debería ser similar al siguiente:

          statefulset.apps/mysql image updated
          
        5. Comprueba el estado de los pods que se están terminando y de los nuevos.

          kubectl get pods --selector=app=mysql -n mysql1
          

        Validar la actualización binaria de MySQL

        Durante la actualización, puedes verificar el estado del lanzamiento, los nuevos pods y el servicio actual.

        1. Confirma la actualización ejecutando el comando rollout status.

          kubectl rollout status statefulset/dbc1 -n mysql1
          

          El resultado debería ser similar al siguiente:

          partitioned roll out complete: 3 new pods have been updated...
          
        2. Confirma la versión de la imagen inspeccionando el conjunto con estado.

          kubectl get statefulsets -o wide -n mysql1
          

          El resultado debería ser similar al siguiente:

          NAME   READY   AGE   CONTAINERS   IMAGES
          dbc1   3/3     37m   mysql        mysql/mysql-server:8.0.30
          
        3. Comprueba el estado del clúster.

          kubectl -n mysql1 \
               exec -it dbc1-0 -- \
                 /bin/bash \
                   -c 'mysqlsh \
                   --uri="root:$MYSQL_ROOT_PASSWORD@dbc1-1.mysql.mysql1.svc.cluster.local" \
                   --js \
                   --execute "print(dba.getClusterSet().status({extended:1})); print(\"\\n\")"'
          

          En cada instancia del clúster, busque los valores de estado y versión en el resultado. El resultado debería ser similar al siguiente:

          ...
            "status": "ONLINE",
            "version": "8.0.30"
          ...
          

        Restaurar la última versión de la aplicación

        Cuando reviertes la implementación de una versión binaria actualizada, el proceso de lanzamiento se invierte y se implementa un nuevo conjunto de pods con la versión de imagen anterior.

        Para revertir la implementación a la versión anterior que funcionaba, usa el comando rollout undo

        kubectl rollout undo statefulset/dbc1 -n mysql1
        

        El resultado debería ser similar al siguiente:

        statefulset.apps/dbc1 rolled back
        

        Escalar horizontalmente un clúster de base de datos

        Para escalar horizontalmente tu clúster InnoDB de MySQL, añade nodos al pool de nodos del clúster de GKE (solo es necesario si usas el modo Estándar), implementa instancias de MySQL adicionales y, a continuación, añade cada instancia al clúster InnoDB de MySQL.

        Añadir nodos a un clúster Standard

        Esta operación no es necesaria si utilizas un clúster de Autopilot.

        Para añadir nodos a tu clúster estándar, sigue las instrucciones que se indican a continuación para Cloud Shell o la consola de Google Cloud . Para ver los pasos detallados, consulta Cambiar el tamaño de un pool de nodos.

        gcloud

        En Cloud Shell, cambia el tamaño del grupo de nodos predeterminado a ocho instancias en cada grupo de instancias administrado.

        gcloud container clusters resize ${CLUSTER_NAME} \
             --node-pool default-pool \
             --num-nodes=8
        

        Consola

        Para añadir nodos a tu clúster estándar, sigue estos pasos:

        1. Abre la gkemulti-west1página Clústeres Google Cloud en la consola.
        2. Selecciona Nodos y haz clic en grupo predeterminado.
        3. Desplázate hacia abajo hasta Grupos de instancias.
        4. En cada grupo de instancias, cambia el valor de Number of nodes de 5 a 8 nodos.

        Añadir pods de MySQL al clúster principal

        Para implementar pods de MySQL adicionales y escalar tu clúster horizontalmente, sigue estos pasos:

        1. En Cloud Shell, actualiza el número de réplicas de la implementación de MySQL de tres a cinco.

          kubectl scale  -n mysql1 --replicas=5 -f c1-mysql.yaml
          
        2. Verifica el progreso de la implementación.

          kubectl -n mysql1 get pods --selector=app=mysql -o wide
          

          Para determinar si los pods están listos, usa la marca --watch para monitorizar la implementación. Si utilizas clústeres de Autopilot y ves errores Pod Unschedulable, puede que GKE esté aprovisionando nodos para dar cabida a los pods adicionales.

        3. Configura los ajustes de replicación de grupo de las nuevas instancias de MySQL que quieras añadir al clúster.

          bash ../scripts/c1-clustersetup.sh 3 4
          

          La secuencia de comandos envía los comandos a las instancias que se ejecutan en los pods con ordinales del 3 al 4.

        4. Abre MySQL Shell.

          kubectl -n mysql1 \
            exec -it dbc1-0 -- \
                /bin/bash \
                  -c 'mysqlsh \
                  --uri="root:$MYSQL_ROOT_PASSWORD@dbc1-0.mysql"'
          
        5. Configura las dos nuevas instancias de MySQL.

          dba.configureInstance('root:$MYSQL_ROOT_PASSWORD@dbc1-3.mysql', {password: os.getenv("MYSQL_ROOT_PASSWORD"),clusterAdmin: 'icadmin', clusterAdminPassword: os.getenv("MYSQL_ADMIN_PASSWORD")});
          dba.configureInstance('root:$MYSQL_ROOT_PASSWORD@dbc1-4.mysql', {password: os.getenv("MYSQL_ROOT_PASSWORD"),clusterAdmin: 'icadmin', clusterAdminPassword: os.getenv("MYSQL_ADMIN_PASSWORD")});
          

          Los comandos comprueban si la instancia está configurada correctamente para usar el clúster InnoDB de MySQL y realizan los cambios de configuración necesarios.

        6. Añade una de las nuevas instancias al clúster principal.

          cluster = dba.getCluster()
          cluster.addInstance('icadmin@dbc1-3.mysql', {password: os.getenv("MYSQL_ROOT_PASSWORD"), recoveryMethod: 'clone'});
          
        7. Añade una segunda instancia nueva al clúster principal.

          cluster.addInstance('icadmin@dbc1-4.mysql', {password: os.getenv("MYSQL_ROOT_PASSWORD"), recoveryMethod: 'clone'});
          
        8. Obtiene el estado de ClusterSet, que también incluye el estado de Cluster.

          clusterset = dba.getClusterSet()
          clusterset.status({extended: 1})
          

          El resultado debería ser similar al siguiente:

          "domainName": "clusterset",
          "globalPrimaryInstance": "dbc1-0.mysql:3306",
          "metadataServer": "dbc1-0.mysql:3306",
          "primaryCluster": "mycluster",
          "status": "HEALTHY",
          "statusText": "All Clusters available."
          
        9. Sal de MySQL Shell.

          \q
          

        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.

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

        Go to Manage resources

      6. In the project list, select the project that you want to delete, and then click Delete.
      7. In the dialog, type the project ID, and then click Shut down to delete the project.
      8. Siguientes pasos