매니페스트를 사용하여 특정 파일 또는 객체 전송

Storage Transfer Service는 매니페스트를 사용하여 지정된 특정 파일 또는 객체의 전송을 지원합니다. 매니페스트는 Cloud Storage에 업로드되는 CSV 파일로, Storage Transfer Service가 작업할 파일 또는 객체 목록이 포함됩니다.

매니페스트는 다음 전송에 사용할 수 있습니다.

  • AWS S3, Azure Blobstore 또는 Cloud Storage에서 Cloud Storage 버킷으로

  • 파일 시스템에서 Cloud Storage 버킷으로

  • S3 호환 스토리지에서 Cloud Storage 버킷으로

  • Cloud Storage 버킷에서 파일 시스템으로

  • 두 파일 시스템 간

  • 공개적으로 액세스 가능한 HTTP/HTTPS 소스에서 Cloud Storage 버킷으로 URL 목록에서 매니페스트 형식이 고유하므로 URL 목록 만들기의 안내를 따르세요.

매니페스트 만들기

매니페스트는 CSV 형식이어야 하며 UTF-8 문자를 포함할 수 있습니다. 첫 번째 열은 파일 이름 또는 문자열로 지정된 객체 이름이어야 합니다.

매니페스트 파일은 와일드 카드를 지원하지 않습니다. 값은 특정 파일 또는 객체 이름이어야 합니다. 파일 또는 객체 이름이 없는 폴더 이름은 지원되지 않습니다.

최대 매니페스트 파일 크기는 1GiB로, 이는 약 100만 개의 행에 해당됩니다. 1GiB를 초과하는 매니페스트 파일을 전송해야 하는 경우 여러 파일로 분할하고 전송 작업을 여러 번 실행하면 됩니다.

파일 또는 객체 이름에 쉼표가 포함된 경우 CSV 표준에 따라 이름을 큰따옴표로 묶어야 합니다. 예를 들면 "object1,a.txt"입니다.

구성 오류로 인해 불필요한 API 호출이 발생하지 않도록 파일 또는 객체의 소규모 하위 집합으로 전송을 테스트하는 것이 좋습니다.

전송 작업 페이지에서 파일 전송 상태를 모니터링할 수 있습니다. 전송하지 못한 파일 또는 객체는 전송 로그에 나열됩니다.

파일 시스템 전송

파일 시스템에 파일 매니페스트를 만들려면 전송 작업 생성에 지정된 루트 디렉터리를 기준으로 파일 경로가 포함된 단일 열이 있는 CSV 파일을 만듭니다.

예를 들어 다음 파일 시스템 파일을 전송할 수 있습니다.

파일 경로
rootdir/dir1/subdir1/file1.txt
rootdir/file2.txt
rootdir/dir2/subdir1/file3.txt

매니페스트는 다음 예시와 같이 표시됩니다.

dir1/subdir1/file1.txt
file2.txt
dir2/subdir1/file3.txt

객체 스토리지 전송

객체 매니페스트를 만들려면 첫 번째 열에 전송 작업 생성에 지정된 버킷 이름과 경로와 관련된 객체 이름을 포함하는 CSV 파일을 만듭니다. 모든 객체가 동일한 버킷에 있어야 합니다.

전송할 특정 버전의 Cloud Storage 세대 번호를 사용하여 선택적인 보조 열을 지정할 수도 있습니다.

예를 들어 다음 객체를 전송할 수 있습니다.

개체 경로 Cloud Storage 세대 번호
SOURCE_PATH/object1.pdf 1664826685911832
SOURCE_PATH/object2.pdf
SOURCE_PATH/object3.pdf 1664826610699837

매니페스트는 다음 예시와 같이 표시됩니다.

object1.pdf,1664826685911832
object2.pdf
object3.pdf,1664826610699837

파일 이름과 .csv 확장자를 사용하여 매니페스트 파일을 저장합니다.

HTTP/HTTPS 전송

HTTP 또는 HTTPS 소스에서 특정 파일을 전송하려면 URL 목록 만들기의 안내를 참조하세요.

매니페스트 게시

매니페스트를 만든 후에는 Storage Transfer Service에서 사용할 수 있도록 게시해야 합니다. Storage Transfer Service는 Cloud Storage 버킷 또는 파일 시스템에서 이 파일에 액세스할 수 있습니다.

Cloud Storage에 매니페스트 업로드

