Migre os seus dados do MySQL do disco persistente para o Hyperdisk no GKE

Este tutorial demonstra como pode migrar os seus dados MySQL existentes de um Persistent Disk (PD) para um Hyperdisk no Google Kubernetes Engine para atualizar o desempenho do armazenamento. O Hyperdisk oferece IOPS e débito mais elevados do que o disco persistente, o que pode melhorar o desempenho do MySQL reduzindo a latência das consultas e transações da base de dados. Pode usar cópias instantâneas de discos para migrar os seus dados para diferentes tipos de discos, consoante a compatibilidade do tipo de máquina. Por exemplo, os volumes Hyperdisk só são compatíveis com alguns tipos de máquinas de terceira, quarta e gerações posteriores, como N4, que não suportam discos persistentes. Para mais informações, consulte as séries de máquinas disponíveis.

Para demonstrar a migração do Persistent Disk para o Hyperdisk, este tutorial usa a base de dados Sakila para fornecer um conjunto de dados de exemplo. Sakila é uma base de dados de amostra fornecida pelo MySQL que pode usar como um esquema para tutoriais e exemplos. Representa uma loja de aluguer de DVDs fictícia e inclui tabelas para filmes, atores, clientes e alugueres.

Este guia destina-se a especialistas e administradores de armazenamento que criam e atribuem armazenamento, e gerem a segurança e o acesso aos dados. Para saber mais sobre as funções comuns e as tarefas de exemplo que referimos no Google Cloud conteúdo, consulte o artigo Funções e tarefas comuns de utilizadores do GKE.

Arquitetura de implementação

O diagrama seguinte ilustra o processo de migração de um disco persistente para um Hyperdisk.

  • Uma aplicação MySQL é executada num conjunto de nós do GKE com tipos de máquinas N2, armazenando os respetivos dados num SSD de disco persistente.
  • Para garantir a consistência dos dados, a aplicação é reduzida para impedir novas escritas.
  • É criado um instantâneo do disco persistente, que serve como uma cópia de segurança completa dos dados num determinado momento.
  • É aprovisionado um novo Hyperdisk a partir da imagem instantânea e é implementada uma nova instância do MySQL num conjunto de nós N4 separado e compatível com o Hyperdisk. Esta nova instância é anexada ao Hyperdisk recém-criado, o que finaliza a migração para o armazenamento de maior desempenho.
Diagrama de arquitetura que mostra a migração de dados do MySQL do disco persistente para o Hyperdisk através de uma captura de ecrã.
Figura 1: migração de dados do MySQL do Persistent Disk para o Hyperdisk através de um instantâneo.

Objetivos

Neste tutorial, vai aprender a fazer o seguinte:

  • Implemente um cluster MySQL.
  • Carregue um conjunto de dados de teste.
  • Crie um instantâneo dos seus dados.
  • Crie um Hyperdisk a partir do instantâneo.
  • Inicie um novo cluster do MySQL num node pool do tipo de máquina N4 com o Hyperdisk ativado.
  • Valide a integridade dos dados para confirmar uma migração bem-sucedida.

Custos

Neste documento, usa os seguintes componentes faturáveis do Google Cloud:

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

Para gerar uma estimativa de custos com base na sua utilização projetada, use a calculadora de preços.

Os novos Google Cloud utilizadores podem ser elegíveis para uma avaliação gratuita.

