從檔案系統轉移至 Cloud Storage

本頁說明如何在檔案系統 (內部部署或雲端) 與 Cloud Storage 之間建立移轉工作。

從檔案系統轉移至 Cloud Storage 的作業是代理程式轉移作業,也就是說,您必須在有權存取檔案系統的電腦上安裝軟體代理程式,才能協調轉移作業。

設定權限

建立轉移作業前,您必須為下列實體設定權限:

用於建立轉移作業的使用者帳戶。這是登入 Google Cloud 控制台的帳戶,或是在驗證 `gcloud` CLI 時指定的帳戶。使用者帳戶可以是一般使用者帳戶,也可以是使用者管理的服務帳戶。
Google 代管的服務帳戶 (也稱為服務代理程式),由 Storage 移轉服務使用。這個帳戶通常會透過電子郵件地址識別,格式為 project-PROJECT_NUMBER@storage-transfer-service.iam.gserviceaccount.com
為轉移代理程式提供 Google Cloud權限的轉移代理程式帳戶。轉移代理帳戶會使用安裝這些帳戶的使用者憑證,或使用者代管的服務帳戶憑證進行驗證。

如需操作說明,請參閱「以代理程式為基礎的轉移權限」。

將代理程式安裝到代理程式集區

代理程式式轉移作業會使用軟體代理程式來協調轉移作業。這些代理程式必須安裝在可存取轉移作業中涉及的檔案系統的電腦上。

請勿在服務專員集區名稱或服務專員 ID 前置字元中加入個人識別資訊 (PII) 或安全性資料等機密資訊。資源名稱可能會傳播至其他 Google Cloud 資源的名稱,並可能會公開給專案以外的 Google 內部系統。
  1. 建立代理程式集區。請使用使用者帳戶 使用者帳戶符號 執行這項操作。
  2. 代理程式安裝到代理程式集區。請使用轉移代理帳戶 執行這項操作。

建議您在來源代理程式集區中先使用 3 個代理程式。轉移作業進行中時,請監控轉移速度;您可以在轉移作業進行中將更多服務代管帳戶加入集區。

建議每個代理程式都使用一個 VM,且每個 VM 至少配備 4 個 CPU 和 8 GiB RAM。

轉移作業選項

下列 Storage 移轉服務功能可用於從檔案系統傳輸至 Cloud Storage。

使用資訊清單轉移特定檔案
您可以傳遞檔案清單,讓 Storage 移轉服務採取行動。詳情請參閱「使用資訊清單轉移特定檔案或物件」。
指定儲存空間級別
您可以指定要用於目的地值區的 Cloud Storage 儲存類別。請參閱 StorageClass 選項,瞭解 REST 詳細資訊,或在 Google Cloud CLI 中使用 --custom-storage-class 標記。

請注意,如果目的地值區已啟用 Autoclass,系統會忽略任何儲存空間級別設定。如果啟用自動調整級別功能,轉移至值區的物件一開始會設為 Standard 儲存空間。

保存中繼資料

從檔案系統傳輸檔案時,Storage 移轉服務可以選擇保留特定屬性做為自訂中繼資料。如果這些檔案日後寫回檔案系統,Storage 移轉服務可以將保存的中繼資料轉換回 POSIX 屬性。

如要進一步瞭解可保留哪些中繼資料,以及如何設定轉移作業,請參閱「中繼資料保留」一文的 POSIX 檔案系統轉移作業一節。

管理網路頻寬
Storage 移轉服務預設會使用可用的頻寬,從檔案系統轉移檔案。您可以設定頻寬限制,避免轉移作業影響其他網路流量。頻寬限制會套用至代理程式集區層級。

詳情請參閱「管理網路頻寬」。

您的使用者帳戶必須具備 Storage Transfer Admin (roles/storagetransfer.admin) 角色,才能設定或變更頻寬限制。

記錄
Storage 移轉服務支援 Storage 移轉服務的 Cloud Logging (建議使用),以及以代理程式為基礎的移轉記錄

建立轉移作業

請勿在轉移作業名稱中加入個人識別資訊 (PII) 或安全性資料等機密資訊。資源名稱可能會傳播至其他 Google Cloud 資源的名稱,並可能會公開給專案以外的 Google 內部系統。

Storage 移轉服務提供多種介面,可用於建立移轉作業。

