Cloud Storage バケット間の転送

Storage Transfer Service を使用すると、同じ Google Cloud プロジェクト内、異なるプロジェクト間、さらに Cloud Storage バケット間でも大量のデータを転送できます。

バケットの移行は、さまざまなシナリオにおいて有用です。たとえば、個別のプロジェクトからのデータを統合したり、データをバックアップのロケーションに移動する場合に使用できます。また、データのロケーションを変更する場合にも使用できます。

Storage Transfer Service の用途

Google Cloud では、Cloud Storage バケット間でデータを転送するための複数のオプションが用意されています。次のガイドラインに従うことをおすすめします。

  • 1 TB 未満のデータ転送: gsutil または gcloud を使用します。手順については、バケットの移動と名前の変更をご覧ください。

  • 1 TB を超えるデータ転送: Storage Transfer Service を使用します。Storage Transfer Service は、すぐに使用できるセキュリティ、信頼性、パフォーマンスを提供するマネージド転送オプションです。これにより、スクリプトの最適化や保守、再試行の処理を行う必要がなくなります。

このガイドでは、Storage Transfer Service を使用して Cloud Storage バケット間でデータを転送する際のベスト プラクティスについて説明します。

転送方法を定義する

転送方法は、状況の複雑さによって異なります。計画を作成する際は、次の点を考慮してください。

バケット名を選択する

別の場所にあるストレージ バケットにデータを移動するには、次のいずれかの方法を選択します。

  • 新しいバケット名を指定する。別の名前のストレージ バケットを参照するようにアプリケーションを更新します。
  • バケット名を維持する。ストレージ バケットを置き換えて現在の名前を維持します。アプリケーションを更新する必要はありません。

どちらの場合もダウンタイムを計画し、ダウンタイムが発生することをユーザーに適切に通知する必要があります。次の説明を確認して、最適な選択肢を選択してください。

新しいバケット名

現在のバケットを使用するすべてのコードとサービスを新しいバケット名で更新する必要があります。この方法は、アプリケーションの構築方法とデプロイ方法によって異なります。

一部の設定では、この方法でダウンタイムが短縮される可能性がありますが、スムーズな移行を実現するために、多くの作業が必要になります。次の作業を行います。

  1. 新しいストレージ バケットにデータをコピーする。
  2. ダウンタイムを開始する。
  3. 新しいバケットを参照するようにアプリケーションを更新する。
  4. すべてが想定どおりに動作することを確認する。関連するすべてのシステムとアカウントがバケットにアクセスできることを確認する。
  5. 元のバケットを削除する。
  6. ダウンタイムを終了する。

バケット名を維持する

新しいバケット名を参照するようにコードを変更しない場合は、この方法を使用します。次の作業を行います。

  1. 一時ストレージ バケットにデータをコピーする。
  2. ダウンタイムを開始する。
  3. 元のバケットを削除する。
  4. 元のバケットと同じ名前の新しいバケットを作成する。
  5. 一時バケットから新しいバケットにデータをコピーする。
  6. 一時バケットを削除する。
  7. すべてが想定どおりに動作することを確認する。関連するすべてのシステムとアカウントがバケットにアクセスできることを確認する。
  8. ダウンタイムを終了する。

ダウンタイムを最小化する

Storage Transfer Service は、転送中に転送元バケットまたは転送先バケットに対する読み取りまたは書き込みをロックしません。

バケットの読み取り / 書き込みを手動でロックする場合は、2 段階(シードと同期)でデータを転送することで、ダウンタイムを最小限に抑えることができます。

  1. シード転送: ソースに対して読み取り / 書き込みをロックすることなく、一括転送を実行します。

  2. 同期転送: 最初の実行が完了したら、ソースバケットで読み取り / 書き込みオペレーションをロックし、別の転送を実行します。Storage Transfer Service の転送はデフォルトで増分的であるため、この 2 回目の転送では、シード転送中に変更されたデータのみが転送されます。

転送速度を最適化する

転送ジョブにかかる時間を見積もるときは、考えられるボトルネックを考慮してください。たとえば、ソースに数十億の小さなファイルがある場合、転送速度は QPS の制約を受けます。オブジェクトのサイズが大きいと、帯域幅がボトルネックになるおそれがあります。

