
Amazon S3 と API の互換性がある Cloudflare R2 を AWS CLI から使ってみる
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
ウィスキー、シガー、パイプをこよなく愛する大栗です。
先日 Cloudflare では Platform Week と題して、様々な発表を行っていました。その中でAmazon S3 と API に互換性のある R2 のオープンベータを開始したとの発表もありました。S3 と互換性があるということで AWS CLI から使ってみました。
Cloudflare R2
Cloudflare R2 は 2021 年 9 月に発表されたオブジェクトストレージで、Amazon S3 と API の互換性を持ち、エグレス料金がかからないという特徴を持ったサービスです。
R2 の API
R2 には Cloudflare Workers からアクセスする時に使用する In-Worker API と <ACCOUNT_ID>.r2.cloudflarestorage.com の形式の URL でバケットを公開する S3-compatible API という 2 種類の API があります。以下のエントリでは Workers から Service Binding を使って In-Worker API で R2 へアクセスしていました。
もう一つの API である S3-compatible API は、API レベルで Amazon S3 と互換性があります。ただし、全ての Amazon S3 の API が実装されている訳ではないのでご注意ください。一般的に使用される API は概ね実装されているためご安心ください。詳しくはドキュメントをご参照ください。
R2 の制限
| 特徴 | 制限 |
|---|---|
| バケット | アカウントあたり1000バケット |
| バケットごとのデータストレージ | 無制限 |
| オブジェクトサイズ | オブジェクトあたり 5 TB |
| 最大アップロードサイズ | 5 GB |
| バケットごとの Class A 操作 | 1 秒あたり 250 回 |
| バケットごとの Class B 操作 | 1 秒あたり 1000 回 |
R2 の料金
R2 の料金での特徴的な点はエグレス料金つまり、アウトバウントのデータ転送量に対する料金が無料である点です。
R2 で発生する料金は保存しているデータ量と以下の 2 種類の操作に基づいて課金されます。
- Class A 操作:状態を変化させる傾向があるより高い操作
ListBuckets,PutBucket,ListObjects,PutObject,CopyObject,CompleteMultipartUpload,CreateMultipartUpload,UploadPart,UploadPartCopyが含まれます。
- Class B 操作:既存の状態を読み取る傾向のある操作
HeadBucket,HeadObject,GetObjectが含まれます。
開発者向けの無料枠もあり、支払い枠のレートでも代表的なオブジェクトストレージサービスより安価になっています。
| 無料枠 | 支払いレート | |
|---|---|---|
| ストレージ | 10 GB/月 | $0.015/GB月 |
| Class A 操作 | 1,000,000 リクエスト/月 | $4.50/100万リクエスト |
| Class B 操作 | 10,000,000 リクエスト/月 | $0.36/100万リクエスト |
R2 のパフォーマンス
Cloudflare の最優先事項は、パフォーマンスと信頼性の向上とのことです。オープンベータ中は、バケット当たり最大 1,000 rps の GET 操作と 100 rps の PUT 操作を維持できます。
また R2 ではリージョンを選択することはありません。R2 のビジョンとして自動的にグローバル分散したストレージを構築してリクエスト元に最も近いストレージリージョンにシームレスに配置するというものがあります。
現在は主に北米にデータを保存しているため、他の地域からのアクセスではレイテンシが高くなる可能性があります。リージョン間でオブジェクトの自動移行する機能を追加する前に、オブジェクトを作成できるリージョンを追加してこの問題に対応する予定となっています。Durable Objects の管轄制限と同様に、プライバシー規制に準拠するように R2 バケットの配置場所を制限することも可能になります。
やってみた
実際に AWS CLI を使用して R2 にアクセスしてみます。ここで AWS CLI は現時点での 2 系の最新バージョンである 2.7.4 を使用しています。
$ aws --version aws-cli/2.7.4 Python/3.9.11 Darwin/21.4.0 exe/x86_64 prompt/off
認証情報の発行
Cloudflare のコンソールで R2 の画面を表示します。後で使用するため Account ID をメモしておきます。Manage R2 API Tokensをクリックします。

Create API Tokenをクリックします。

Token nameにトークンの名称を入力して、Permissionsで権限を選択します。書き込みをしたいためEditを選択して、Create API Tokenをクリックしてトークンを発行します。

発行されたトークンのAccess Key IDとSecret Access Keyをメモします。