Google Cloud 控制台

  1. 前往 Google Cloud 控制台的「Storage Transfer Service」頁面。

    前往 Storage 移轉服務

  2. 按一下「建立移轉工作」。系統會顯示「Create a transfer job」(建立移轉工作) 頁面。

  3. 選擇「POSIX 檔案系統」做為來源。

  4. 選取「Cloud Storage」做為目的地類型,然後點選「下一步」

  5. 選取現有的服務代理集區,或選取「建立服務代理集區」,然後按照指示建立新集區。

  6. 指定檔案系統目錄的完整路徑。

  7. 點選「下一步」

  8. 在「Bucket or folder」欄位中輸入目的地值區和 (選用) 資料夾名稱,或按一下「Browse」,從目前專案中現有的值區清單中選取值區。如要建立新的值區,請按一下 「值區」圖示「建立新的值區」

  9. 點選「下一步」

  10. 選擇時段設定選項。

  11. 點選「下一步」

  12. 選擇轉移工作的設定。

    • 在「Description」欄位中輸入轉移作業的說明。最佳做法是輸入有意義且不重複的說明,以便區分工作。

    • 在「中繼資料選項」下方,使用預設選項,或更新一或多個值。詳情請參閱「中繼資料保留」一文。

    • 在「何時覆寫」下方,選取下列其中一個選項:

      • 永不:Storage 移轉服務會略過從來源檔案中轉移任何檔案,如果該檔案與目的地檔案同名。

      • 如果不同:如果名稱相同的來源檔案具有不同的 ETag 或總和檢查碼值,則會覆寫目的地檔案。

      • 一律:來源檔案的名稱與目的地檔案相同時,一律會覆寫目的地檔案,即使兩者為相同檔案亦然。

    • 在「刪除時間」下方,選取下列任一選項:

      • 一律不刪除:一律不要從來源或目的地刪除檔案。

      • 轉移後刪除來源檔案:在檔案轉移至目的地後刪除來源檔案。如果來源檔案已存在目的地,系統就不會移轉該檔案,因此不會刪除來源檔案。

      • 如果檔案未同時存在於來源,則將檔案從目的地中刪除:如果目的地 Cloud Storage 值區中的檔案未同時存在於來源,請從 Cloud Storage 值區中刪除檔案。

        這個選項可確保目的地 Cloud Storage 值區與來源完全相符。

    • 選取是否要啟用 Cloud Storage 記錄功能和/或啟用 Cloud Logging 記錄功能。詳情請參閱「檔案系統移轉記錄檔」和「Storage 移轉服務的 Cloud Logging」。

  13. 如要建立轉移工作,請按一下「建立」

gcloud

使用 gcloud 指令前,請先安裝 Google Cloud CLI

如要建立新的轉移工作,請使用 gcloud transfer jobs create 指令。除非指定排程或 --do-not-run,否則建立新工作會啟動指定的轉移作業。

gcloud transfer jobs create \
  posix:///SOURCE \
  gs://DESTINATION/ \
  --source-agent-pool=SOURCE_POOL_NAME

其中:

  • SOURCE 是從檔案系統根目錄的絕對路徑。前置字串為 posix://,因此最終值會包含 3 個正斜線。例如:posix:///tmp/data/

  • DESTINATION 是 Cloud Storage 值區的名稱,以及選用的資料夾路徑,後面加上斜線。例如:gs://example-bucket/data/

  • --source-agent-pool 會指定要用於這項轉移作業的來源代理程式集區。

其他選項包括:

  • --do-not-run 可防止 Storage 移轉服務在提交指令時執行工作。如要執行工作,請更新工作以新增時間表,或使用 jobs run 手動啟動工作。

  • --manifest-file 會指定 Cloud Storage 中 CSV 檔案的路徑,其中包含要從來源轉移的檔案清單。如需瞭解資訊清單檔案格式,請參閱「使用資訊清單轉移特定檔案或物件」。

  • 工作資訊:您可以指定 --name--description

  • 時間表:指定 --schedule-starts--schedule-repeats-every--schedule-repeats-until,或 --do-not-run

  • 移轉選項:指定是否覆寫目的地檔案 (--overwrite-when=differentalways),以及是否在移轉期間或之後刪除特定檔案 (--delete-from=destination-if-uniquesource-after-transfer);指定要保留哪些中繼資料值 (--preserve-metadata);以及視需要在已移轉的物件上設定儲存類別 (--custom-storage-class)。

如要查看所有選項,請執行 gcloud transfer jobs create --help 或參閱 gcloud 參考說明文件。請注意,並非所有選項都支援以代理人為基礎的轉移作業;說明文字會指出哪些選項不支援這項作業。

REST

以下範例說明如何透過 REST API 使用 Storage 移轉服務。

