MySQL-Daten von Persistent Disk zu Hyperdisk in GKE migrieren

In dieser Anleitung wird gezeigt, wie Sie Ihre vorhandenen MySQL-Daten von einem nichtflüchtigen Speicher zu Hyperdisk in Google Kubernetes Engine migrieren können, um die Speicherleistung zu verbessern. Hyperdisk bietet höhere IOPS und einen höheren Durchsatz als Persistent Disk. Dadurch kann die MySQL-Leistung verbessert werden, da die Latenz für Datenbankabfragen und ‑transaktionen reduziert wird. Sie können Festplattensnapshots verwenden, um Ihre Daten auf verschiedene Festplattentypen zu migrieren, je nach Kompatibilität des Maschinentyps. Hyperdisk-Volumes sind beispielsweise nur mit einigen Maschinentypen der dritten, vierten und späteren Generation wie N4 kompatibel, die keine nichtflüchtigen Speicher unterstützen. Weitere Informationen finden Sie unter Verfügbare Maschinenserien.

Zur Veranschaulichung der Migration von Persistent Disk zu Hyperdisk wird in dieser Anleitung die Sakila-Datenbank als Beispiel-Dataset verwendet. Sakila ist eine von MySQL bereitgestellte Beispieldatenbank, die Sie als Schema für Anleitungen und Beispiele verwenden können. Sie stellt einen fiktiven DVD-Verleih dar und enthält Tabellen für Filme, Schauspieler, Kunden und Verleihvorgänge.

Diese Anleitung richtet sich an Speicherspezialisten und Speicheradministratoren, die Speicherplatz erstellen und zuweisen sowie Datensicherheit und Datenzugriff verwalten. Weitere Informationen zu gängigen Rollen und Beispielaufgaben, auf die wir in Google Cloud -Inhalten verweisen, finden Sie unter Häufig verwendete GKE-Nutzerrollen und -Aufgaben.

Bereitstellungsarchitektur

Das folgende Diagramm veranschaulicht den Migrationsprozess von einer Persistent Disk zu einer Hyperdisk.

  • Eine MySQL-Anwendung wird in einem GKE-Knotenpool mit N2-Maschinentypen ausgeführt und speichert ihre Daten auf einer SSD für nichtflüchtigen Speicher.
  • Um die Datenkonsistenz zu gewährleisten, wird die Anwendung herunterskaliert, um neue Schreibvorgänge zu verhindern.
  • Ein Snapshot des nichtflüchtigen Speichers wird erstellt, der als vollständige Sicherung der Daten zu einem bestimmten Zeitpunkt dient.
  • Ein neues Hyperdisk wird aus dem Snapshot bereitgestellt und eine neue MySQL-Instanz wird in einem separaten, Hyperdisk-kompatiblen N4-Knotenpool bereitgestellt. Diese neue Instanz wird an die neu erstellte Hyperdisk angehängt. Damit wird die Migration zum leistungsstärkeren Speicher abgeschlossen.
Architekturdiagramm, das die Migration von MySQL-Daten von Persistent Disk zu Hyperdisk mithilfe eines Snapshots zeigt.
Abbildung 1: Migration von MySQL-Daten von Persistent Disk zu Hyperdisk mithilfe eines Snapshots.

Ziele

In dieser Anleitung erfahren Sie, wie Sie Folgendes tun:

  • MySQL-Cluster bereitstellen
  • Test-Dataset hochladen
  • Erstellen Sie einen Snapshot Ihrer Daten.
  • Erstellen Sie eine Hyperdisk aus dem Snapshot.
  • Starten Sie einen neuen MySQL-Cluster in einem Knotenpool mit einem N4-Maschinentyp, der Hyperdisk unterstützt.
  • Prüfen Sie die Datenintegrität, um zu bestätigen, dass die Migration erfolgreich war.

Kosten

In diesem Dokument verwenden Sie die folgenden kostenpflichtigen Komponenten von Google Cloud:

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

Mit dem Preisrechner können Sie eine Kostenschätzung für Ihre voraussichtliche Nutzung vornehmen.

Neuen Nutzern von Google Cloud steht möglicherweise eine kostenlose Testversion zur Verfügung.