帯域幅の上限はリージョン レベルで設定され、すべてのプロジェクトに公平に割り当てられます。十分な帯域幅がある場合、Storage Transfer Service は 1 秒あたり約 1,000 個のタスクを処理できます。この場合、たとえば、包含接頭辞と除外接頭辞を使用して特定のファイルを転送するなど、ジョブを複数の小さな転送ジョブに分割することで転送を高速化できます。

ロケーション、ストレージ クラス、暗号鍵が同じである場合、Storage Transfer Service はバイトの新しいコピーを作成しません。代わりに転送元 blob を指す新しいメタデータ エントリを作成します。その結果、大規模なコーパスの同じロケーションとクラスのコピーが QPS の制約内で非常に迅速に完了します。

削除もメタデータのみのオペレーションになります。このような転送では、転送を複数の小さなジョブに分割して並列処理することで、速度が向上します。

メタデータを保持する

次のオブジェクト メタデータは、Storage Transfer Service を使用して Cloud Storage バケット間でデータを転送するときに保持されます。

  • ユーザー作成のカスタム メタデータ
  • Cache-Control、Content-Disposition、Content-Type、Custom-Time などの Cloud Storage 固定キー メタデータ フィールド。
  • オブジェクト サイズ。
  • 世代番号は、キー x-goog-reserved-source-generation を持つカスタム メタデータ フィールドとして保持され、後で編集や削除ができます。

