Backup for GKE を使用して Persistent Disk から Hyperdisk に MySQL データを移行する

このチュートリアルでは、Backup for GKE を使用して、GKE のステートフル アプリケーションを、Persistent Disk ボリュームがアタッチされた N2 などの古い世代のマシンタイプから、Hyperdisk ボリュームがアタッチされた N4 などの新しい世代のマシンタイプに移行する方法について説明します。Hyperdisk をサポートするマシンタイプの詳細については、Compute Engine のドキュメントをご覧ください。

このチュートリアルでは、移行を説明するために、Sakila データベースWorld データベースを使用してサンプル データセットを提供します。Sakila は、MySQL が提供するサンプル データベースで、架空の DVD レンタルショップを表しています。World データベースには、国と都市に関するデータが含まれています。このチュートリアルでは、複雑なマルチテナント環境をシミュレートするために、別々の Namespace で 2 つの異なるデータセットを使用します。

このチュートリアルは、ストレージの作成と割り当てを行い、データ セキュリティとデータアクセスを管理するストレージ スペシャリストとストレージ管理者を対象としています。 Google Cloudのコンテンツで使用されている一般的なロールとタスクの例の詳細については、一般的な GKE ユーザーのロールとタスクをご覧ください。

デプロイ アーキテクチャ

次の図は、Backup for GKE を使用して、ステートフル MySQL ワークロードを N2 マシンタイプの Persistent Disk から N4 マシンタイプの Hyperdisk に移行するプロセスを示しています。

  • 移行元クラスタ: 2 つの MySQL Deployment が、N2 マシンシリーズのノードプール上の別々の Namespace(namespace-anamespace-b)に存在します。これらのデプロイでは、データ ストレージに SSD 永続ディスクを使用します。
  • バックアップ戦略: クラスタで Backup for GKE エージェントを有効にし、バックアップ プランを作成して、Namespace、ボリュームデータ、シークレットをキャプチャします。次に、手動バックアップを実行して、ポイントインタイム リカバリ ポイントを作成します。
  • 変換と復元: 変換ルールを使用して復元プランを定義し、移行先の環境のリソースを適応させます。これらのルールは次の処理を行います。
    • StorageClasspremium-rwo(PD)から balanced-storage という名前の Hyperdisk ストレージ クラスにスワップします。
    • Pod アフィニティ ルールを変更して、復元されたワークロードが新しい N4 ノードプールにスケジュールされるようにします。
  • 移行先の環境: N4 マシンタイプを使用して新しい GKE クラスタをプロビジョニングします。復元プロセスでは、バックアップからディスクが Hyperdisk ボリュームとして再作成され、MySQL インスタンスが互換性のある N4 ノードにデプロイされます。
Backup for GKE を使用して Persistent Disk から Hyperdisk に MySQL データを移行するアーキテクチャ図。
図 1: Backup for GKE を使用した Persistent Disk から Hyperdisk への MySQL データの移行。

目標

このチュートリアルでは、次の方法について学習します。

  • バックアップ用に GKE ステートフル アプリケーションを準備します。
  • Backup for GKE アドオンを有効にします。
  • バックアップ プランを作成し、ソース クラスタをバックアップします。
  • 変換ルールを使用してストレージを Hyperdisk に移行する復元プランを作成します。
  • ワークロードを新しいクラスタに復元し、データを確認します。

費用

このドキュメントでは、課金対象である次の Google Cloudコンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。

新規の Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

