Migra tus datos de MySQL de Persistent Disk a Hyperdisk en GKE

En este instructivo, se muestra cómo migrar tus datos existentes de MySQL de un disco persistente (PD) a Hyperdisk en Google Kubernetes Engine para mejorar el rendimiento del almacenamiento. Hyperdisk ofrece más IOPS y capacidad de procesamiento que Persistent Disk, lo que puede mejorar el rendimiento de MySQL al reducir la latencia de las consultas y transacciones de la base de datos. Puedes usar instantáneas de disco para migrar tus datos a diferentes tipos de discos según la compatibilidad del tipo de máquina. Por ejemplo, los volúmenes de Hyperdisk solo son compatibles con algunos tipos de máquinas de tercera, cuarta y generaciones posteriores, como N4, que no admiten discos persistentes. Para obtener más información, consulta las series de máquinas disponibles.

Para demostrar la migración de Persistent Disk a Hyperdisk, en este instructivo, se usa la base de datos Sakila para proporcionar un conjunto de datos de muestra. Sakila es una base de datos de muestra proporcionada por MySQL que puedes usar como esquema para instructivos y ejemplos. Representa una tienda de alquiler de DVD ficticia y contiene tablas para películas, actores, clientes y alquileres.

Esta guía está dirigida a los especialistas y administradores de almacenamiento que crean y asignan almacenamiento, y administran la seguridad y el acceso a los datos. Para obtener más información sobre los roles comunes y las tareas de ejemplo a las que hacemos referencia en el contenido de Google Cloud , consulta Roles de usuario y tareas comunes de GKE.

Arquitectura de implementación

En el siguiente diagrama, se ilustra el proceso de migración de un Persistent Disk a un Hyperdisk.

  • Una aplicación de MySQL se ejecuta en un grupo de nodos de GKE con tipos de máquinas N2 y almacena sus datos en un SSD de disco persistente.
  • Para garantizar la coherencia de los datos, la aplicación se reduce para evitar nuevas escrituras.
  • Se crea una instantánea del Persistent Disk, que sirve como copia de seguridad completa de los datos en un momento determinado.
  • Se aprovisiona un nuevo Hyperdisk a partir de la instantánea y se implementa una nueva instancia de MySQL en un grupo de nodos N4 independiente y compatible con Hyperdisk. Esta nueva instancia se conecta al Hyperdisk recién creado, lo que finaliza la migración al almacenamiento de mayor rendimiento.
Diagrama de arquitectura que muestra la migración de datos de MySQL de Persistent Disk a Hyperdisk con una instantánea.
Figura 1: Migración de datos de MySQL de Persistent Disk a Hyperdisk con una instantánea.

Objetivos

En este instructivo, aprenderás a realizar las siguientes tareas:

  • Implementa un clúster de MySQL.
  • Sube un conjunto de datos de prueba.
  • Crea una instantánea de tus datos.
  • Crea un Hyperdisk a partir de la instantánea.
  • Inicia un nuevo clúster de MySQL en un grupo de nodos con tipo de máquina N4 habilitado para Hyperdisk.
  • Verifica la integridad de los datos para confirmar que la migración se realizó correctamente.

Costos

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

  • GKE
  • Compute Engine, which includes:
    • Storage capacity provisioned for both Persistent Disk and Hyperdisk.
    • Storage costs for the snapshots.

Para generar 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.

