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

HyperdiskHyperdisk をサポートするマシンタイプの詳細については、 Compute Engine のドキュメントをご覧ください

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

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

デプロイ アーキテクチャ

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

  • 元のクラスタ: 2 つの MySQL Deployment が、N2 マシンシリーズ ノードプールの別々の Namespace(namespace-anamespace-b)に存在します。これらの Deployment は、データ ストレージに SSD 永続ディスクを使用します。
  • バックアップ戦略: クラスタで Backup for GKE エージェントを有効にし、Namespace、ボリュームデータ、シークレットをキャプチャするバックアップ プランを作成します。次に、手動バックアップを実行して、ポイントインタイム リカバリ ポイントを作成します。
  • 変換と復元: 変換ルールを使用して復元プランを定義し、移行先の環境に合わせてリソースを調整します。これらのルールは次のことを行います。
    • StorageClasspremium-rwo(PD)から balanced-storage という名前の Hyperdisk ストレージ クラスに切り替えます。
    • 復元されたワークロードが新しい N4 ノードプールでスケジュールされるように、Pod アフィニティ ルールを変更します。
  • 移行先の環境: N4 マシンタイプを使用して新しい GKE クラスタをプロビジョニングします。復元プロセスでは、バックアップからディスクを Hyperdisk ボリュームとして再作成し、互換性のある N4 ノードに MySQL インスタンスをデプロイします。
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 プロダクトのパフォーマンスを評価してください。 Google Cloud新規のお客様には、ワークロードの実行、テスト、デプロイができる無料クレジット $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. コンソールで、[IAM] ページに移動します。 Google Cloud

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

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

    ロールを付与する

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

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

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

Cloud Shell を設定する

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

    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)に変更します。
    • Deployment 変換: ノード アフィニティを更新して、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
    

次のステップ