Migrer vos données MySQL d'un disque persistant vers un hyperdisque dans GKE

Ce tutoriel explique comment migrer vos données MySQL existantes d'un disque persistant vers un hyperdisk sur Google Kubernetes Engine afin d'améliorer les performances de votre stockage. Hyperdisk offre des IOPS et un débit plus élevés que Persistent Disk, ce qui peut améliorer les performances de MySQL en réduisant la latence des requêtes et des transactions de base de données. Vous pouvez utiliser des instantanés de disque pour migrer vos données vers différents types de disques en fonction de la compatibilité du type de machine. Par exemple, les volumes Hyperdisk ne sont compatibles qu'avec certains types de machines de troisième, quatrième génération et ultérieures, comme N4, qui ne sont pas compatibles avec les disques persistants. Pour en savoir plus, consultez les séries de machines disponibles.

Pour illustrer la migration de disque persistant vers Hyperdisk, ce tutoriel utilise la base de données Sakila pour fournir un exemple d'ensemble de données. Sakila est un exemple de base de données fourni par MySQL. Vous pouvez l'utiliser comme schéma pour les tutoriels et les exemples. Elle représente un magasin de location de DVD fictif et comprend des tables pour les films, les acteurs, les clients et les locations.

Ce guide s'adresse aux spécialistes et aux administrateurs du stockage qui créent et attribuent de l'espace de stockage, et qui gèrent la sécurité et l'accès aux données. Pour en savoir plus sur les rôles courants et les exemples de tâches que nous citons dans le contenu Google Cloud , consultez Rôles utilisateur et tâches courantes de GKE.

Architecture de déploiement

Le schéma suivant illustre le processus de migration d'un disque persistant vers un Hyperdisk.

  • Une application MySQL s'exécute sur un pool de nœuds GKE avec des types de machines N2, en stockant ses données sur un disque persistant SSD.
  • Pour assurer la cohérence des données, l'application est réduite pour empêcher les nouvelles écritures.
  • Un instantané du disque persistant est créé, ce qui constitue une sauvegarde complète des données à un moment précis.
  • Un nouveau disque Hyperdisk est provisionné à partir de l'instantané, et une nouvelle instance MySQL est déployée sur un pool de nœuds N4 distinct et compatible avec Hyperdisk. Cette nouvelle instance est associée à l'hyperdisque nouvellement créé, ce qui finalise la migration vers le stockage plus performant.
Schéma d'architecture montrant la migration de données MySQL d'un disque persistant vers un disque Hyperdisk à l'aide d'un instantané.
Figure 1 : Migration des données MySQL d'un disque persistant vers un disque Hyperdisk à l'aide d'un instantané.

Objectifs

Dans ce tutoriel, vous allez apprendre à effectuer les opérations suivantes :

  • Déployez un cluster MySQL.
  • Importer un ensemble de données de test
  • Créez un instantané de vos données.
  • Créez un Hyperdisk à partir de l'instantané.
  • Démarrez un cluster MySQL dans un pool de nœuds de type de machine N4 compatible avec Hyperdisk.
  • Vérifiez l'intégrité des données pour confirmer que la migration a réussi.

Coûts

Dans ce document, vous utilisez les composants facturables de Google Cloudsuivants :

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

Vous pouvez obtenir une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût.

Les nouveaux utilisateurs de Google Cloud peuvent bénéficier d'un essai gratuit.

