Migrar dados do MySQL do Persistent Disk para o Hyperdisk no GKE

Neste tutorial, mostramos como migrar seus dados do MySQL de um Persistent Disk (DP) para o Hyperdisk no Google Kubernetes Engine para fazer upgrade da performance de armazenamento. O Hyperdisk oferece IOPS e capacidade de processamento mais altos do que Persistent Disk, o que pode melhorar o desempenho do MySQL ao reduzir a latência das consultas e transações do banco de dados. É possível usar snapshots de disco para migrar seus dados para diferentes tipos de disco, dependendo da compatibilidade do tipo de máquina. Por exemplo, os volumes do Hyperdisk são compatíveis apenas com alguns tipos de máquinas de terceira, quarta e gerações posteriores, como N4, que não são compatíveis com discos permanentes. 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 o banco de dados Sakila para fornecer um conjunto de dados de amostra. O Sakila é um banco de dados de amostra fornecido pelo MySQL que pode ser usado como um esquema para tutoriais e exemplos. Ele representa uma locadora de DVD fictícia e inclui tabelas para filmes, atores, clientes e locações.

Este guia é destinado a especialistas e administradores de armazenamento que criam e alocam armazenamento e gerenciam a segurança de dados e o acesso aos dados. Para saber mais sobre papéis comuns e tarefas de exemplo que mencionamos no conteúdo do Google Cloud , consulte Funções e tarefas comuns do usuário do GKE.

Arquitetura de implantação

O diagrama a seguir ilustra o processo de migração de um Persistent Disk para um Hyperdisk.

  • Um aplicativo MySQL é executado em um pool de nós do GKE com tipos de máquina N2, armazenando os dados em um SSD de disco permanente.
  • Para garantir a consistência dos dados, o aplicativo é reduzido para evitar novas gravações.
  • Um snapshot do Persistent Disk é criado, servindo como um backup completo e pontual dos dados.
  • Um novo Hyperdisk é provisionado do snapshot, e uma nova instância do MySQL é implantada em um pool de nós N4 separado e compatível com o Hyperdisk. Essa nova instância é anexada ao Hyperdisk recém-criado, concluindo a migração para o armazenamento de maior desempenho.
Diagrama de arquitetura mostrando a migração de dados do MySQL do Persistent Disk para o Hyperdisk usando um snapshot.
Figura 1: migração de dados do MySQL do Persistent Disk para o hiperdisco usando um snapshot.

Objetivos

Neste tutorial, você vai aprender a:

  • Implante um cluster do MySQL.
  • Faça o upload de um conjunto de dados de teste.
  • Crie um snapshot dos seus dados.
  • Crie um hiperdisco com base no snapshot.
  • Inicie um novo cluster do MySQL em um pool de nós do tipo de máquina N4 com Hyperdisk ativado.
  • Verifique a integridade de dados para confirmar uma migração bem-sucedida.

Custos

Neste documento, você vai usar 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 custo baseada na projeção de uso deste tutorial, use a calculadora de preços.

Novos usuários do Google Cloud podem estar qualificados para um teste sem custo financeiro.