Hinweis

  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.

      IAM aufrufen
    2. Wählen Sie das Projekt aus.
    3. Klicken Sie auf Zugriffsrechte erteilen.
    4. Geben Sie im Feld Neue Hauptkonten Ihre Nutzer-ID ein. Das ist in der Regel die E‑Mail-Adresse eines Google-Kontos.

    5. Wählen Sie in der Liste Rolle auswählen eine Rolle aus.
    6. Klicken Sie auf Weitere Rolle hinzufügen, wenn Sie weitere Rollen zuweisen möchten.
    7. Klicken Sie auf Speichern.
    8. Cloud Shell einrichten

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

        Activate Cloud Shell

        Eine Cloud Shell-Sitzung wird gestartet und eine Eingabeaufforderung wird angezeigt. Das Initialisieren der Sitzung kann einige Sekunden dauern.

      2. Legen Sie ein Standardprojekt fest:

          gcloud config set project PROJECT_ID
        

        Ersetzen Sie PROJECT_ID durch Ihre Projekt-ID.

      3. Umgebung vorbereiten

        1. Legen Sie in Cloud Shell die Umgebungsvariablen für Ihr Projekt, Ihren Standort und Ihr Clusterpräfix fest.

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

          Ersetzen Sie Folgendes:

          • PROJECT_ID: Ihre Google Cloud Projekt-ID.
          • EMAIL_ADDRESS: Ihre E-Mail-Adresse.
          • LOCATION: die Zone, in der Sie Ihre Bereitstellungsressourcen erstellen möchten. Verwenden Sie für diese Anleitung die Zone us-central1-a.
        2. Klonen Sie das Beispielcode-Repository aus GitHub:

          git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
          
        3. Wechseln Sie in das Verzeichnis offline-hyperdisk-migration, um mit dem Erstellen der Bereitstellungsressourcen zu beginnen:

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

        GKE-Cluster und Knotenpools erstellen

        In dieser Anleitung wird der Einfachheit halber ein zonaler Cluster verwendet, da Hyperdisk-Volumes zonale Ressourcen sind und nur innerhalb einer einzelnen Zone zugänglich sind.

        1. Erstellen Sie einen zonalen GKE-Cluster:

          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. Fügen Sie einen Knotenpool mit einem N2-Maschinentyp für die erste MySQL-Bereitstellung hinzu:

          gcloud container node-pools create regular-pool \
              --cluster ${KUBERNETES_CLUSTER_PREFIX}-cluster \
              --machine-type n2-standard-4 \
              --location ${LOCATION} \
              --num-nodes 1
          
        3. Fügen Sie einen Knotenpool mit einem N4-Maschinentyp auf Hyperdisk hinzu, in den die MySQL-Bereitstellung migriert und ausgeführt wird:

          gcloud container node-pools create hyperdisk-pool \
              --cluster ${KUBERNETES_CLUSTER_PREFIX}-cluster \
              --machine-type n4-standard-4 \
              --location ${LOCATION} \
              --num-nodes 1
          
        4. Als Nächstes stellen Sie die Verbindung zum Cluster her:

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

        MySQL auf nichtflüchtigem Speicher bereitstellen

        In diesem Abschnitt stellen Sie eine MySQL-Instanz bereit, die einen nichtflüchtigen Speicher zum Speichern verwendet, und laden sie mit Beispieldaten.

        1. Erstellen und wenden Sie ein StorageClass für Hyperdisk an. Diese StorageClass wird später in der Anleitung verwendet.

          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. Erstellen und stellen Sie eine MySQL-Instanz mit Knotenaffinität bereit, damit Pods auf regular-pool-Knoten geplant werden, und stellen Sie ein nichtflüchtiges SSD-Volume bereit.

          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
          

          Mit diesem Manifest werden eine MySQL-Bereitstellung und ein MySQL-Dienst mit einer dynamisch bereitgestellten Persistent Disk für die Datenspeicherung erstellt. Das Passwort für den Nutzer root lautet migration.

        3. Stellen Sie einen MySQL-Client-Pod bereit, um Daten zu laden und die Datenmigration zu überprüfen:

          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. Stellen Sie eine Verbindung zum Client-Pod her:

          kubectl exec -it mysql-client -- bash
          
        5. Laden Sie in der Client-Pod-Shell das Sakila-Beispieldataset herunter und importieren Sie es:

          # 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. Prüfen Sie, ob die Daten importiert wurden:

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

          Die Ausgabe enthält eine Liste von Tabellen mit Zeilenanzahlen.

          | 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. Beenden Sie die mysql-Sitzung:

          exit;
          
        8. Beenden Sie die Client-Pod-Shell:

          exit
          
        9. Rufen Sie den Namen des für MySQL erstellten PersistentVolume (PV) ab und speichern Sie ihn in einer Umgebungsvariablen:

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

        Daten zu einem Hyperdisk-Volume migrieren

        Sie haben jetzt eine MySQL-Arbeitslast mit Daten, die auf einem SSD-Volume mit nichtflüchtigem Speicher gespeichert sind. In diesem Abschnitt wird beschrieben, wie Sie diese Daten mithilfe eines Snapshots zu einem Hyperdisk-Volume migrieren. Bei dieser Migrationsmethode bleibt auch das ursprüngliche Persistent Disk-Volume erhalten. So können Sie bei Bedarf zur ursprünglichen MySQL-Instanz zurückkehren.

        1. Sie können Snapshots von Laufwerken erstellen, ohne sie von Arbeitslasten zu trennen. Um die Datenintegrität für MySQL zu gewährleisten, müssen Sie jedoch verhindern, dass während der Snapshot-Erstellung neue Schreibvorgänge auf Ihrem Laufwerk erfolgen. Skalieren Sie das MySQL-Deployment auf 0 Replikate herunter, um Schreibvorgänge zu beenden:

          kubectl scale deployment regular-mysql --replicas=0
          
        2. Erstellen Sie einen Snapshot des vorhandenen nichtflüchtigen Speichers:

          gcloud compute disks snapshot ${PV_NAME} --location=${LOCATION} --snapshot-name=original-snapshot --description="snapshot taken from pd-ssd"
          
        3. Erstellen Sie ein neues Hyperdisk-Volume mit dem Namen mysql-recovery aus dem 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. Aktualisieren Sie die Manifestdatei für das wiederhergestellte PV mit Ihrer Projekt-ID:

          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. Erstellen Sie das PersistentVolume (PVC) und den PersistentVolumeClaim aus der neuen Hyperdisk:

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

        Datenmigration prüfen

        Stellen Sie eine neue MySQL-Instanz bereit, die das neu erstellte Hyperdisk-Volume verwendet. Dieser Pod wird im Knotenpool hyperdisk-pool geplant, der aus N4-Knoten besteht.

        1. Stellen Sie die neue MySQL-Instanz bereit:

          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. Stellen Sie noch einmal eine Verbindung zum MySQL-Client-Pod her, um die Datenintegrität zu prüfen:

          kubectl exec -it mysql-client -- bash
          
        3. Stellen Sie im Client-Pod eine Verbindung zur neuen MySQL-Datenbank (recovered-mysql.default) her und prüfen Sie die Daten. Das Passwort lautet migration.

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

          Die Daten sollten mit denen in Ihrer ursprünglichen MySQL-Instanz auf dem nichtflüchtigen Speicher übereinstimmen.

        4. Beenden Sie die mysql-Sitzung:

          exit;
          
        5. Beenden Sie die Client-Pod-Shell:

          exit
          

        Bereinigen

        Damit Ihrem Google Cloud-Konto die in dieser Anleitung verwendeten Ressourcen nicht in Rechnung gestellt werden, löschen Sie entweder das Projekt, das die Ressourcen enthält, oder Sie behalten das Projekt und löschen die einzelnen Ressourcen.

        Projekt löschen

        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.

        Einzelne Ressourcen löschen

        Wenn Sie ein vorhandenes Projekt verwendet haben und es nicht löschen möchten, können Sie die einzelnen Ressourcen löschen:

        1. Legen Sie Umgebungsvariablen für die Bereinigung fest und rufen Sie den Namen des Persistent Disk-Volumes ab, das vom mysql-pv-claim-PersistentVolumeClaim erstellt wurde:

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

          Ersetzen Sie PROJECT_ID durch Ihre Projekt-ID.

        2. Löschen Sie den Snapshot:

          gcloud compute snapshots delete original-snapshot --quiet
          
        3. Löschen Sie den GKE-Cluster:

          gcloud container clusters delete ${KUBERNETES_CLUSTER_PREFIX}-cluster --location=${LOCATION} --quiet
          
        4. Löschen Sie die Persistent Disk- und Hyperdisk-Volumes:

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

        Nächste Schritte