매니페스트 파일은 모든 Cloud Storage 버킷에 저장할 수 있습니다.

전송을 실행하는 서비스 에이전트에는 매니페스트가 포함된 버킷에 대한 storage.objects.get 권한이 있어야 합니다. 서비스 에이전트 ID를 찾고 버킷에 대한 서비스 에이전트에 권한을 부여하는 방법은 필수 권한 부여를 참조하세요.

매니페스트를 버킷에 업로드하는 방법은 Cloud Storage 문서의 객체 업로드를 참고하세요.

예를 들어 gcloud CLI를 사용하여 Cloud Storage에 파일을 업로드하려면 gcloud storage cp 명령어를 사용합니다.

gcloud storage cp MANIFEST.CSV gs://DESTINATION_BUCKET_NAME/

각 항목의 의미는 다음과 같습니다.

  • MANIFEST.CSV는 매니페스트 파일의 로컬 경로입니다. 예를 들면 Desktop/manifest01.csv입니다.

  • DESTINATION_BUCKET_NAME은 객체를 업로드할 버킷의 이름입니다. 예를 들면 my-bucket입니다.

성공하면 응답은 다음 예시와 같습니다.

Completed files 1/1 | 164.3kiB/164.3kiB

고객 관리 Cloud KMS 암호화 키를 사용하여 매니페스트를 암호화할 수 있습니다. 이 경우 매니페스트에 액세스하는 서비스 계정에 해당하는 암호화 키가 할당되었는지 확인합니다. 고객 제공 키는 지원되지 않습니다.

파일 시스템에 매니페스트 저장

매니페스트 파일을 소스 또는 대상 파일 시스템에 저장할 수 있습니다.

전송 에이전트가 파일 위치에 액세스할 수 있어야 합니다. 에이전트의 디렉터리 액세스를 제한하는 경우 매니페스트 파일이 마운트된 디렉터리 내에 있는지 확인합니다.

전송 시작

전송 작업이 완료될 때까지 매니페스트 파일을 수정하지 마세요. 전송이 수행될 때는 매니페스트 파일을 잠그는 것이 좋습니다.

Cloud 콘솔에서 매니페스트로 전송을 시작하려면 다음 안내를 따르세요.

  1. 전송 만들기의 안내에 따라 소스, 대상, 옵션을 선택합니다.

  2. 마지막 단계인 설정 선택에서 매니페스트 파일을 통해 전송할 파일 목록 제공 체크박스를 선택합니다.

  3. 매니페스트 파일 위치를 입력합니다.

매니페스트에 나열된 파일 또는 객체를 전송하려면 gcloud transfer jobs create 명령어에 --manifest-file=MANIFEST_FILE 플래그를 포함하세요.

gcloud transfer jobs create SOURCE DESTINATION \
  --manifest-file=MANIFEST_FILE

MANIFEST_FILE은 다음 값 중 하나입니다.

  • Cloud Storage 버킷에 있는 CSV 파일의 경로:

    --manifest-file=gs://my_bucket/sample_manifest.csv
    

    버킷 또는 파일이 공개 상태가 아닌 경우 필요한 권한에 대한 자세한 내용은 Cloud Storage에 매니페스트 업로드를 참조하세요.

  • 지정된 모든 경로를 포함한 파일 시스템 SOURCE의 상대 경로:

    --manifest-file=source://relative_path/sample_manifest.csv
    
  • 지정된 모든 경로를 포함한 파일 시스템 DESTINATION의 상대 경로:

    --manifest-file=destination://relative_path/sample_manifest.csv
    

매니페스트에 나열된 파일 또는 객체를 전송하려면 transferManifest 필드가 추가된 transferSpec을 지정하는 createTransferJob API를 호출합니다. 예를 들면 다음과 같습니다.

POST https://storagetransfer.googleapis.com/v1/transferJobs

...
  "transferSpec": {
      "posixDataSource": {
          "rootDirectory": "/home/",
      },
      "gcsDataSink": {
          "bucketName": "GCS_NEARLINE_SINK_NAME",
          "path": "GCS_SINK_PATH",
      },
      "transferManifest": {
          "location": "gs://my_bucket/sample_manifest.csv"
      }
  }