當您使用 Storage Transfer Service API 設定或編輯移轉工作時,時間必須為世界標準時間 (UTC)。如要進一步瞭解如何指定移轉工作時間表,請參閱「時間表」。

如要將檔案從 POSIX 檔案系統移至 Cloud Storage 值區,請使用 transferJobs.create 搭配 posixDataSource

POST https://storagetransfer.googleapis.com/v1/transferJobs
{
 "name":"transferJobs/sample_transfer",
 "description": "My First Transfer",
 "status": "ENABLED",
 "projectId": "my_transfer_project_id",
 "schedule": {
     "scheduleStartDate": {
         "year": 2022,
         "month": 5,
         "day": 2
     },
     "startTimeOfDay": {
         "hours": 22,
         "minutes": 30,
         "seconds": 0,
         "nanos": 0
     }
     "scheduleEndDate": {
         "year": 2022,
         "month": 12,
         "day": 31
     },
     "repeatInterval": {
         "259200s"
     },
 },
 "transferSpec": {
     "posixDataSource": {
          "rootDirectory": "/bar/",
     },
     "sourceAgentPoolName": "my_example_pool",
     "gcsDataSink": {
          "bucketName": "destination_bucket"
          "path": "foo/bar/"
     },
  }
}

schedule 欄位為選用欄位;如果未納入,則必須使用 transferJobs.run 要求啟動轉移工作。

如要在建立工作後查看轉移作業狀態,請使用 transferJobs.get

GET https://storagetransfer.googleapis.com/v1/transferJobs/sample_transfer?project_id=my_transfer_project_id

用戶端程式庫

下列範例說明如何透過 Go、Java、Node.js 和 Python 以程式化方式使用 Storage 移轉服務。

當您以程式化方式設定或編輯移轉工作時,系統時間必須為世界標準時間 (UTC)。如要進一步瞭解如何指定移轉工作時間表,請參閱「時間表」。

如要進一步瞭解 Storage 移轉服務用戶端程式庫,請參閱「Storage 移轉服務用戶端程式庫的使用說明」。

如要將檔案從 POSIX 檔案系統移至 Cloud Storage bucket,請按照下列步驟操作:

Go


import (
	"context"
	"fmt"
	"io"

	storagetransfer "cloud.google.com/go/storagetransfer/apiv1"
	"cloud.google.com/go/storagetransfer/apiv1/storagetransferpb"
)

func transferFromPosix(w io.Writer, projectID string, sourceAgentPoolName string, rootDirectory string, gcsSinkBucket string) (*storagetransferpb.TransferJob, error) {
	// Your project id
	// projectId := "myproject-id"

	// The agent pool associated with the POSIX data source. If not provided, defaults to the default agent
	// sourceAgentPoolName := "projects/my-project/agentPools/transfer_service_default"

	// The root directory path on the source filesystem
	// rootDirectory := "/directory/to/transfer/source"

	// The ID of the GCS bucket to transfer data to
	// gcsSinkBucket := "my-sink-bucket"

	ctx := context.Background()
	client, err := storagetransfer.NewClient(ctx)
	if err != nil {
		return nil, fmt.Errorf("storagetransfer.NewClient: %w", err)
	}
	defer client.Close()

	req := &storagetransferpb.CreateTransferJobRequest{
		TransferJob: &storagetransferpb.TransferJob{
			ProjectId: projectID,
			TransferSpec: &storagetransferpb.TransferSpec{
				SourceAgentPoolName: sourceAgentPoolName,
				DataSource: &storagetransferpb.TransferSpec_PosixDataSource{
					PosixDataSource: &storagetransferpb.PosixFilesystem{RootDirectory: rootDirectory},
				},
				DataSink: &storagetransferpb.TransferSpec_GcsDataSink{
					GcsDataSink: &storagetransferpb.GcsData{BucketName: gcsSinkBucket},
				},
			},
			Status: storagetransferpb.TransferJob_ENABLED,
		},
	}

	resp, err := client.CreateTransferJob(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("failed to create transfer job: %w", err)
	}
	if _, err = client.RunTransferJob(ctx, &storagetransferpb.RunTransferJobRequest{
		ProjectId: projectID,
		JobName:   resp.Name,
	}); err != nil {
		return nil, fmt.Errorf("failed to run transfer job: %w", err)
	}
	fmt.Fprintf(w, "Created and ran transfer job from %v to %v with name %v", rootDirectory, gcsSinkBucket, resp.Name)
	return resp, nil
}

Java