始める前に

  1. Google Cloud アカウントにログインします。 Google Cloudを初めて使用する場合は、 アカウントを作成して、実際のシナリオでの Google プロダクトのパフォーマンスを評価してください。新規のお客様には、ワークロードの実行、テスト、デプロイができる無料クレジット $300 分を差し上げます。
  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. プロジェクトに次のロール(複数の場合あり)が割り当てられていることを確認します。 roles/container.admin、roles/iam.serviceAccountAdmin、roles/compute.admin、roles/gkebackup.admin、roles/monitoring.viewer

    ロールを確認する

    1. Google Cloud コンソールで、[IAM] ページに移動します。

      IAM に移動
    2. プロジェクトを選択します。
    3. [プリンシパル] 列で、自分または自分が所属するグループの行をすべて確認します。所属するグループについては、管理者にお問い合わせください。

    4. 自分のメールアドレスを含む行の [ロール] 列で、ロールのリストに必要なロールが含まれているかどうか確認します。

    ロールを付与する

    1. Google Cloud コンソールで、[IAM] ページに移動します。

      IAM に移動
    2. プロジェクトを選択します。
    3. [ アクセスを許可] をクリックします。
    4. [新しいプリンシパル] フィールドに、ユーザー ID を入力します。 これは通常、Google アカウントのメールアドレスです。

    5. [ロールを選択] をクリックし、ロールを検索します。
    6. 追加のロールを付与するには、 [別のロールを追加] をクリックして各ロールを追加します。
    7. [保存] をクリックします。

Cloud Shell を設定する

  1. Google Cloud コンソールで Cloud Shell をアクティブにします。

    Cloud Shell をアクティブにする

    Cloud Shell セッションが開始し、コマンドライン プロンプトが表示されます。セッションが初期化されるまで数秒かかることがあります。

  2. デフォルト プロジェクトを設定します。

      gcloud config set project PROJECT_ID
    

    PROJECT_ID は、実際のプロジェクト ID に置き換えます。

環境を設定する

このセクションでは、環境変数を準備し、サンプル リポジトリのクローンを作成します。

  1. プロジェクト、クラスタ名、ゾーンの環境変数を設定します。

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

    PROJECT_ID は、実際の Google Cloudプロジェクト ID に置き換えます。

  2. サンプルコード リポジトリのクローンを作成し、ディレクトリに移動します。

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

移行元 GKE クラスタを作成する

N2 マシンタイプを使用し、Persistent Disk ボリュームがアタッチされたノードプールを含むゾーンクラスタを作成します。

  1. クラスタを作成します。

    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. 移行元ワークロード用に n2-standard-4 マシンタイプを使用してノードプールを作成します。

    gcloud container node-pools create regular-pool \
      --cluster ${KUBERNETES_CLUSTER_PREFIX}-cluster \
      --machine-type n2-standard-4 \
      --zone ${ZONE} \
      --num-nodes 1
    
  3. 移行元クラスタで Backup for GKE アドオンを有効にします。

    gcloud container clusters update ${KUBERNETES_CLUSTER_PREFIX}-cluster \
      --project=${PROJECT_ID}  \
      --location=${ZONE} \
      --update-addons=BackupRestore=ENABLED
    
  4. クラスタの認証情報を取得します。

    gcloud container clusters get-credentials ${KUBERNETES_CLUSTER_PREFIX}-cluster --zone ${ZONE}
    
  5. Backup for GKE エージェントが有効になっていることを確認します。

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

    出力は次のようになります。バックアップ エージェントが有効になっていることが確認できます。

    addonsConfig:
      gkeBackupAgentConfig:
        enabled: true
    

サンプルデータを使用して MySQL をデプロイする

