Migrasikan data MySQL Anda dari Persistent Disk ke Hyperdisk menggunakan Pencadangan untuk GKE

Tutorial ini menunjukkan cara memigrasikan aplikasi stateful di GKE dari jenis mesin generasi lama, seperti N2, dengan volume Persistent Disk terlampir, ke jenis mesin generasi baru, seperti N4, dengan volume Hyperdisk terlampir menggunakan Backup for GKE. Untuk mengetahui informasi selengkapnya tentang jenis mesin yang mendukung Hyperdisk, lihat dokumentasi Compute Engine.

Untuk mendemonstrasikan migrasi, tutorial ini menggunakan database Sakila dan database World untuk menyediakan set data contoh. Sakila adalah database contoh yang disediakan oleh MySQL yang merepresentasikan toko penyewaan DVD fiktif. Database World berisi data tentang negara dan kota. Tutorial ini menggunakan dua set data berbeda di seluruh namespace terpisah untuk menyimulasikan lingkungan multi-tenant yang kompleks.

Tutorial ini ditujukan untuk spesialis Penyimpanan dan administrator Penyimpanan yang membuat dan mengalokasikan penyimpanan, serta mengelola keamanan data dan akses data. Untuk mempelajari lebih lanjut peran umum dan contoh tugas yang dirujuk dalam konten, lihat Peran dan tugas pengguna GKE umum. Google Cloud

Arsitektur deployment

Diagram berikut menggambarkan proses penggunaan Backup untuk GKE guna memigrasikan workload MySQL stateful dari Persistent Disk pada jenis mesin N2 ke Hyperdisk pada jenis mesin N4.

  • Cluster asal: dua deployment MySQL berada di namespace terpisah, namespace-a dan namespace-b, di node pool seri mesin N2. Deployment ini menggunakan SSD Persistent Disk untuk penyimpanan data.
  • Strategi pencadangan: Anda mengaktifkan agen Pencadangan untuk GKE di cluster, dan membuat rencana pencadangan untuk merekam namespace, data volume, dan secret. Kemudian, Anda menjalankan pencadangan manual untuk membuat titik pemulihan point-in-time.
  • Transformasi dan pemulihan: Anda menentukan rencana pemulihan dengan menggunakan aturan transformasi untuk menyesuaikan resource bagi lingkungan target. Aturan ini melakukan hal berikut:
    • Tukar StorageClass dari premium-rwo (PD) ke kelas penyimpanan Hyperdisk bernama balanced-storage.
    • Ubah aturan afinitas Pod untuk membantu memastikan bahwa workload yang dipulihkan dijadwalkan di node pool N4 baru.
  • Lingkungan target: Anda menyediakan cluster GKE baru dengan jenis mesin N4. Proses pemulihan membuat ulang disk sebagai volume Hyperdisk dari cadangan dan men-deploy instance MySQL ke node N4 yang kompatibel.
Diagram arsitektur yang menunjukkan migrasi data MySQL dari Persistent Disk ke Hyperdisk menggunakan Pencadangan untuk GKE.
Gambar 1: Migrasi data MySQL dari Persistent Disk ke Hyperdisk menggunakan Backup untuk GKE.

Tujuan

Dalam tutorial ini, Anda akan mempelajari cara melakukan hal-hal berikut:

  • Siapkan aplikasi stateful GKE untuk pencadangan.
  • Aktifkan add-on Backup for GKE.
  • Buat rencana pencadangan dan cadangkan cluster sumber.
  • Buat rencana pemulihan yang menggunakan aturan transformasi untuk memigrasikan penyimpanan ke Hyperdisk.
  • Pulihkan beban kerja ke cluster baru dan verifikasi data.

Biaya

Dalam dokumen ini, Anda akan menggunakan komponen Google Cloudyang dapat ditagih berikut:

Untuk membuat perkiraan biaya berdasarkan proyeksi penggunaan Anda, gunakan kalkulator harga.

Pengguna Google Cloud baru mungkin memenuhi syarat untuk mendapatkan uji coba gratis.