import com.google.storagetransfer.v1.proto.StorageTransferServiceClient;
import com.google.storagetransfer.v1.proto.TransferProto;
import com.google.storagetransfer.v1.proto.TransferTypes.GcsData;
import com.google.storagetransfer.v1.proto.TransferTypes.PosixFilesystem;
import com.google.storagetransfer.v1.proto.TransferTypes.TransferJob;
import com.google.storagetransfer.v1.proto.TransferTypes.TransferSpec;
import java.io.IOException;

public class TransferFromPosix {

  public static void main(String[] args) throws IOException {
    // TODO(developer): Replace these variables before running the sample.

    // Your project id
    String projectId = "my-project-id";

    // The agent pool associated with the POSIX data source. If not provided, defaults to the
    // default agent
    String sourceAgentPoolName = "projects/my-project-id/agentPools/transfer_service_default";

    // The root directory path on the source filesystem
    String rootDirectory = "/directory/to/transfer/source";

    // The ID of the GCS bucket to transfer data to
    String gcsSinkBucket = "my-sink-bucket";

    transferFromPosix(projectId, sourceAgentPoolName, rootDirectory, gcsSinkBucket);
  }

  public static void transferFromPosix(
      String projectId, String sourceAgentPoolName, String rootDirectory, String gcsSinkBucket)
      throws IOException {
    TransferJob transferJob =
        TransferJob.newBuilder()
            .setProjectId(projectId)
            .setTransferSpec(
                TransferSpec.newBuilder()
                    .setSourceAgentPoolName(sourceAgentPoolName)
                    .setPosixDataSource(
                        PosixFilesystem.newBuilder().setRootDirectory(rootDirectory).build())
                    .setGcsDataSink(GcsData.newBuilder().setBucketName(gcsSinkBucket).build()))
            .setStatus(TransferJob.Status.ENABLED)
            .build();

    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests. After completing all of your requests, call
    // the "close" method on the client to safely clean up any remaining background resources,
    // or use "try-with-close" statement to do this automatically.
    try (StorageTransferServiceClient storageTransfer = StorageTransferServiceClient.create()) {

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

      System.out.println(
          "Created a transfer job from "
              + rootDirectory
              + " to "
              + gcsSinkBucket
              + " with "
              + "name "
              + response.getName());
    }
  }
}

Node.js


// Imports the Google Cloud client library
const {
  StorageTransferServiceClient,
} = require('@google-cloud/storage-transfer');

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// Your project id
// const projectId = 'my-project'

// The agent pool associated with the POSIX data source. Defaults to the default agent
// const sourceAgentPoolName = 'projects/my-project/agentPools/transfer_service_default'

// The root directory path on the source filesystem
// const rootDirectory = '/directory/to/transfer/source'

// The ID of the GCS bucket to transfer data to
// const gcsSinkBucket = 'my-sink-bucket'

// Creates a client
const client = new StorageTransferServiceClient();

/**
 * Creates a request to transfer from the local file system to the sink bucket
 */
async function transferDirectory() {
  const createRequest = {
    transferJob: {
      projectId,
      transferSpec: {
        sourceAgentPoolName,
        posixDataSource: {
          rootDirectory,
        },
        gcsDataSink: {bucketName: gcsSinkBucket},
      },
      status: 'ENABLED',
    },
  };

  // Runs the request and creates the job
  const [transferJob] = await client.createTransferJob(createRequest);

  const runRequest = {
    jobName: transferJob.name,
    projectId: projectId,
  };

  await client.runTransferJob(runRequest);

  console.log(
    `Created and ran a transfer job from '${rootDirectory}' to '${gcsSinkBucket}' with name ${transferJob.name}`
  );
}

transferDirectory();

Python

from google.cloud import storage_transfer


def transfer_from_posix_to_gcs(
    project_id: str,
    description: str,
    source_agent_pool_name: str,
    root_directory: str,
    sink_bucket: str,
):
    """Create a transfer from a POSIX file system to a GCS bucket."""

    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'

    # The agent pool associated with the POSIX data source.
    # Defaults to 'projects/{project_id}/agentPools/transfer_service_default'
    # source_agent_pool_name = 'projects/my-project/agentPools/my-agent'

    # The root directory path on the source filesystem
    # root_directory = '/directory/to/transfer/source'

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

    transfer_job_request = storage_transfer.CreateTransferJobRequest(
        {
            "transfer_job": {
                "project_id": project_id,
                "description": description,
                "status": storage_transfer.TransferJob.Status.ENABLED,
                "transfer_spec": {
                    "source_agent_pool_name": source_agent_pool_name,
                    "posix_data_source": {
                        "root_directory": root_directory,
                    },
                    "gcs_data_sink": {"bucket_name": sink_bucket},
                },
            }
        }
    )

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