本番環境をシミュレートするために、別々の Namespace に 2 つの MySQL データベースをデプロイします。

  1. namespace-a Namespace と namespace-b Namespace を作成します。

    kubectl create namespace namespace-a
    kubectl create namespace namespace-b
    
  2. namespace-anamespace-b に MySQL ワークロードをデプロイします。

    • mysql-a-deployment.yaml ファイルをデプロイします。

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

      次のマニフェストは、regular-pool ノードに動的にプロビジョニングされた Persistent Disk SSD ディスクを使用して、namespace-a に MySQL Pod を作成します。root パスワードが 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
    • mysql-b-deployment.yaml ファイルをデプロイします。

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

      次のマニフェストは、regular-pool ノードに動的にプロビジョニングされた Persistent Disk SSD ディスクを使用して、namespace-b に MySQL Pod を作成します。root パスワードが 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. MySQL クライアント Pod をデプロイして、サンプル データセットをアップロードします。

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

    次のマニフェストは、MySQL クライアント Pod をデプロイします。

    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. クライアント Pod に接続します。

    kubectl exec -it mysql-client -- bash
    
  5. Pod 内で、Sakila と 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. Sakila データセットを 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. インポートされた Sakila データを確認します。

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

    MySQL を終了します。

    exit
    
  8. World データセットを mysql-b データベースにインポートします。

    mysql -u root -h mysql-b.namespace-b -p
    # Enter password: migration
    
    SOURCE /world-db/world.sql;
    
  9. インポートされた World データを確認します。

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

    出力は次のようになります。

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

    MySQL を終了します。

    exit
    
  10. クライアント Pod シェルを終了します。

    exit
    

GKE クラスタをバックアップする

シークレットやボリュームなど、クラスタ全体をバックアップします。

  1. バックアップ プランを作成します。

    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: システム リソースとの競合を回避するために、特定の Namespace をバックアップします。
    • --include-volume-data: Persistent Disk のデータのバックアップを確保します。
    • --target-rpo-minutes: 目標復旧時点(RPO)に基づくバックアップ スケジュールを構成します。RPO は、データが失われる可能性のある最大許容時間枠であり、バックアップ頻度を決定します。1440 分(1 日)の場合、バックアップは毎日実行されるようにスケジュールされます。
  2. バックアップを作成します。

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

    出力に Backup state: SUCCEEDED が表示されるまで待ちます。

  3. バックアップが作成されたことを確認します。

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

Hyperdisk 変換で復元する

バックアップを新しいクラスタに復元します。復元により、ストレージが Persistent Disk から Hyperdisk に変換され、ワークロードが N4 ノードに移動します。

  1. N4 ノードにターゲット GKE クラスタを作成します。

    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. Hyperdisk に必要な n4-standard-4 マシンタイプを使用してノードプールを作成します。

    gcloud container node-pools create hyperdisk-pool \
      --cluster ${TARGET_CLUSTER_PREFIX}-cluster \
      --machine-type n4-standard-4 \
      --zone ${ZONE} \
      --num-nodes 1
    
  3. ターゲット クラスタの認証情報を取得します。

    gcloud container clusters get-credentials ${TARGET_CLUSTER_PREFIX}-cluster --zone ${ZONE}
    
  4. balanced-storage という名前の Hyperdisk StorageClass を適用します。

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

    次のマニフェストは、Hyperdisk StorageClass を定義しています。

    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. manifests/03-transformation-rule/volume.yaml ファイルで変換ルールを確認します。このファイルでは、復元中にリソースがどのように変更されるかを定義します。

    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"
    • PVC 変換: storageClassNamebalanced-storage(Hyperdisk)に変更します。
    • デプロイの変換: ノード アフィニティを更新して、n4-standard-4 ノードで Pod をスケジュールします。
  6. 次の変換ルールを使用して復元プランを作成します。

    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. 復元を実行します。

    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
    

移行を確認する

アプリケーションが新しいクラスタで実行され、データがそのまま残っていることを確認します。

  1. Pod が実行されているかどうかを確認します。

    kubectl get pods -A
    
  2. 新しいクラスタの MySQL クライアント Pod に接続します。

    # 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. namespace-a で復元された Sakila データベースを確認します。

    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. namespace-b で復元された World データベースを確認します。

    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';
    

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。

  1. GKE クラスタを削除します。

    gcloud container clusters delete ${KUBERNETES_CLUSTER_PREFIX}-cluster --location ${ZONE} --quiet
    gcloud container clusters delete ${TARGET_CLUSTER_PREFIX}-cluster --location ${ZONE} --quiet
    
  2. バックアップ プランと復元プランを削除します。

    # 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
    

次のステップ