Antes de comenzar

  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, select or create 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 (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 Compute Engine, GKE, Identity and Access Management Service Account Credentials 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, select or create 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 (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 Compute Engine, GKE, Identity and Access Management Service Account Credentials 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. Make sure that you have the following role or roles on the project: roles/container.admin, roles/iam.serviceAccountAdmin, roles/compute.admin

    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 Otorgar acceso.
    4. En el campo Principales nuevas, ingresa tu identificador de usuario. Esta suele ser la dirección de correo electrónico de una Cuenta de Google.

    5. En la lista Seleccionar un rol, elige uno.
    6. Para otorgar roles adicionales, haz clic en Agregar otro rol y agrega uno más.
    7. Haz clic en Guardar.
    8. Configura Cloud Shell

      1. In the Google Cloud console, activate Cloud Shell.

        Activate Cloud Shell

        Se inicia una sesión de Cloud Shell y se muestra una ventana de línea de comandos. La sesión puede tardar unos segundos en inicializarse.

      2. Configura el proyecto predeterminado:

          gcloud config set project PROJECT_ID
        

        Reemplaza PROJECT_ID con el ID del proyecto.

      3. Prepare el entorno

        1. En Cloud Shell, configura las variables de entorno para tu proyecto, ubicación y prefijo del clúster.

          export PROJECT_ID=PROJECT_ID
          export EMAIL_ADDRESS=EMAIL_ADDRESS
          export KUBERNETES_CLUSTER_PREFIX=offline-hyperdisk-migration
          export LOCATION=us-central1-a
          

          Reemplaza lo siguiente:

          • PROJECT_ID: El Google Cloud ID del proyecto.
          • EMAIL_ADDRESS: el dirección de correo electrónico
          • LOCATION: Es la zona en la que deseas crear los recursos de implementación. Para los fines de este instructivo, usa la zona us-central1-a.
        2. Clona el repositorio de código de muestra de GitHub:

          git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
          
        3. Navega al directorio offline-hyperdisk-migration para comenzar a crear recursos de implementación:

          cd kubernetes-engine-samples/databases/offline-hyperdisk-migration
          

        Crea el clúster de GKE y los grupos de nodos

        En este instructivo, se usa un clúster zonal para simplificar el proceso, ya que los volúmenes de Hyperdisk son recursos zonales y solo se puede acceder a ellos dentro de una sola zona.

        1. Crea un clúster de GKE zonal:

          gcloud container clusters create ${KUBERNETES_CLUSTER_PREFIX}-cluster \
              --location ${LOCATION} \
              --node-locations ${LOCATION} \
              --shielded-secure-boot \
              --shielded-integrity-monitoring \
              --machine-type "e2-micro" \
              --num-nodes "1"
          
        2. Agrega un grupo de nodos con un tipo de máquina N2 para la implementación inicial de MySQL:

          gcloud container node-pools create regular-pool \
              --cluster ${KUBERNETES_CLUSTER_PREFIX}-cluster \
              --machine-type n2-standard-4 \
              --location ${LOCATION} \
              --num-nodes 1
          
        3. Agrega un grupo de nodos con un tipo de máquina N4 en Hyperdisk donde se migrará y ejecutará la implementación de MySQL:

          gcloud container node-pools create hyperdisk-pool \
              --cluster ${KUBERNETES_CLUSTER_PREFIX}-cluster \
              --machine-type n4-standard-4 \
              --location ${LOCATION} \
              --num-nodes 1
          
        4. Conéctese al clúster:

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

        Implementa MySQL en Persistent Disk

        En esta sección, implementarás una instancia de MySQL que usa un Persistent Disk para el almacenamiento y la cargarás con datos de muestra.

        1. Crea y aplica un objeto StorageClass para Hyperdisk. Este StorageClass se usará más adelante en el instructivo.

          apiVersion: storage.k8s.io/v1
          kind: StorageClass
          metadata:
            name: balanced-storage
          provisioner: pd.csi.storage.gke.io
          volumeBindingMode: WaitForFirstConsumer
          allowVolumeExpansion: true
          parameters:
            type: hyperdisk-balanced
            provisioned-throughput-on-create: "250Mi"
            provisioned-iops-on-create: "7000"
          kubectl apply -f manifests/01-storage-class/storage-class-hdb.yaml
          
        2. Crea e implementa una instancia de MySQL que incluya afinidad de nodos para garantizar que los Pods se programen en nodos regular-pool y aprovisione un volumen de SSD de disco persistente.

          apiVersion: v1
          kind: Service
          metadata:
            name: regular-mysql
            labels:
              app: mysql
          spec:
            ports:
              - port: 3306
            selector:
              app: mysql
            clusterIP: None
          ---
          apiVersion: v1
          kind: PersistentVolumeClaim
          metadata:
            name: mysql-pv-claim
            labels:
              app: mysql
          spec:
            accessModes:
              - ReadWriteOnce
            resources:
              requests:
                storage: 30Gi
            storageClassName: premium-rwo
          ---
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: existing-mysql
            labels:
              app: mysql
          spec:
            selector:
              matchLabels:
                app: mysql
            strategy:
              type: Recreate
            template:
              metadata:
                labels:
                  app: mysql
              spec:
                containers:
                - image: mysql:8.0
                  name: mysql
                  env:
                  - name: MYSQL_ROOT_PASSWORD
                    value: migration
                  - name: MYSQL_DATABASE
                    value: mysql
                  - name: MYSQL_USER
                    value: app
                  - name: MYSQL_PASSWORD
                    value: migration
                  ports:
                  - containerPort: 3306
                    name: mysql
                  volumeMounts:
                  - name: mysql-persistent-storage
                    mountPath: /var/lib/mysql
                affinity: 
                  nodeAffinity:
                    preferredDuringSchedulingIgnoredDuringExecution:
                    - weight: 1
                      preference:
                        matchExpressions:
                        - key: "node.kubernetes.io/instance-type"
                          operator: In
                          values:
                          - "n2-standard-4"
                volumes:
                - name: mysql-persistent-storage
                  persistentVolumeClaim:
                    claimName: mysql-pv-claim
          kubectl apply -f manifests/02-mysql/mysql-deployment.yaml
          

          Este manifiesto crea una implementación y un servicio de MySQL, con un Persistent Disk aprovisionado de forma dinámica para el almacenamiento de datos. La contraseña del usuario root es migration.

        3. Implementa un Pod de cliente de MySQL para cargar datos y verificar la migración de datos:

          apiVersion: v1
          kind: Pod
          metadata:
            name: mysql-client
          spec:
            containers:
            - name: main
              image: mysql:8.0
              command: ["sleep", "360000"]
              resources:
                requests:
                  memory: 1Gi
                  cpu: 500m
                limits:
                  memory: 1Gi
                  cpu: "1"
              env:
              - name: MYSQL_ROOT_PASSWORD
                value: migration
          kubectl apply -f manifests/02-mysql/mysql-client.yaml
          kubectl wait pods mysql-client --for condition=Ready --timeout=300s
          
        4. Conéctate al Pod cliente:

          kubectl exec -it mysql-client -- bash
          
        5. Desde el shell del Pod del cliente, descarga e importa el conjunto de datos de muestra de Sakila:

          # Download the dataset
          curl --output dataset.tgz "https://downloads.mysql.com/docs/sakila-db.tar.gz"
          
          # Extract the dataset
          tar -xvzf dataset.tgz -C /home/mysql
          
          # Import the dataset into MySQL (the password is "migration").
          mysql -u root -h regular-mysql.default -p
              SOURCE /sakila-db/sakila-schema.sql;
              SOURCE /sakila-db/sakila-data.sql;
          
        6. Verifica que los datos se hayan importado:

          USE sakila;
          SELECT      table_name,      table_rows  FROM      INFORMATION_SCHEMA.TABLES  WHERE TABLE_SCHEMA = 'sakila';
          

          El resultado muestra una lista de tablas con recuentos de filas.

          | TABLE_NAME                 | TABLE_ROWS |
          +----------------------------+------------+
          | actor                      |        200 |
          | actor_info                 |       NULL |
          | address                    |        603 |
          | category                   |         16 |
          | city                       |        600 |
          | country                    |        109 |
          | customer                   |        599 |
          | customer_list              |       NULL |
          | film                       |       1000 |
          | film_actor                 |       5462 |
          | film_category              |       1000 |
          | film_list                  |       NULL |
          | film_text                  |       1000 |
          | inventory                  |       4581 |
          | language                   |          6 |
          | nicer_but_slower_film_list |       NULL |
          | payment                    |      16086 |
          | rental                     |      16419 |
          | sales_by_film_category     |       NULL |
          | sales_by_store             |       NULL |
          | staff                      |          2 |
          | staff_list                 |       NULL |
          | store                      |          2 |
          +----------------------------+------------+
          23 rows in set (0.01 sec)
          
        7. Sal de la sesión de mysql:

          exit;
          
        8. Sal de la shell del Pod del cliente:

          exit
          
        9. Obtén el nombre del PersistentVolume (PV) creado para MySQL y almacénalo en una variable de entorno:

          export PV_NAME=$(kubectl get pvc mysql-pv-claim -o jsonpath='{.spec.volumeName}')
          

        Migra los datos a un volumen de Hyperdisk

        Ahora tienes una carga de trabajo de MySQL con datos almacenados en un volumen de SSD de disco persistente. En esta sección, se describe cómo migrar estos datos a un volumen de Hyperdisk con una instantánea. Este enfoque de migración también conserva el volumen original del Persistent Disk, lo que te permite revertir el uso de la instancia original de MySQL si es necesario.

        1. Si bien puedes crear instantáneas de los discos sin desconectarlos de las cargas de trabajo, para garantizar la integridad de los datos de MySQL, debes detener cualquier operación de escritura nueva en el disco durante la creación de la instantánea. Reduce la escala de la implementación de MySQL a 0 réplicas para detener las escrituras:

          kubectl scale deployment regular-mysql --replicas=0
          
        2. Crea una instantánea a partir del Persistent Disk existente:

          gcloud compute disks snapshot ${PV_NAME} --location=${LOCATION} --snapshot-name=original-snapshot --description="snapshot taken from pd-ssd"
          
        3. Crea un volumen de Hyperdisk nuevo llamado mysql-recovery a partir de la instantánea:

          gcloud compute disks create mysql-recovery --project=${PROJECT_ID} \
              --type=hyperdisk-balanced \
              --size=150GB --location=${LOCATION} \
              --source-snapshot=projects/${PROJECT_ID}/global/snapshots/original-snapshot
          
        4. Actualiza el archivo de manifiesto del PV restablecido con el ID de tu proyecto:

          apiVersion: v1
          kind: PersistentVolume
          metadata:
            name: backup
          spec:
            storageClassName: balanced-storage
            capacity:
              storage: 150G
            accessModes:
              - ReadWriteOnce
            claimRef:
              name: hyperdisk-recovery
              namespace: default
            csi:
              driver: pd.csi.storage.gke.io
              volumeHandle: projects/PRJCTID/zones/us-central1-a/disks/mysql-recovery
              fsType: ext4
          ---
          apiVersion: v1
          kind: PersistentVolumeClaim
          metadata:
            namespace: default
            name: hyperdisk-recovery
          spec:
            storageClassName: balanced-storage
            accessModes:
              - ReadWriteOnce
            resources:
              requests:
                storage: 150G
          sed -i "s/PRJCTID/$PROJECT_ID/g" manifests/02-mysql/restore_pv.yaml
          
        5. Crea el PersistentVolume (PV) y el PersistentVolumeClaim a partir del nuevo Hyperdisk:

          kubectl apply -f manifests/02-mysql/restore_pv.yaml
          

        Verifica la migración de datos

        Implementa una instancia de MySQL nueva que use el volumen de Hyperdisk recién creado. Este Pod se programará en el grupo de nodos hyperdisk-pool, que consta de nodos N4.

        1. Implementa la nueva instancia de MySQL:

          apiVersion: v1
          kind: Service
          metadata:
            name: recovered-mysql
            labels:
              app: new-mysql
          spec:
            ports:
              - port: 3306
            selector:
              app: new-mysql
            clusterIP: None
          ---
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: new-mysql
            labels:
              app: new-mysql
          spec:
            selector:
              matchLabels:
                app: new-mysql
            strategy:
              type: Recreate
            template:
              metadata:
                labels:
                  app: new-mysql
              spec:
                containers:
                - image: mysql:8.0
                  name: mysql
                  env:
                  - name: MYSQL_ROOT_PASSWORD
                    value: migration
                  - name: MYSQL_DATABASE
                    value: mysql
                  - name: MYSQL_USER
                    value: app
                  - name: MYSQL_PASSWORD
                    value: migration
                  ports:
                  - containerPort: 3306
                    name: mysql
                  volumeMounts:
                  - name: mysql-persistent-storage
                    mountPath: /var/lib/mysql
                affinity: 
                  nodeAffinity:
                    preferredDuringSchedulingIgnoredDuringExecution:
                    - weight: 1
                      preference:
                        matchExpressions:
                        - key: "cloud.google.com/gke-nodepool"
                          operator: In
                          values:
                          - "hyperdisk-pool"      
                volumes:
                - name: mysql-persistent-storage
                  persistentVolumeClaim:
                    claimName: hyperdisk-recovery
          kubectl apply -f manifests/02-mysql/recovery_mysql_deployment.yaml
          
        2. Para verificar la integridad de los datos, vuelve a conectarte al Pod del cliente de MySQL:

          kubectl exec -it mysql-client -- bash
          
        3. Dentro del Pod de cliente, conéctate a la nueva base de datos de MySQL (recovered-mysql.default) y verifica los datos. La contraseña es migration.

          mysql -u root -h recovered-mysql.default -p
          USE sakila;
          SELECT table_name, table_rows FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'sakila';
          

          Los datos deben ser los mismos que en tu instancia original de MySQL en el Persistent Disk persistente.

        4. Sal de la sesión de mysql:

          exit;
          
        5. Sal de la shell del Pod del cliente:

          exit
          

        Limpia

        Para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos usados en este instructivo, borra el proyecto que contiene los recursos o conserva el proyecto y borra los recursos individuales.

        Borra el proyecto

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

          Go to Manage resources

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

        Borra los recursos individuales

        Si usaste un proyecto existente y no quieres borrarlo, borra los recursos individuales:

        1. Configura variables de entorno para la limpieza y recupera el nombre del volumen de Persistent Disk creado por el PersistentVolumeClaim mysql-pv-claim:

          export PROJECT_ID=PROJECT_ID
          export KUBERNETES_CLUSTER_PREFIX=offline-hyperdisk-migration
          export location=us-central1-a
          export PV_NAME=$(kubectl get pvc mysql-pv-claim -o jsonpath='{.spec.volumeName}')
          

          Reemplaza PROJECT_ID con el ID del proyecto.

        2. Borra la instantánea:

          gcloud compute snapshots delete original-snapshot --quiet
          
        3. Borra el clúster de GKE:

          gcloud container clusters delete ${KUBERNETES_CLUSTER_PREFIX}-cluster --location=${LOCATION} --quiet
          
        4. Borra los volúmenes de Persistent Disk y Hyperdisk:

          gcloud compute disks delete ${PV_NAME} --location=${LOCATION} --quiet
          gcloud compute disks delete mysql-recovery --location=${LOCATION} --quiet
          

        ¿Qué sigue?