Sebelum memulai

  1. Login ke akun Google Cloud Anda. Jika Anda baru menggunakan Google Cloud, buat akun untuk mengevaluasi performa produk kami dalam skenario dunia nyata. Pelanggan baru juga mendapatkan kredit gratis senilai $300 untuk menjalankan, menguji, dan men-deploy workload.
  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, Backup for GKE, and IAM 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, Backup for GKE, and IAM 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. Pastikan Anda memiliki peran berikut di project: roles/container.admin, roles/iam.serviceAccountAdmin, roles/compute.admin, roles/gkebackup.admin, roles/monitoring.viewer

    Memeriksa peran

    1. Di konsol Google Cloud , buka halaman IAM.

      Buka IAM
    2. Pilih project.
    3. Di kolom Akun utama, temukan semua baris yang mengidentifikasi Anda atau grup yang Anda ikuti. Untuk mengetahui grup mana saja yang Anda ikuti, hubungi administrator Anda.

    4. Untuk semua baris yang menentukan atau menyertakan Anda, periksa kolom Peran untuk melihat apakah daftar peran menyertakan peran yang diperlukan.

    Memberikan peran

    1. Di konsol Google Cloud , buka halaman IAM.

      Buka IAM
    2. Pilih project.
    3. Klik Grant access.
    4. Di kolom New principals, masukkan ID pengguna Anda. Biasanya, ini adalah alamat email untuk Akun Google.

    5. Klik Pilih peran, lalu telusuri peran.
    6. Untuk memberikan peran tambahan, klik Add another role, lalu tambahkan tiap peran tambahan.
    7. Klik Simpan.

Menyiapkan Cloud Shell

  1. Di konsol Google Cloud , aktifkan Cloud Shell.

    Aktifkan Cloud Shell

    Sesi Cloud Shell akan dimulai dan menampilkan perintah command line. Diperlukan waktu beberapa detik untuk melakukan inisialisasi pada sesi.

  2. Setel project default Anda:

      gcloud config set project PROJECT_ID
    

    Ganti PROJECT_ID dengan project ID Anda.

Menyiapkan lingkungan

Di bagian ini, Anda akan menyiapkan variabel lingkungan dan meng-clone repositori contoh.

  1. Tetapkan variabel lingkungan untuk project, nama cluster, dan zona Anda:

    export PROJECT_ID=PROJECT_ID
    export KUBERNETES_CLUSTER_PREFIX=backup-gke-migration
    export TARGET_CLUSTER_PREFIX=restore-gke-migration
    export ZONE=us-central1-a
    

    Ganti PROJECT_ID dengan ID project Google Cloud Anda.

  2. Buat clone repositori kode contoh dan buka direktori:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    cd kubernetes-engine-samples/databases/backup-migration
    

Buat cluster GKE sumber

Buat cluster zona dengan node pool yang menggunakan jenis mesin N2 dan volume Persistent Disk yang terpasang.

  1. Membuat cluster:

    gcloud container clusters create ${KUBERNETES_CLUSTER_PREFIX}-cluster \
      --location ${ZONE} \
      --node-locations ${ZONE} \
      --shielded-secure-boot \
      --shielded-integrity-monitoring \
      --machine-type "e2-micro" \
      --num-nodes "1"
    
  2. Buat node pool dengan jenis mesin n2-standard-4 untuk beban kerja sumber:

    gcloud container node-pools create regular-pool \
      --cluster ${KUBERNETES_CLUSTER_PREFIX}-cluster \
      --machine-type n2-standard-4 \
      --zone ${ZONE} \
      --num-nodes 1
    
  3. Aktifkan add-on Backup for GKE di cluster sumber:

    gcloud container clusters update ${KUBERNETES_CLUSTER_PREFIX}-cluster \
      --project=${PROJECT_ID}  \
      --location=${ZONE} \
      --update-addons=BackupRestore=ENABLED
    
  4. Dapatkan kredensial untuk cluster:

    gcloud container clusters get-credentials ${KUBERNETES_CLUSTER_PREFIX}-cluster --zone ${ZONE}
    
  5. Pastikan agen Backup for GKE diaktifkan:

    gcloud container clusters describe ${KUBERNETES_CLUSTER_PREFIX}-cluster \
      --project=${PROJECT_ID}  \
      --location=${ZONE}
    

    Outputnya akan terlihat mirip dengan berikut ini, dan mengonfirmasi bahwa agen pencadangan diaktifkan:

    addonsConfig:
      gkeBackupAgentConfig:
        enabled: true
    