AWS CLI に認証情報を設定します。
aws configureコマンドを実行します。ここでは--profileオプションを付けて、デフォルトでないプロファイルを作成しています。AWS Access Key IDとAWS Secret Access Keyに先程発行した Access Key ID と Secret Access Key を各々入力します。今の所 R2 にはリージョンがないのでDefault region nameは何も入力しません。Default output formatは JSON にしておきました。
$ aws configure --profile <Profile Name> AWS Access Key ID [None]: <Access Key ID> AWS Secret Access Key [None]: <Secret Access Key> Default region name [None]: Default output format [None]: json
これで準備が完了しました。
AWS CLI の実行
AWS CLI で R2 にアクセスします。注意点は以下の 2 点です。
- 作成したプロファイルを指定する
--endpoint-urlオプションで自分の R2 の URL を指定する
R2 の URL は <ACCOUNT_ID>.r2.cloudflarestorage.com となります。ACCOUNT_IDはR2 の画面の右上で確認できます。
AWS CLI には S3 を操作するためのコマンド群が 2 種類あり、API レベルのコマンドであるaws s3apiと、高レベルコマンドのaws s3です。ここでは一般的に使用される高レベルコマンドのaws s3を使用していきます。
まずはバケットの一覧を見てみます。まだバケットを作成していないため何も表示されません。
$ aws s3 ls --profile <Profile Name> --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com
バケットを作成します。R2 にはリージョンがないので指定せずに実行するとエラーになってしまいました。リージョンをautoで指定する必要があります。
aws s3 mb s3://test-bucket-1 --profile <Profile Name> --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com make_bucket failed: s3://test-bucket-1 An error occurred (InvalidRegionName) when calling the CreateBucket operation: The region name 'aws-global' is not valid. Must be 'auto'
リージョンをautoで指定して再度実行します。なおバケット名ですが S3 ではグローバルで一意の名称にしなければなりませんでしたが、R2 ではアカウント内で一意であればよいためアカウントが異なれば同じ名称のバケットを作成できます。
aws s3 mb s3://test-bucket-1 --region auto --profile <Profile Name> --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com make_bucket: test-bucket-1
もう一つバケットを作成します。
aws s3 mb s3://test-bucket-2 --region auto --profile <Profile Name> --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com make_bucket: test-bucket-2
バケット一覧を確認します。
$ aws s3 ls --profile cloudflare-r2-test --endpoint-url https://016710547c15a9a30e9598cbfff93d9a.r2.cloudflarestorage.com 2022-05-30 13:52:43 test-bucket-1 2022-05-30 14:00:58 test-bucket-2
ファイルをアップロードするためaws s3 cpコマンドを使用します。このようにファイルをアップロードできます。`
$ aws s3 cp ./test1.txt s3://test-bucket-1/folder1/ --profile <Profile Name> --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com upload: ./test1.txt to s3://test-bucket-1/folder1/test1.txt $ aws s3 ls s3://test-bucket-1/folder1/ --profile <Profile Name> --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com 2022-05-30 14:55:22 34 test1.txt
バケット間でファイルをコピーします。
aws s3 cp s3://test-bucket-1/folder1/test1.txt s3://test-bucket-2/folder2/ --profile <Profile Name> --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com copy: s3://test-bucket-1/folder1/test1.txt to s3://test-bucket-2/folder2/test1.txt
もう一つファイルをアップロードして、バケット間で同期してみます。
$ aws s3 cp ./test2.txt s3://test-bucket-1/folder1/ --profile <Profile Name> --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com upload: ./test2.txt to s3://test-bucket-1/folder1/test2.txt $ aws s3 sync s3://test-bucket-1 s3://test-bucket-2 --profile <Profile Name> --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com copy: s3://test-bucket-1/folder1/test1.txt to s3://test-bucket-2/folder1/test1.txt copy: s3://test-bucket-1/folder1/test2.txt to s3://test-bucket-2/folder1/test2.txt
次に--aclオプションでpublic-readを付けてコピーを実行してみます。x-amz-aclヘッダーでpublic-readは実装されていないためエラーとなります。そもそも現時点では R2 単体でオブジェクトを公開する機能がないためだと思われます。
$ aws s3 cp s3://test-bucket-1/folder1/test1.txt s3://test-bucket-2/folder3/ --acl public-read --profile <Profile Name> --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com copy failed: s3://test-bucket-1/folder1/test1.txt to s3://test-bucket-2/folder3/test1.txt An error occurred (NotImplemented) when calling the CopyObject operation: Header 'x-amz-acl' with value 'public-read' not implemented
--aclオプションをpublic-readではなくprivateにすると問題なくコピーできました。パブリックバケットは今後のロードマップとして明記してある機能ですので実装を待ちましょう。
aws s3 cp s3://test-bucket-1/folder1/test1.txt s3://test-bucket-2/folder3/ --acl private --profile <Profile Name> --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com copy: s3://test-bucket-1/folder1/test1.txt to s3://test-bucket-2/folder3/test1.txt
また、実装されていないListMultipartUploadsAPI も試してみましょう。こちらは API レベルのコマンドであるaws s3apiで実行してみます。するとListMultipartUploadsが実装されていないというエラーが表示されます。
$ aws s3api list-multipart-uploads --bucket test-bucket-1 --profile cloudflare-r2-test --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com An error occurred (NotImplemented) when calling the ListMultipartUploads operation: ListMultipartUploads not implemented
最後に
Amazon S3 と互換性があるということなので、AWS CLI を使ってアクセスしてみました。R2 が使える機能であれば問題なく使用できそうだということがわかりました。しかし Amazon S3 に実装されており R2 に実装されていない機能は当然使用できないためエラーになります。現時点では Cloudflare Workers との連携やエグレス料金がかからないメリットなどが重要な場合など利用用途を明確にして使用するべきかと思います。将来的にリクエスト元に最も近いストレージリージョンにシームレスにデータを配置するというビジョンがあるので、とても期待をしているサービスです。
現在はオープンベータですが、先に検証をしておくと一般提供になったときに直ぐに使い始めることができます。積極的に検証して、Cloudflare へフィードバックをしていきましょう。







