🪶

Cloud SQL (MySQL) のデータをGCS経由で別プロジェクトへ移行する

に公開

はじめに

システム移行や環境分離などで、Google Cloud SQLのデータを別のプロジェクトにあるCloud SQLインスタンスへ移行したいケースがあります。

今回は、Cloud Storage (GCS) を踏み台にして、特定のテーブルをエクスポートし、別プロジェクトのデータベースへインポートする手順をまとめました。

概要

移行の流れは以下の通りです。

  1. ソースプロジェクト:Cloud SQL から GCS バケットへデータをエクスポート
  2. 権限設定:移行先インスタンスのサービスアカウントに、GCSへのアクセス権限を付与
  3. ターゲットプロジェクト:GCS バケットから Cloud SQL へデータをインポート

ソースプロジェクトでのエクスポート

まず、移行元のデータベースからデータをエクスポートします。

GCS バケットの準備
ソースプロジェクトに、一時保存用の GCS バケットを作成します。

エクスポートの実行
移行元のプロジェクトで以下のコマンドを実行します。

gcloud sql export sql [SOURCE_INSTANCE_NAME] gs://[BUCKET_NAME]/export_data.sql \
    --project=[SOURCE_PROJECT_ID] \
    --database=[DATABASE_NAME] \
    --offload \
    --table=[TABLE_NAME1],[TABLE_NAME2]
  • --offload: インスタンスへの負荷を軽減するために別のレプリカ等で実行するオプション(推奨)
  • --table: 特定のテーブルのみを指定する場合に使用します

移行先インスタンスに権限付与

移行先(ターゲット)の Cloud SQL インスタンスが、移行元(ソース)の GCS バケットを読み取れるようにする必要があります。
コマンドラインで実行する手順は以下の通りです。

  1. 移行先 Cloud SQL のサービスアカウントを特定
    ターゲットプロジェクトで以下のコマンドを実行し、インスタンスに紐付いているサービスアカウントのアドレスを取得します。

    gcloud sql instances describe [TARGET_INSTANCE_NAME] \
     --project=[TARGET_PROJECT_ID] \
     --format="value(serviceAccountEmailAddress)"
    

    ※ 出力されたメールアドレス(例:p123456789-abcde@gcp-sa-cloud-sql.iam.gserviceaccount.com)を控えておきます。

  2. GCS バケットへの権限付与
    ソースプロジェクト側で、先ほど取得したサービスアカウントに対して GCS バケットの読み取り権限(Storage オブジェクト閲覧者)を付与します。

    gcloud storage buckets add-iam-policy-binding gs://[BUCKET_NAME] \
     --project=[SOURCE_PROJECT_ID] \
     --member="serviceAccount:[取得したサービスアカウントのメールアドレス]" \
     --role="roles/storage.objectViewer"
    

ターゲットプロジェクトでのインポート

権限設定が完了したら、移行先のインスタンスでインポートを開始します。

インポートの実行
移行先のインスタンスにデータベース(スキーマ)が存在することを確認し、インポートを実行します。

gcloud sql import sql [TARGET_INSTANCE_NAME] gs://[BUCKET_NAME]/export_data.sql \
    --project=[TARGET_PROJECT_ID] \
    --database=[TARGET_DATABASE_NAME]

大規模データ移行時のタイムアウト対策(非同期実行)

データ量が多い場合、通常のコマンド実行では接続タイムアウト(Client-side timeout)が発生し、処理が途中で終了したように見えることがあります。
これを避けるために、--async フラグで非同期実行し、オペレーション ID を追跡して完了まで待機します。

以下は、エクスポート完了を待ってからインポートを開始するシェルスクリプトの例です。

#!/bin/bash

# 変数の設定
SOURCE_PROJECT="source-project-id"
TARGET_PROJECT="target-project-id"
SOURCE_INSTANCE="source-instance"
TARGET_INSTANCE="target-instance"
BUCKET="your-bucket-name"
DB_NAME="your-db-name"

# エクスポートの実行(非同期)
echo "Starting export in $SOURCE_PROJECT"
EXPORT_OP_ID=$(gcloud sql export sql $SOURCE_INSTANCE gs://$BUCKET/data.sql \
    --project=$SOURCE_PROJECT \
    --database=$DB_NAME \
    --offload \
    --async \
    --format="value(name)")

# エクスポートのオペレーション完了を待機
echo "Waiting for export operation: $EXPORT_OP_ID"
gcloud beta sql operations wait $EXPORT_OP_ID \
    --project=$SOURCE_PROJECT \
    --timeout=unlimited

# インポートの実行(非同期)
echo "Starting import in $TARGET_PROJECT"
IMPORT_OP_ID=$(gcloud sql import sql $TARGET_INSTANCE gs://$BUCKET/data.sql \
    --project=$TARGET_PROJECT \
    --database=$DB_NAME \
    --quiet \
    --async \
    --format="value(name)")

# インポートのオペレーション完了を待機
echo "Waiting for import operation: $IMPORT_OP_ID"
gcloud beta sql operations wait $IMPORT_OP_ID \
    --project=$TARGET_PROJECT \
    --timeout=unlimited

echo "Migration completed successfully."
  • --async: コマンドをバックグラウンドで即座に終了させ、オペレーション ID を返します
  • --quiet: 対話型確認メッセージをスキップします
  • gcloud beta sql operations wait: 指定したオペレーションが完了するまでポーリングして待機します
  • --timeout=unlimited: wait コマンド自体のタイムアウト設定を無効にします

まとめ

この手順を自動化スクリプトに組み込むことで、データ移行をスムーズに行うことができます。

  1. エクスポート:ソースプロジェクトで実施(大量データなら --async)
  2. サービスアカウントの特定:gcloud sql instances describe でターゲット側の SA を確認
  3. 権限付与:gcloud storage buckets add-iam-policy-binding でバケット権限を付与
  4. インポート:ターゲットプロジェクトで実施(gcloud beta sql operations wait で完了を捕捉)
レスキューナウテックブログ

Discussion