Antes de começar

  1. Faça login na sua conta do Google Cloud . Se você começou a usar o Google Cloud, crie uma conta para avaliar o desempenho de nossos produtos em situações reais. Clientes novos também recebem US$ 300 em créditos para executar, testar e implantar cargas de trabalho.
  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 role (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 role (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. Verifique se você tem os seguintes papéis no projeto: roles/container.admin, roles/iam.serviceAccountAdmin, roles/compute.admin

    Verificar os papéis

    1. No console do Google Cloud , acesse a página IAM.

      Acessar IAM
    2. Selecione o projeto.
    3. Na coluna Principal, encontre todas as linhas que identificam você ou um grupo no qual você está incluído. Para saber em quais grupos você está incluído, entre em contato com o administrador.

    4. Em todas as linhas que especificam ou incluem você, verifique a coluna Papel para ver se a lista de papéis inclui os papéis necessários.

    Conceder os papéis

    1. No console do Google Cloud , acesse a página IAM.

      Acessar IAM
    2. Selecione o projeto.
    3. Clique em Conceder acesso.
    4. No campo Novos principais, digite seu identificador de usuário. Normalmente, é o endereço de e-mail de uma Conta do Google.

    5. Clique em Selecionar um papel e pesquise o papel.
    6. Para conceder outros papéis, adicione-os clicando em Adicionar outro papel.
    7. Clique em Salvar.

Configurar o Cloud Shell

  1. No console do Google Cloud , ative o Cloud Shell.

    Ativar o Cloud Shell

    Na parte de baixo do console Google Cloud , uma sessão do Cloud Shell é iniciada e exibe um prompt de linha de comando. O Cloud Shell é um ambiente shell com a CLI do Google Cloud já instalada e com valores já definidos para o projeto atual. A inicialização da sessão pode levar alguns segundos.

  2. Uma sessão do Cloud Shell é iniciada e exibe um prompt de linha de comando. A inicialização da sessão pode levar alguns segundos.

  3. Defina seu projeto padrão:

      gcloud config set project PROJECT_ID
    

    Substitua PROJECT_ID pela ID do seu projeto.

Prepare o ambiente

  1. No Cloud Shell, defina as variáveis de ambiente para o projeto, o local e o 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:

    • PROJECT_ID: o ID do projeto do Google Cloud .
    • EMAIL_ADDRESS: seu endereço de e-mail.
    • LOCATION: a zona em que você quer criar os recursos de implantação. Para os fins deste tutorial, use a zona us-central1-a.
  2. Clone o repositório de exemplo de código do GitHub:

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

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

Criar o cluster do GKE e os pools de nós

Este tutorial usa um cluster zonal para simplificar, porque os volumes do Hyperdisk são recursos zonais e só podem ser acessados em uma única zona.

  1. Crie um cluster zonal do GKE:

    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 pool de nós com um tipo de máquina N2 para a implantaçã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 pool de nós com um tipo de máquina N4 no Hyperdisk, em que a implantação do MySQL 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. Conecte-se ao cluster:

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

Implantar o MySQL em Persistent Disk

Nesta seção, você vai implantar uma instância do MySQL que usa um Persistent Disk para armazenamento e carregá-la com dados de amostra.

  1. Crie e aplique um StorageClass para o Hyperdisk. Esse StorageClass 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 implante uma instância do MySQL que inclua afinidade de nós para garantir que os pods sejam programados em nós regular-pool e provisione um volume SSD do Persistent Disk.

    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
    

    Esse manifesto cria uma implantação e um serviço do MySQL, com um Persistent Disk provisionado dinamicamente para armazenamento de dados. A senha do usuário root é migration.

  3. Implante um pod cliente do MySQL para carregar dados e verifique 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. Conecte-se ao pod cliente:

    kubectl exec -it mysql-client -- bash
    
  5. No shell do pod cliente, faça o download e importe o conjunto de dados de amostra 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 mysql:

    exit;
    
  8. Saia do shell do pod cliente:

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

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

Migrar os dados para um volume do Hyperdisk

Agora você tem uma carga de trabalho do MySQL com dados armazenados em um volume SSD do Persistent Disk. Nesta seção, descrevemos como migrar esses dados para um volume do hiperdisco usando um snapshot. Essa abordagem de migração também preserva o volume original do Persistent Disk, permitindo que você reverter a usar a instância original do MySQL, se necessário.

  1. É possível criar snapshots de discos sem separá-los das cargas de trabalho, mas, para garantir a integridade de dados do MySQL, interrompa qualquer nova gravação no disco durante a criação do snapshot. Reduza a escala vertical da implantação do MySQL para 0 réplicas para interromper as gravações:

    kubectl scale deployment regular-mysql --replicas=0
    
  2. Crie um snapshot do Persistent Disk atual:

    gcloud compute disks snapshot ${PV_NAME} --location=${LOCATION} --snapshot-name=original-snapshot --description="snapshot taken from pd-ssd"
    
  3. Crie um volume do Hyperdisk chamado mysql-recovery com base no snapshot:

    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 arquivo de manifesto do PV restaurado com o ID do 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 do novo Hyperdisk:

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

Verificar a migração de dados

Implante uma nova instância do MySQL que use o volume do Hyperdisk recém-criado. Esse pod será programado no pool de nós hyperdisk-pool, que consiste em nós N4.

  1. Implante 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 verificar a integridade de dados, conecte-se ao pod cliente do MySQL novamente:

    kubectl exec -it mysql-client -- bash
    
  3. Dentro do pod cliente, conecte-se ao novo banco de dados MySQL (recovered-mysql.default) e verifique os dados. A senha é 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 precisam ser os mesmos da instância original do MySQL no Persistent Disk permanente.

  4. Saia da sessão mysql:

    exit;
    
  5. Saia do shell do pod cliente:

    exit
    

Limpar

Para evitar cobranças na sua conta do Google Cloud pelos recursos usados no tutorial, exclua o projeto que os contém ou mantenha o projeto e exclua os recursos individuais.

Excluir o projeto

    Excluir um projeto do Google Cloud :

    gcloud projects delete PROJECT_ID

Excluir recursos individuais

Se você usou um projeto atual e não quer excluí-lo, exclua os recursos individuais:

  1. Defina variáveis de ambiente para limpeza e recupere o nome do volume de Persistent Disk criado pelo 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}')
    

    Substitua PROJECT_ID pela ID do seu projeto.

  2. Exclua o snapshot:

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

    gcloud container clusters delete ${KUBERNETES_CLUSTER_PREFIX}-cluster --location=${LOCATION} --quiet
    
  4. Exclua os volumes de Persistent Disk e hiperdisco:

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

A seguir