Men-deploy MySQL dengan data sampel

Deploy dua database MySQL di namespace terpisah untuk menyimulasikan lingkungan produksi.

  1. Buat namespace namespace-a dan namespace-b:

    kubectl create namespace namespace-a
    kubectl create namespace namespace-b
    
  2. Deploy workload MySQL di namespace-a dan namespace-b:

    • Deploy file mysql-a-deployment.yaml:

      kubectl apply -f manifests/02-mysql/mysql-a-deployment.yaml -n namespace-a
      

      Manifes berikut membuat Pod MySQL di namespace-a dengan disk SSD Persistent Disk yang disediakan secara dinamis di node regular-pool. Sandi root ditetapkan ke migration:

      apiVersion: v1
      kind: Service
      metadata:
        name: mysql-a
        labels:
          app: mysql
      spec:
        ports:
          - port: 3306
        selector:
          app: mysql
        clusterIP: None
      ---
      apiVersion: v1
      kind: PersistentVolumeClaim
      metadata:
        name: mysql-a-pv-claim
        labels:
          app: mysql
      spec:
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 30Gi
        storageClassName: premium-rwo
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: existing-mysql-a
        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-a
              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-a-pv-claim
    • Deploy file mysql-b-deployment.yaml:

      kubectl apply -f manifests/02-mysql/mysql-b-deployment.yaml -n namespace-b
      

      Manifes berikut membuat Pod MySQL di namespace-b dengan disk SSD Persistent Disk yang disediakan secara dinamis di node regular-pool. Sandi root ditetapkan ke migration:

      apiVersion: v1
      kind: Service
      metadata:
        name: mysql-b
        labels:
          app: mysql
      spec:
        ports:
          - port: 3306
        selector:
          app: mysql
        clusterIP: None
      ---
      apiVersion: v1
      kind: PersistentVolumeClaim
      metadata:
        name: mysql-b-pv-claim
        labels:
          app: mysql
      spec:
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 30Gi
        storageClassName: premium-rwo
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: existing-mysql-b
        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-b
              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-b-pv-claim
  3. Deploy Pod klien MySQL untuk mengupload set data sampel:

    kubectl apply -f manifests/02-mysql/mysql-client.yaml
    kubectl wait pods mysql-client --for condition=Ready --timeout=300s
    

    Manifes berikut men-deploy Pod klien MySQL:

    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
  4. Hubungkan ke Pod klien:

    kubectl exec -it mysql-client -- bash
    
  5. Di dalam Pod, download set data sampel Sakila dan World:

    curl --output dataset.tgz "https://downloads.mysql.com/docs/sakila-db.tar.gz"
    tar -xvzf dataset.tgz -C ./
    
    curl --output world-db.tar.gz "https://downloads.mysql.com/docs/world-db.tar.gz"
    tar xvzf world-db.tar.gz -C ./
    
  6. Impor set data Sakila ke dalam database mysql-a:

    mysql -u root -h mysql-a.namespace-a -p
    # Enter password: migration
    
    SOURCE /sakila-db/sakila-schema.sql;
    SOURCE /sakila-db/sakila-data.sql;
    
  7. Verifikasi data Sakila yang diimpor:

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

    Keluar dari MySQL:

    exit
    
  8. Impor set data World ke dalam database mysql-b:

    mysql -u root -h mysql-b.namespace-b -p
    # Enter password: migration
    
    SOURCE /world-db/world.sql;
    
  9. Verifikasi data Dunia yang diimpor:

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

    Outputnya mirip dengan hal berikut ini:

    +-----------------+------------+
    | table_name      | table_rows |
    +-----------------+------------+
    | city            |       4079 |
    | country         |        239 |
    | countrylanguage |        984 |
    +-----------------+------------+
    

    Keluar dari MySQL:

    exit
    
  10. Keluar dari shell Pod klien:

    exit
    