API を使用して転送する場合、必要に応じて次のメタデータ フィールドを保持できます。

  • ACL(acl
  • ストレージ クラス(storageClass
  • CMEK(kmsKey
  • 一時保留(temporaryHold
  • オブジェクトの作成日時(customTime

詳しくは、TransferSpec API リファレンスをご覧ください。

次のメタデータ フィールドは保持されません。

  • 最終更新時刻(updated
  • etag
  • componentCount

保持する場合、オブジェクト作成時間はカスタム フィールド customTime として保存されます。オブジェクトの updated 時間は転送時にリセットされるため、オブジェクトのストレージ クラスで費やされた時間もリセットされます。つまり、早期削除の料金が発生しないように、転送後、Coldline Storage のオブジェクトは転送先で 90 日間存在する必要があります。

customTime を使用して、createTime ベースのライフサイクル ポリシーを適用できます。既存の customTime 値は上書きされます。

保持される内容と保持されない内容の詳細については、メタデータの保持をご覧ください。

バージョニングされたオブジェクトを処理する

最新のストレージ オブジェクトだけでなく、すべてのバージョンのストレージ オブジェクトの転送を行う場合は、gcloud CLI または REST API と Storage Transfer Service のマニフェスト機能を使用して、データを転送する必要があります。

すべてのオブジェクト バージョンを転送するには:

  1. バケット オブジェクトを一覧表示して、JSON ファイルにコピーします。

    gcloud storage ls --all-versions --recursive --json [SOURCE_BUCKET] > object-listing.json
    

    このコマンドは通常、1 秒あたり約 1,000 個のオブジェクトをリストします。

  2. JSON ファイルを 2 つの CSV ファイルに分割します。1 つは非現行バージョンのファイルで、もう 1 つはライブ バージョンのファイルです。

    jq -r '.[] | select( .type=="cloud_object" and (.metadata | has("timeDeleted") | not)) | [.metadata.name, .metadata.generation] | @csv' object-listing.json > live-object-manifest.csv
    jq -r '.[] | select( .type=="cloud_object" and (.metadata | has("timeDeleted"))) | [.metadata.name, .metadata.generation] | @csv' object-listing.json > non-current-object-manifest.csv
    
  3. 転送先のバケットでオブジェクトのバージョニングを有効にします

  4. non-current-object-manifest.csv マニフェスト ファイルを transferManifest フィールドの値として渡すことにより、最初に非現行バージョンを転送します。

  5. 次に、マニフェスト ファイルとして live-object-manifest.csv を指定して、同じ方法でライブ バージョンを転送します。

転送オプションを構成する

転送を設定するときに使用できるオプションは次のとおりです。

  • ロギング: Cloud Logging では、個々のオブジェクトの詳細なログが記録されます。このログを使用して、転送のステータスを確認し、追加データの整合性チェックを実行できます。

  • フィルタリング: 包含接頭辞と除外接頭辞を使用して、Storage Transfer Service の対象オブジェクトを制限できます。このオプションを使用すると、転送を複数の転送ジョブに分割し、並列実行できるようになります。詳細については、転送速度を最適化するをご覧ください。

  • 転送オプション: 転送先バケット内の既存のアイテムを上書きするように転送を構成できます。この方法で、転送セットに存在しない転送先のオブジェクトを削除することも、転送されたオブジェクトを転送元から削除することもできます。

データを転送する

転送方法を定義したら転送を実行できます。

新しいバケットを作成する

転送を開始する前に、ストレージ バケットを作成します。適切なバケットのロケーションについては、ロケーションに関する考慮事項をご覧ください。

新しいバケットを作成するときに、いくつかのバケット メタデータをコピーすることをおすすめします。転送元バケットのメタデータを表示する方法については、バケット メタデータの取得をご覧ください。これにより、新しいバケットに同じ設定を適用できるようになります。

新しいバケットにオブジェクトをコピーする

Google Cloud コンソール、gcloud CLI、REST API、またはクライアント ライブラリを使用して、転送元バケットから新しいバケットにオブジェクトをコピーできます。どの方法を選択するかは転送方法によって異なります。

次の手順は、バケット間でオブジェクトを転送する基本的なユースケースを想定しているため、ニーズに合わせて変更する必要があります。

転送ジョブ名に、個人を特定できる情報(PII)やセキュリティ データなどの機密情報を含めないでください。リソース名は、他の Google Cloud リソースの名前に反映され、プロジェクト外部の Google 内部システムに公開される場合があります。

Google Cloud コンソール

Google Cloud コンソールから Cloud Storage Transfer Service を使用します。

  1. Google Cloud コンソールで [転送] ページを開きます。

    [転送] ページを開く

  2. [転送ジョブを作成] をクリックします。
  3. 段階的チュートリアルに沿って、各手順を完了するごとに [次のステップ] をクリックします。

    • 開始: Google Cloud Storage参照元の種類宛先の種類の両方として使用します。

    • 転送元の選択: 目的のバケットの名前を直接入力するか、[参照] をクリックして必要なバケットを選択します。

    • 転送先の選択: 目的のバケットの名前を直接入力するか、[参照] をクリックして必要なバケットを選択します。

    • 設定の選択: [転送後にファイルをソースから削除する] オプションを選択します。

    • スケジュールのオプション: このセクションは無視してください。

  4. 段階的なチュートリアルの完了後、[作成] をクリックします。

    これで古いバケットから新しいバケットへのオブジェクトのコピーが開始されます。この処理には時間がかかる場合がありますが、[作成] をクリックしたら Google Cloud コンソールから移動しても構いません。

    転送の進行状況を確認するには:

    Google Cloud コンソールで [転送] ページを開きます。

    [転送] ページを開く

    Google Cloud コンソールで失敗した Storage Transfer Service オペレーションに関する詳細なエラー情報を確認する方法については、トラブルシューティングをご覧ください。

  5. 設定時に [転送完了後に転送元オブジェクトを削除する] チェックボックスをオンにしていれば、転送が完了した後、古いバケットからオブジェクトを削除するために必要な操作はありません。ただし、古いバケットを削除することもできます。その場合は別途行う必要があります。

gcloud CLI

gcloud CLI をインストールする

まだインストールしていない場合は、gcloud コマンドライン ツールをインストールします

次に、gcloud init を呼び出してツールを初期化し、プロジェクト ID とユーザー アカウントを指定します。詳細については、Cloud SDK の初期化をご覧ください。

gcloud init

宛先フォルダにサービス アカウントを追加する

転送を作成する前に、Storage Transfer Service サービス アカウントを宛先バケットに追加する必要があります。その場合は、gsutil iam ch を使用します。

gsutil iam ch serviceAccount:project-12345678@storage-transfer-service.iam.gserviceaccount.com:roles/storage.admin gs://bucket_name

Google Cloud コンソールまたは API の使用手順については、Cloud Storage ドキュメントの IAM 権限の使用をご覧ください。

転送ジョブを作成する

新しい転送ジョブを作成するには、gcloud transfer jobs create コマンドを使用します。スケジュールまたは --do-not-run が指定されていない限り、新しいジョブを作成すると、指定された転送が開始します。

gcloud transfer jobs create SOURCE DESTINATION

ここで

  • SOURCE は、この転送のデータソース(gs://BUCKET_NAME 形式)です。

  • DESTINATION は、新しいバケットです。形式は gs://BUCKET_NAME です。

上記以外に次のようなオプションがあります。

  • ジョブ情報: --name--description を指定できます。

  • スケジュール: --schedule-starts--schedule-repeats-every--schedule-repeats-until、または --do-not-run を指定します。

  • オブジェクト条件: 条件を使用して、転送するオブジェクトを決定します。これには、--include-prefixes--exclude-prefixes--include-modified-[before | after]-[absolute | relative] の時間ベースの条件が含まれます。

  • 転送オプション: 宛先ファイルを上書きするかどうか(--overwrite-when=different または always)、転送中または転送後に特定のファイルを削除するかどうか(--delete-from=destination-if-unique または source-after-transfer)を指定します。[保持するメタデータ値] メタデータを指定することや、転送されたオブジェクトにストレージ クラスを設定することもできます(--custom-storage-class)。

  • 通知: --notification-pubsub-topic--notification-event-types--notification-payload-format を使用して、転送の Pub/Sub 通知を構成します。

すべてのオプションを表示するには、gcloud transfer jobs create --help を実行します。

たとえば、接頭辞 folder1 が付いたすべてのオブジェクトを転送するには、次のコマンドを実行します。

gcloud transfer jobs create gs://old-bucket gs://new-bucket \
  --include-prefixes="folder1/"

REST

この例では、Cloud Storage バケット間でファイルを移動する方法について説明します。たとえば、別のロケーションのバケットにデータを移動できます。

transferJobs create を使ってリクエストします。

POST https://storagetransfer.googleapis.com/v1/transferJobs
{
  "description": "YOUR DESCRIPTION",
  "status": "ENABLED",
  "projectId": "PROJECT_ID",
  "schedule": {
      "scheduleStartDate": {
          "day": 1,
          "month": 1,
          "year": 2025
      },
      "startTimeOfDay": {
          "hours": 1,
          "minutes": 1
      },
      "scheduleEndDate": {
          "day": 1,
          "month": 1,
          "year": 2025
      }
  },
  "transferSpec": {
      "gcsDataSource": {
          "bucketName": "GCS_SOURCE_NAME"
      },
      "gcsDataSink": {
          "bucketName": "GCS_SINK_NAME"
      },
      "transferOptions": {
          "deleteObjectsFromSourceAfterTransfer": true
      }
  }
}

レスポンス:

200 OK
{
  "transferJob": [
      {
          "creationTime": "2015-01-01T01:01:00.000000000Z",
          "description": "YOUR DESCRIPTION",
          "name": "transferJobs/JOB_ID",
          "status": "ENABLED",
          "lastModificationTime": "2015-01-01T01:01:00.000000000Z",
          "projectId": "PROJECT_ID",
          "schedule": {
              "scheduleStartDate": {
                  "day": 1,
                  "month": 1,
                  "year": 2015
              },
              "startTimeOfDay": {
                  "hours": 1,
                  "minutes": 1
              }
          },
          "transferSpec": {
              "gcsDataSource": {
                  "bucketName": "GCS_SOURCE_NAME",
              },
              "gcsDataSink": {
                  "bucketName": "GCS_NEARLINE_SINK_NAME"
              },
              "objectConditions": {
                  "minTimeElapsedSinceLastModification": "2592000.000s"
              },
              "transferOptions": {
                  "deleteObjectsFromSourceAfterTransfer": true
              }
          }
      }
  ]
}

クライアント ライブラリ

この例では、Cloud Storage バケット間でファイルを移動する方法について説明します。たとえば、別のロケーションのバケットにデータを複製できます。

Storage Transfer Service クライアント ライブラリの詳細については、Storage Transfer Service クライアント ライブラリ スタートガイドをご覧ください。

Java

古いサンプルをお探しの場合Storage Transfer Service 移行ガイドをご覧ください。

import com.google.protobuf.Duration;
import com.google.storagetransfer.v1.proto.StorageTransferServiceClient;
import com.google.storagetransfer.v1.proto.TransferProto.CreateTransferJobRequest;
import com.google.storagetransfer.v1.proto.TransferTypes.GcsData;
import com.google.storagetransfer.v1.proto.TransferTypes.ObjectConditions;
import com.google.storagetransfer.v1.proto.TransferTypes.Schedule;
import com.google.storagetransfer.v1.proto.TransferTypes.TransferJob;
import com.google.storagetransfer.v1.proto.TransferTypes.TransferJob.Status;
import com.google.storagetransfer.v1.proto.TransferTypes.TransferOptions;
import com.google.storagetransfer.v1.proto.TransferTypes.TransferSpec;
import com.google.type.Date;
import com.google.type.TimeOfDay;
import java.io.IOException;
import java.util.Calendar;

public class TransferToNearline {
  /**
   * Creates a one-off transfer job that transfers objects in a standard GCS bucket that are more
   * than 30 days old to a Nearline GCS bucket.
   */
  public static void transferToNearline(
      String projectId,
      String jobDescription,
      String gcsSourceBucket,
      String gcsNearlineSinkBucket,
      long startDateTime)
      throws IOException {

    // Your Google Cloud Project ID
    // String projectId = "your-project-id";

    // A short description of this job
    // String jobDescription = "Sample transfer job of old objects to a Nearline GCS bucket.";

    // The name of the source GCS bucket to transfer data from
    // String gcsSourceBucket = "your-gcs-source-bucket";

    // The name of the Nearline GCS bucket to transfer old objects to
    // String gcsSinkBucket = "your-nearline-gcs-bucket";

    // What day and time in UTC to start the transfer, expressed as an epoch date timestamp.
    // If this is in the past relative to when the job is created, it will run the next day.
    // long startDateTime =
    //     new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2000-01-01 00:00:00").getTime();

    // Parse epoch timestamp into the model classes
    Calendar startCalendar = Calendar.getInstance();
    startCalendar.setTimeInMillis(startDateTime);
    // Note that this is a Date from the model class package, not a java.util.Date
    Date date =
        Date.newBuilder()
            .setYear(startCalendar.get(Calendar.YEAR))
            .setMonth(startCalendar.get(Calendar.MONTH) + 1)
            .setDay(startCalendar.get(Calendar.DAY_OF_MONTH))
            .build();
    TimeOfDay time =
        TimeOfDay.newBuilder()
            .setHours(startCalendar.get(Calendar.HOUR_OF_DAY))
            .setMinutes(startCalendar.get(Calendar.MINUTE))
            .setSeconds(startCalendar.get(Calendar.SECOND))
            .build();

    TransferJob transferJob =
        TransferJob.newBuilder()
            .setDescription(jobDescription)
            .setProjectId(projectId)
            .setTransferSpec(
                TransferSpec.newBuilder()
                    .setGcsDataSource(GcsData.newBuilder().setBucketName(gcsSourceBucket))
                    .setGcsDataSink(GcsData.newBuilder().setBucketName(gcsNearlineSinkBucket))
                    .setObjectConditions(
                        ObjectConditions.newBuilder()
                            .setMinTimeElapsedSinceLastModification(
                                Duration.newBuilder().setSeconds(2592000 /* 30 days */)))
                    .setTransferOptions(
                        TransferOptions.newBuilder().setDeleteObjectsFromSourceAfterTransfer(true)))
            .setSchedule(Schedule.newBuilder().setScheduleStartDate(date).setStartTimeOfDay(time))
            .setStatus(Status.ENABLED)
            .build();

    // Create a Transfer Service client
    StorageTransferServiceClient storageTransfer = StorageTransferServiceClient.create();

    // Create the transfer job
    TransferJob response =
        storageTransfer.createTransferJob(
            CreateTransferJobRequest.newBuilder().setTransferJob(transferJob).build());

    System.out.println("Created transfer job from standard bucket to Nearline bucket:");
    System.out.println(response.toString());
  }
}

Python

古いサンプルをお探しの場合Storage Transfer Service 移行ガイドをご覧ください。

from datetime import datetime

from google.cloud import storage_transfer
from google.protobuf.duration_pb2 import Duration

def create_daily_nearline_30_day_migration(
    project_id: str,
    description: str,
    source_bucket: str,
    sink_bucket: str,
    start_date: datetime,
):
    """Create a daily migration from a GCS bucket to a Nearline GCS bucket
    for objects untouched for 30 days."""

    client = storage_transfer.StorageTransferServiceClient()

    # The ID of the Google Cloud Platform Project that owns the job
    # project_id = 'my-project-id'

    # A useful description for your transfer job
    # description = 'My transfer job'

    # Google Cloud Storage source bucket name
    # source_bucket = 'my-gcs-source-bucket'

    # Google Cloud Storage destination bucket name
    # sink_bucket = 'my-gcs-destination-bucket'

    transfer_job_request = storage_transfer.CreateTransferJobRequest(
        {
            "transfer_job": {
                "project_id": project_id,
                "description": description,
                "status": storage_transfer.TransferJob.Status.ENABLED,
                "schedule": {
                    "schedule_start_date": {
                        "day": start_date.day,
                        "month": start_date.month,
                        "year": start_date.year,
                    }
                },
                "transfer_spec": {
                    "gcs_data_source": {
                        "bucket_name": source_bucket,
                    },
                    "gcs_data_sink": {
                        "bucket_name": sink_bucket,
                    },
                    "object_conditions": {
                        "min_time_elapsed_since_last_modification": Duration(
                            seconds=2592000  # 30 days
                        )
                    },
                    "transfer_options": {
                        "delete_objects_from_source_after_transfer": True
                    },
                },
            }
        }
    )

    result = client.create_transfer_job(transfer_job_request)
    print(f"Created transferJob: {result.name}")

コピーされたオブジェクトを確認する

転送が完了したら、追加データの整合性チェックを実行することをおすすめします。

  • チェックサムやサイズなど、オブジェクトのメタデータを確認して、オブジェクトが正しくコピーされたことを確認します。

  • オブジェクトの正しいバージョンがコピーされていることを確認します。Storage Transfer Service には、オブジェクトのコピーの検証にすぐに利用できるオプションが用意されています。ロギングを有効にしている場合は、ログを表示して、すべてのオブジェクトが正常にコピーされたかどうか、それに対応するメタデータ フィールドがあるかどうかを確認します。

宛先バケットの使用を開始する

移行が完了したら、既存のアプリケーションまたはワークロードを更新して、ターゲット バケット名を使用するようにします。Cloud Audit Logsデータアクセス ログをチェックして、オペレーションによるオブジェクトの変更と読み取りが正しく行われていることを確認します。

元のバケットを削除する

すべて正常に機能したら、元のバケットを削除します。

Storage Transfer Service では、ジョブ構成で deleteObjectsFromSourceAfterTransfer: true を指定するか、Google Cloud コンソールでオプションを選択して、転送後にオブジェクトを削除できます。

オブジェクトの削除をスケジュールする

オブジェクトの削除をスケジュールするには、スケジュールされた転送ジョブdeleteObjectsUniqueInSink = true オプションを組み合わせて使用します。

転送ジョブでは、空のバケットが、オブジェクトを含むバケットに転送されるように設定する必要があります。これにより、Storage Transfer Service でオブジェクトを一覧表示し、削除を開始できます。削除はメタデータのみのオペレーションであるため、転送ジョブは QPS の制約を受けます。プロセスを高速化するには、それぞれが異なる接頭辞のセットを処理するように、転送を複数のジョブに分割します。

また、Google Cloud のマネージド cron ジョブ スケジューラを使用することもできます。詳細については、Cloud Scheduler を使用して Google Cloud STS 転送ジョブをスケジュールするをご覧ください。