Cloudflare:R2
R2를 이용해 S3와 호환 가능한 개체 스토리지로 원하는 멀티 클라우드 아키텍처를 자유롭게 생성할 수 있습니다.
- 글로벌 개체 스토리지
- Cloudflare Workers와의 통합으로 제공되는 동적 기능
- Cloudflare의 S3 호환 API로 벤더 종속 방지
R2 가격 정책
R2는 저장된 데이터의 총량과 해당 데이터의 두 작업 클래스에 따라 요금이 부과됩니다. 송신료가 없습니다.
- | 평생 무료 | 월 요금 |
스토리지 | 10GB/월 | $0.015/1GB |
클래스 A 작업: 변형 상태 | 1,000,000/월 | $4.50/백만 |
클래스 B 작업: 기존 상태 읽기 | 10,000,000/월 | $0.36/백만 |
- 송신 (인터넷으로 데이터 전송)
- Workers API, S3 API 및 r2.dev 도메인을 통하는 것을 포함하여 R2에서 직접 송신하는 경우 데이터 전송(송신) 요금이 발생하지 않으며 무료입니다.
- 다른 측정 서비스를 R2 버킷에 연결하면 해당 서비스에 따라 요금이 부과될 수 있습니다.
Storage usage
스토리지는 청구 지표로 기가바이트-월(GB-월)을 사용하여 청구됩니다. GB-월은 해당 월의 기간 동안 저장된 총 바이트를 기록하여 계산됩니다. (duration of the month)
예를 들어:
- 30일 동안 1GB를 저장하면 1GB-월로 요금이 부과됩니다.
- 15일 동안 2GB를 저장하면 1GB-월로 요금이 부과됩니다.
아마도 다음과 같은 공식이 적용되는 듯 하다.
Operation Categories
요금에 영향이 있는 연산들 이다.
Class A operations
Class A Operations include ListBuckets, PutBucket, ListObjects, PutObject, CopyObject, CompleteMultipartUpload, CreateMultipartUpload, ListMultipartUploads, UploadPart, UploadPartCopy and PutBucketEncryption.
Class B operations
Class B Operations include HeadBucket, HeadObject, GetObject, UsageSummary, GetBucketEncryption and GetBucketLocation.
Free operations
Free operations include DeleteObject, DeleteBucket and AbortMultipartUpload.
버킷 만들기 및 API 토큰 만들기
| R2 에 들어가면 버킷을 만들거나 "Manage R2 API Tokens" 링크가 있다: |
| 버킷을 만들때 특별한 경우가 아니면 "자동" (R2는 사용자의 위치를 기준으로 사용 가능한 가장 가까운 지역에 버킷을 자동으로 배치합니다) 을 선택하자. |
| "Manage R2 API Tokens" 링크를 클릭하여 토큰을 만들 수 있다. |
| 토큰을 생성하면 여러 Access Key ID, Secret Access Key, Endpoint URL 가 출력된다. 그리고 버킷명과 해당 버킷의 region (아시아: apac)을 기억하면 된다. |
boto3 example
import boto3
s3 = boto3.client(
service_name ="s3",
endpoint_url = 'https://<accountid>.r2.cloudflarestorage.com',
aws_access_key_id = '<access_key_id>',
aws_secret_access_key = '<access_key_secret>',
region_name="<location>", # Must be one of: wnam, enam, weur, eeur, apac, auto
)
# Get object information
object_information = s3.head_object(Bucket=<R2_BUCKET_NAME>, Key=<FILE_KEY_NAME>)
# Upload/Update single file
s3.upload_fileobj(io.BytesIO(file_content), <R2_BUCKET_NAME>, <FILE_KEY_NAME>)
# Delete object
s3.delete_object(Bucket=<R2_BUCKET_NAME>, Key=<FILE_KEY_NAME>)
aws-sdk-js-v3 example
import {
S3Client,
ListBucketsCommand,
ListObjectsV2Command,
GetObjectCommand,
PutObjectCommand
} from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
const S3 = new S3Client({
region: "auto",
endpoint: `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`,
credentials: {
accessKeyId: ACCESS_KEY_ID,
secretAccessKey: SECRET_ACCESS_KEY,
},
});
console.log(
await S3.send(
new ListBucketsCommand('')
)
);
// {
// '$metadata': {
// httpStatusCode: 200,
// requestId: undefined,
// extendedRequestId: undefined,
// cfId: undefined,
// attempts: 1,
// totalRetryDelay: 0
// },
// Buckets: [
// { Name: 'user-uploads', CreationDate: 2022-04-13T21:23:47.102Z },
// { Name: 'my-bucket-name', CreationDate: 2022-05-07T02:46:49.218Z }
// ],
// Owner: {
// DisplayName: '...',
// ID: '...'
// }
// }
console.log(
await S3.send(
new ListObjectsV2Command({ Bucket: 'my-bucket-name' })
)
);
// {
// '$metadata': {
// httpStatusCode: 200,
// requestId: undefined,
// extendedRequestId: undefined,
// cfId: undefined,
// attempts: 1,
// totalRetryDelay: 0
// },
// CommonPrefixes: undefined,
// Contents: [
// {
// Key: 'cat.png',
// LastModified: 2022-05-07T02:50:45.616Z,
// ETag: '"c4da329b38467509049e615c11b0c48a"',
// ChecksumAlgorithm: undefined,
// Size: 751832,
// StorageClass: 'STANDARD',
// Owner: undefined
// },
// {
// Key: 'todos.txt',
// LastModified: 2022-05-07T21:37:17.150Z,
// ETag: '"29d911f495d1ba7cb3a4d7d15e63236a"',
// ChecksumAlgorithm: undefined,
// Size: 279,
// StorageClass: 'STANDARD',
// Owner: undefined
// }
// ],
// ContinuationToken: undefined,
// Delimiter: undefined,
// EncodingType: undefined,
// IsTruncated: false,
// KeyCount: 8,
// MaxKeys: 1000,
// Name: 'my-bucket-name',
// NextContinuationToken: undefined,
// Prefix: undefined,
// StartAfter: undefined
// }
Presigned URLs
보안에 관련된 내용.