매니페스트 파일은 Cloud Storage 버킷 또는 소스나 대상 파일 시스템에 저장할 수 있습니다. Cloud Storage 버킷은 gs:// 프리픽스를 사용해야 하며 버킷 이름을 포함한 전체 경로를 포함해야 합니다. 파일 시스템 위치는 source:// 또는 destination:// 프리픽스를 사용해야 하며 파일 시스템 소스 또는 대상 및 루트 디렉터리(선택사항)를 기준으로 합니다.


import (
	"context"
	"fmt"
	"io"

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

func transferUsingManifest(w io.Writer, projectID string, sourceAgentPoolName string, rootDirectory string, gcsSinkBucket string, manifestBucket string, manifestObjectName 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"

	// The ID of the GCS bucket that contains the manifest file
	// manifestBucket := "my-manifest-bucket"

	// The name of the manifest file in manifestBucket that specifies which objects to transfer
	// manifestObjectName := "path/to/manifest.csv"

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

	manifestLocation := "gs://" + manifestBucket + "/" + manifestObjectName
	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},
				},
				TransferManifest: &storagetransferpb.TransferManifest{Location: manifestLocation},
			},
			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 using manifest file %v with name %v", rootDirectory, gcsSinkBucket, manifestLocation, resp.Name)
	return resp, nil
}

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.TransferManifest;
import com.google.storagetransfer.v1.proto.TransferTypes.TransferSpec;
import java.io.IOException;

public class TransferUsingManifest {

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

    // The ID of the GCS bucket which has your manifest file
    String manifestBucket = "my-bucket";

    // The ID of the object in manifestBucket that specifies which files to transfer
    String manifestObjectName = "path/to/manifest.csv";

    transferUsingManifest(
        projectId,
        sourceAgentPoolName,
        rootDirectory,
        gcsSinkBucket,
        manifestBucket,
        manifestObjectName);
  }

  public static void transferUsingManifest(
      String projectId,
      String sourceAgentPoolName,
      String rootDirectory,
      String gcsSinkBucket,
      String manifestBucket,
      String manifestObjectName)
      throws IOException {
    String manifestLocation = "gs://" + manifestBucket + "/" + manifestObjectName;
    TransferJob transferJob =
        TransferJob.newBuilder()
            .setProjectId(projectId)
            .setTransferSpec(
                TransferSpec.newBuilder()
                    .setSourceAgentPoolName(sourceAgentPoolName)
                    .setPosixDataSource(
                        PosixFilesystem.newBuilder().setRootDirectory(rootDirectory).build())
                    .setGcsDataSink((GcsData.newBuilder().setBucketName(gcsSinkBucket)).build())
                    .setTransferManifest(
                        TransferManifest.newBuilder().setLocation(manifestLocation).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 and ran a transfer job from "
              + rootDirectory
              + " to "
              + gcsSinkBucket
              + " using "
              + "manifest file "
              + manifestLocation
              + " with name "
              + response.getName());
    }
  }
}

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

// Transfer manifest location. Must be a `gs:` URL
// const manifestLocation = 'gs://my-bucket/sample_manifest.csv'

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

/**
 * Creates a request to transfer from the local file system to the sink bucket
 */
async function transferViaManifest() {
  const createRequest = {
    transferJob: {
      projectId,
      transferSpec: {
        sourceAgentPoolName,
        posixDataSource: {
          rootDirectory,
        },
        gcsDataSink: {bucketName: gcsSinkBucket},
        transferManifest: {
          location: manifestLocation,
        },
      },
      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}' using manifest \`${manifestLocation}\` with name ${transferJob.name}`
  );
}

transferViaManifest();
from google.cloud import storage_transfer


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

    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 destination bucket name
    # sink_bucket = 'my-gcs-destination-bucket'

    # Transfer manifest location. Must be a `gs:` URL
    # manifest_location = 'gs://my-bucket/sample_manifest.csv'

    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,
                    },
                    "transfer_manifest": {"location": manifest_location},
                },
            }
        }
    )

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

매니페스트의 객체 또는 파일이 반드시 나열된 순서로 전송되지는 않습니다.

매니페스트에 이미 대상에 있는 파일이 포함된 경우 싱크의 기존 객체 덮어쓰기 옵션이 지정되지 않는 한 해당 파일을 건너뜁니다.

매니페스트에 대상의 다른 버전으로 존재하는 객체가 포함된 경우 객체의 소스 버전이 대상의 객체를 덮어씁니다. 대상이 버전 관리되는 버킷이면 객체의 새 버전이 생성됩니다.

다음 단계