Mencadangkan cluster GKE

Mencadangkan seluruh cluster, termasuk secret dan volume.

  1. Buat rencana pencadangan:

    gcloud beta container backup-restore backup-plans create main-plan \
      --project=${PROJECT_ID} \
      --location=us-central1 \
      --cluster=projects/${PROJECT_ID}/locations/${ZONE}/clusters/${KUBERNETES_CLUSTER_PREFIX}-cluster \
      --selected-namespaces=namespace-a,namespace-b,default \
      --include-secrets \
      --include-volume-data \
      --target-rpo-minutes=1440 \
      --backup-retain-days=7 \
      --backup-delete-lock-days=3 \
      --locked
    
    • --selected-namespaces: mencadangkan namespace tertentu untuk menghindari konflik dengan resource sistem.
    • --include-volume-data: membantu memastikan data Persistent Disk dicadangkan.
    • --target-rpo-minutes: mengonfigurasi jadwal pencadangan berbasis Toleransi Jumlah Data yang Hilang (RPO). RPO adalah jangka waktu maksimum yang dapat ditoleransi dengan kemungkinan hilangnya data, dan RPO menentukan frekuensi pencadangan. Dengan 1440 menit (1 hari), pencadangan dijadwalkan untuk berjalan setiap hari.
  2. Buat cadangan:

    gcloud beta container backup-restore backups create first-backup \
        --project=${PROJECT_ID} \
        --location=us-central1 \
        --backup-plan=main-plan \
        --wait-for-completion
    

    Tunggu hingga output menampilkan Backup state: SUCCEEDED.

  3. Pastikan cadangan dibuat:

    gcloud beta container backup-restore backups list \
        --project=${PROJECT_ID} \
        --location=us-central1 \
        --backup-plan=main-plan
    

Pemulihan dengan transformasi Hyperdisk

Pulihkan cadangan ke cluster baru. Pemulihan mengubah penyimpanan dari Persistent Disk ke Hyperdisk dan memindahkan workload ke node N4.

  1. Buat cluster GKE target di node N4:

    gcloud container clusters create ${TARGET_CLUSTER_PREFIX}-cluster \
      --location ${ZONE} \
      --node-locations ${ZONE} \
      --shielded-secure-boot \
      --shielded-integrity-monitoring \
      --machine-type "e2-micro" \
      --num-nodes "1"
    
  2. Buat node pool dengan jenis mesin n4-standard-4, yang diperlukan untuk Hyperdisk:

    gcloud container node-pools create hyperdisk-pool \
      --cluster ${TARGET_CLUSTER_PREFIX}-cluster \
      --machine-type n4-standard-4 \
      --zone ${ZONE} \
      --num-nodes 1
    
  3. Dapatkan kredensial untuk cluster target:

    gcloud container clusters get-credentials ${TARGET_CLUSTER_PREFIX}-cluster --zone ${ZONE}
    
  4. Terapkan Hyperdisk StorageClass bernama balanced-storage:

    kubectl apply -f manifests/01-storage-class/storage-class-hdb.yaml
    

    Manifes berikut menentukan StorageClass Hyperdisk:

    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"
  5. Tinjau aturan transformasi dalam file manifests/03-transformation-rule/volume.yaml. File ini menentukan cara sumber daya diubah selama pemulihan:

    transformationRules:
    - description: Change the StorageClass on PVCs from premium-rwo to balanced-storage
      resourceFilter:
        namespaces: ["namespace-a","namespace-b"]
        groupKinds:
        - resourceGroup: ""
          resourceKind: PersistentVolumeClaim
      fieldActions:
      - op: REPLACE
        path: "/spec/storageClassName"
        value: "balanced-storage"
    - description: Change node type from n2-standard-4 to n4-standard-4
      resourceFilter:
        namespaces: ["namespace-a","namespace-b"]
        jsonPath: ".metadata[?(@.name == 'existing-mysql')]"
        groupKinds:
        - resourceGroup: apps
          resourceKind: Deployment
      fieldActions:
      - op: REPLACE
        path: "/spec/template/spec/affinity/nodeAffinity/preferredDuringSchedulingIgnoredDuringExecution/0/preference/matchExpressions/0/values/0"
        value: "n4-standard-4"
    • Transformasi PVC: mengubah storageClassName menjadi balanced-storage (Hyperdisk).
    • Transformasi deployment: memperbarui afinitas node untuk menjadwalkan Pod di node n4-standard-4.
  6. Buat rencana pemulihan menggunakan aturan transformasi berikut:

    gcloud beta container backup-restore restore-plans create main-restore \
      --project=${PROJECT_ID} \
      --location=us-central1 \
      --backup-plan=projects/${PROJECT_ID}/locations/us-central1/backupPlans/main-plan \
      --cluster=projects/${PROJECT_ID}/locations/${ZONE}/clusters/${TARGET_CLUSTER_PREFIX}-cluster \
      --namespaced-resource-restore-mode=merge-replace-on-conflict \
      --all-namespaces \
      --cluster-resource-conflict-policy=use-existing-version  \
      --cluster-resource-scope-selected-group-kinds=cluster-resource-scope-all-group-kinds \
      --volume-data-restore-policy=restore-volume-data-from-backup \
      --transformation-rules-file=manifests/03-transformation-rule/volume.yaml
    
  7. Lakukan pemulihan:

    gcloud beta container backup-restore restores create first-restore \
       --project=${PROJECT_ID} \
       --location=us-central1 \
       --restore-plan=main-restore \
       --backup=projects/${PROJECT_ID}/locations/us-central1/backupPlans/main-plan/backups/first-backup
    