Avant de commencer

  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.

      Accéder à IAM
    2. Sélectionnez le projet.
    3. Cliquez sur  Accorder l'accès.
    4. Dans le champ Nouveaux comptes principaux, saisissez votre identifiant utilisateur. Il s'agit généralement de l'adresse e-mail d'un compte Google.

    5. Dans la liste Sélectionner un rôle, sélectionnez un rôle.
    6. Pour attribuer des rôles supplémentaires, cliquez sur  Ajouter un autre rôle et ajoutez tous les rôles supplémentaires.
    7. Cliquez sur Enregistrer.
    8. Configurer Cloud Shell

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

        Activate Cloud Shell

        Une session Cloud Shell démarre et affiche une invite de ligne de commande. L'initialisation de la session peut prendre quelques secondes.

      2. Définissez le projet par défaut :

          gcloud config set project PROJECT_ID
        

        Remplacez PROJECT_ID par l'ID du projet.

      3. Préparer l'environnement

        1. Dans Cloud Shell, définissez les variables d'environnement pour votre projet, votre emplacement et le préfixe de votre cluster.

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

          Remplacez les éléments suivants :

          • PROJECT_ID : ID de votre projet Google Cloud .
          • EMAIL_ADDRESS : votre adresse e-mail.
          • LOCATION : zone dans laquelle vous souhaitez créer vos ressources de déploiement. Pour les besoins de ce tutoriel, utilisez la zone us-central1-a.
        2. Clonez l'exemple de dépôt de code depuis GitHub :

          git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
          
        3. Accédez au répertoire offline-hyperdisk-migration pour commencer à créer des ressources de déploiement :

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

        Créer le cluster GKE et les pools de nœuds

        Ce tutoriel utilise un cluster zonal pour plus de simplicité, car les volumes Hyperdisk sont des ressources zonales et ne sont accessibles que dans une seule zone.

        1. Créez un cluster 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. Ajoutez un pool de nœuds avec un type de machine N2 pour le déploiement initial 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. Ajoutez un pool de nœuds avec un type de machine N4 sur Hyperdisk, où le déploiement MySQL sera migré et exécuté :

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

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

        Déployer MySQL sur un disque persistant

        Dans cette section, vous allez déployer une instance MySQL qui utilise un disque persistant pour le stockage et la charger avec des exemples de données.

        1. Créez et appliquez un StorageClass pour Hyperdisk. Ce StorageClass sera utilisé plus loin dans le tutoriel.

          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. Créez et déployez une instance MySQL qui inclut l'affinité de nœud pour vous assurer que les pods sont planifiés sur les nœuds regular-pool et provisionnez un volume SSD de disque persistant.

          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
          

          Ce fichier manifeste crée un déploiement et un service MySQL, avec un disque persistant provisionné de manière dynamique pour le stockage des données. Le mot de passe de l'utilisateur root est migration.

        3. Déployez un pod client MySQL pour charger les données et vérifiez la migration des données :

          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. Connectez-vous au pod client :

          kubectl exec -it mysql-client -- bash
          
        5. Dans le shell du pod client, téléchargez et importez l'exemple d'ensemble de données 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. Vérifiez que les données ont été importées :

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

          Le résultat affiche une liste de tables avec le nombre de lignes.

          | 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. Quittez la session mysql :

          exit;
          
        8. Quittez le shell du pod client :

          exit
          
        9. Obtenez le nom du PersistentVolume (PV) créé pour MySQL et stockez-le dans une variable d'environnement :

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

        Migrer les données vers un volume Hyperdisk

        Vous disposez maintenant d'une charge de travail MySQL avec des données stockées sur un volume SSD de disque persistant. Cette section explique comment migrer ces données vers un volume Hyperdisk à l'aide d'un instantané. Cette approche de migration préserve également le volume de disque persistant d'origine, ce qui vous permet de revenir à l'instance MySQL d'origine si nécessaire.

        1. Bien que vous puissiez créer des instantanés à partir de disques sans les dissocier des charges de travail, vous devez arrêter toute nouvelle écriture sur votre disque pendant la création de l'instantané pour garantir l'intégrité des données MySQL. Ramenez le nombre d'instances répliquées du déploiement MySQL à 0 pour arrêter les écritures :

          kubectl scale deployment regular-mysql --replicas=0
          
        2. Créez un instantané à partir du disque persistant existant :

          gcloud compute disks snapshot ${PV_NAME} --location=${LOCATION} --snapshot-name=original-snapshot --description="snapshot taken from pd-ssd"
          
        3. Créez un volume Hyperdisk nommé mysql-recovery à partir de l'instantané :

          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. Mettez à jour le fichier manifeste du PV restauré avec l'ID de votre projet :

          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. Créez les objets PersistentVolume (PVC) et PersistentVolumeClaim à partir du nouveau disque Hyperdisk :

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

        Vérifier la migration des données

        Déployez une instance MySQL qui utilise le volume Hyperdisk nouvellement créé. Ce pod sera programmé sur le pool de nœuds hyperdisk-pool, qui se compose de nœuds N4.

        1. Déployez la nouvelle instance 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. Pour vérifier l'intégrité des données, reconnectez-vous au pod client MySQL :

          kubectl exec -it mysql-client -- bash
          
        3. Dans le pod client, connectez-vous à la nouvelle base de données MySQL (recovered-mysql.default) et vérifiez les données. Le mot de passe est migration.

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

          Les données doivent être identiques à celles de votre instance MySQL d'origine sur le volume de disque persistant.

        4. Quittez la session mysql :

          exit;
          
        5. Quittez le shell du pod client :

          exit
          

        Effectuer un nettoyage

        Pour éviter que les ressources utilisées lors de ce tutoriel soient facturées sur votre compte Google Cloud, supprimez le projet contenant les ressources, ou conservez le projet et supprimez les ressources individuelles.

        Supprimer le projet

        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.

        Supprimer des ressources individuelles

        Si vous avez utilisé un projet existant et que vous ne souhaitez pas le supprimer, supprimez les ressources individuelles :

        1. Définissez des variables d'environnement pour le nettoyage et récupérez le nom du volume de disque persistant créé par 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}')
          

          Remplacez PROJECT_ID par l'ID du projet.

        2. Supprimez l'instantané :

          gcloud compute snapshots delete original-snapshot --quiet
          
        3. Supprimez le cluster GKE :

          gcloud container clusters delete ${KUBERNETES_CLUSTER_PREFIX}-cluster --location=${LOCATION} --quiet
          
        4. Supprimez les volumes Persistent Disk et Hyperdisk :

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

        Étapes suivantes