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.

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