Memverifikasi migrasi

Pastikan aplikasi berjalan di cluster baru dan data tetap utuh.

  1. Periksa apakah Pod sedang berjalan:

    kubectl get pods -A
    
  2. Hubungkan ke Pod klien MySQL di cluster baru:

    # Verify that the client Pod is running
    kubectl apply -f manifests/02-mysql/mysql-client.yaml
    kubectl wait pods mysql-client --for condition=Ready --timeout=300s
    kubectl exec -it mysql-client -- bash
    
  3. Verifikasi database Sakila yang dipulihkan di namespace-a:

    mysql -u root -h mysql-a.namespace-a -p
    # Password: migration
    
    USE sakila;
    SELECT table_name, table_rows FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'sakila';
    
  4. Verifikasi database World yang dipulihkan di namespace-b:

    mysql -u root -h mysql-b.namespace-b -p
    # Password: migration
    
    USE world;
    SELECT table_name, table_rows FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'world';
    

Pembersihan

Agar tidak perlu membayar biaya pada akun Google Cloud Anda untuk resource yang digunakan dalam tutorial ini, hapus project yang berisi resource tersebut, atau simpan project dan hapus setiap resource.

  1. Hapus cluster GKE:

    gcloud container clusters delete ${KUBERNETES_CLUSTER_PREFIX}-cluster --location ${ZONE} --quiet
    gcloud container clusters delete ${TARGET_CLUSTER_PREFIX}-cluster --location ${ZONE} --quiet
    
  2. Hapus rencana pencadangan dan pemulihan:

    # Delete the restore plan
    gcloud beta container backup-restore restore-plans delete main-restore \
        --project=${PROJECT_ID} \
        --location=us-central1 \
        --quiet
    
    # Delete the Backup
    gcloud beta container backup-restore backups delete first-backup \
        --project=${PROJECT_ID} \
        --location=us-central1 \
        --backup-plan=main-plan \
        --quiet
    
    # Delete the backup plan
    gcloud beta container backup-restore backup-plans delete main-plan \
        --project=${PROJECT_ID} \
        --location=us-central1 \
        --quiet
    

Langkah berikutnya