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é.

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