Antes de começar

  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.

      Aceder ao IAM
    2. Selecione o projeto.
    3. Clique em Conceder acesso.
    4. No campo Novos responsáveis, introduza o identificador do utilizador. Normalmente, este é o endereço de email de uma Conta Google.

    5. Na lista Selecionar uma função, selecione uma função.
    6. Para conceder funções adicionais, clique em Adicionar outra função e adicione cada função adicional.
    7. Clique em Guardar.
    8. Configure o Cloud Shell

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

        Activate Cloud Shell

        É iniciada uma sessão do Cloud Shell e é apresentado um pedido de linha de comandos. A sessão pode demorar alguns segundos a ser inicializada.

      2. Defina o projeto predefinido:

          gcloud config set project PROJECT_ID
        

        Substitua PROJECT_ID pelo ID do seu projeto.

      3. Prepare o ambiente

        1. No Cloud Shell, defina as variáveis de ambiente para o seu projeto, localização e prefixo do cluster.

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

          Substitua o seguinte:

          • PROJECT_ID: o seu Google Cloud ID do projeto.
          • EMAIL_ADDRESS: o seu endereço de email.
          • LOCATION: a zona onde quer criar os recursos de implementação. Para efeitos deste tutorial, use a us-central1-a zona.
        2. Clone o repositório de código de exemplo do GitHub:

          git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
          
        3. Navegue para o offline-hyperdisk-migrationdiretório para começar a criar recursos de implementação:

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

        Crie o cluster do GKE e os node pools

        Este tutorial usa um cluster zonal por simplicidade, porque os volumes do Hyperdisk são recursos zonais e só estão acessíveis numa única zona.

        1. Crie um cluster do 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. Adicione um conjunto de nós com um tipo de máquina N2 para a implementação inicial do MySQL:

          gcloud container node-pools create regular-pool \
              --cluster ${KUBERNETES_CLUSTER_PREFIX}-cluster \
              --machine-type n2-standard-4 \
              --location ${LOCATION} \
              --num-nodes 1
          
        3. Adicione um conjunto de nós com um tipo de máquina N4 no Hyperdisk onde a implementação do MySQL vai ser migrada e executada:

          gcloud container node-pools create hyperdisk-pool \
              --cluster ${KUBERNETES_CLUSTER_PREFIX}-cluster \
              --machine-type n4-standard-4 \
              --location ${LOCATION} \
              --num-nodes 1
          
        4. Ligue-se ao cluster:

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

        Implemente o MySQL no disco persistente

        Nesta secção, implementa uma instância do MySQL que usa um disco persistente para armazenamento e carrega-o com dados de exemplo.

        1. Crie e aplique um StorageClass para o Hyperdisk. Este StorageClass vai ser usado mais tarde no tutorial.

          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. Crie e implemente uma instância do MySQL que inclua afinidade de nós para garantir que os pods são agendados em nós regular-pool e aprovisiona um volume 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 manifesto cria uma implementação e um serviço MySQL, com um disco persistente aprovisionado dinamicamente para o armazenamento de dados. A palavra-passe do utilizador root é migration.

        3. Implemente um pod de cliente MySQL para carregar dados e validar a migração de dados:

          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. Ligue-se ao pod do cliente:

          kubectl exec -it mysql-client -- bash
          
        5. A partir da shell do pod do cliente, transfira e importe o conjunto de dados de exemplo 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. Verifique se os dados foram importados:

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

          A saída mostra uma lista de tabelas com contagens de linhas.

          | 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. Saia da sessão do mysql:

          exit;
          
        8. Saia da shell do pod do cliente:

          exit
          
        9. Obtenha o nome do PersistentVolume (PV) criado para o MySQL e armazene-o numa variável de ambiente:

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

        Migre os dados para um volume do Hyperdisk

        Agora, tem uma carga de trabalho do MySQL com dados armazenados num volume de SSD do Persistent Disk. Esta secção descreve como migrar estes dados para um volume do Hyperdisk através de uma captura instantânea. Esta abordagem de migração também preserva o volume do disco persistente original, o que lhe permite reverter para a utilização da instância do MySQL original, se necessário.

        1. Embora possa criar instantâneos a partir de discos sem os desassociar de cargas de trabalho, para garantir a integridade dos dados do MySQL, tem de impedir que ocorram novas gravações no disco durante a criação do instantâneo. Reduza a escala da implementação do MySQL para 0 réplicas para parar as gravações:

          kubectl scale deployment regular-mysql --replicas=0
          
        2. Crie um instantâneo a partir do Persistent Disk existente:

          gcloud compute disks snapshot ${PV_NAME} --location=${LOCATION} --snapshot-name=original-snapshot --description="snapshot taken from pd-ssd"
          
        3. Crie um novo volume do Hyperdisk com o nome mysql-recovery a partir do instantâneo:

          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. Atualize o ficheiro de manifesto para o PV restaurado com o ID do seu projeto:

          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. Crie o PersistentVolume (PVC) e o PersistentVolumeClaim a partir do novo Hyperdisk:

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

        Valide a migração de dados

        Implemente uma nova instância do MySQL que use o volume do Hyperdisk recém-criado. Este pod vai ser agendado no conjunto de nós hyperdisk-pool, que consiste em nós N4.

        1. Implemente a nova instância do 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 validar a integridade dos dados, ligue-se novamente ao pod do cliente MySQL:

          kubectl exec -it mysql-client -- bash
          
        3. No pod do cliente, estabeleça ligação à nova base de dados MySQL (recovered-mysql.default) e valide os dados. A palavra-passe é migration.

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

          Os dados devem ser os mesmos que na instância original do MySQL no volume do disco persistente.

        4. Saia da sessão do mysql:

          exit;
          
        5. Saia da shell do pod do cliente:

          exit
          

        Limpar

        Para evitar incorrer em custos na sua conta do Google Cloud pelos recursos usados neste tutorial, elimine o projeto que contém os recursos ou mantenha o projeto e elimine os recursos individuais.

        Elimine o projeto

        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.

        Elimine recursos individuais

        Se usou um projeto existente e não quer eliminá-lo, elimine os recursos individuais:

        1. Defina variáveis de ambiente para a limpeza e obtenha o nome do volume do disco persistente criado pelo mysql-pv-claim PersistentVolumeClaim:

          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}')
          

          Substitua PROJECT_ID pelo ID do seu projeto.

        2. Elimine o instantâneo:

          gcloud compute snapshots delete original-snapshot --quiet
          
        3. Elimine o cluster do GKE:

          gcloud container clusters delete ${KUBERNETES_CLUSTER_PREFIX}-cluster --location=${LOCATION} --quiet
          
        4. Elimine os volumes do Persistent Disk e Hyperdisk:

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

        O que se segue?