Cloudflare R2を試してみる
2023/12/8
Cloudflareが提供するオブジェクトストレージサービスを試してみます。
Cloudflare R2を試してみる
公式ドキュメントを読みながら進めてみます。
CloudflareのCLIツールであるwrangler(ラングラー)を使用するみたいなので、npmでインストールをしてログインしてみます。
npm install -g wrangler
wrangler login
同意画面的なものが出てから先に進むと認証が完了します。
バケットを作成する
wrangler r2 bucket list
下記のエラーが出ます。
✘ [ERROR] A request to the Cloudflare API (/accounts/*****/r2/buckets) failed.
Please enable R2 through the Cloudflare Dashboard. [code: 10042]
CloudflareのダッシュボードからR2を開き、overviewへ移動するとSubscription画面になります。
ホビーユースの範囲では基本的に無料な感じです。とりあえず以下のように、
- Class A operations
- POST・PUT系のバケット作成やオブジェクトアップロード・コピー
- Class B operations
- GET系のバケット取得やサマリ取得
- Free operations
- DELETE系のバケット・オブジェクトの削除など
といった雰囲気で認識しています。
改めてコマンドを実行します。
wrangler r2 bucket list
[]
何も作っていないので空の配列が返ってきました。とりあえず新しくバケットを作成します。
Cloudflare R2 - Create Buckets
wrangler r2 bucket create BUCKET_NAME
バケット名は、このサイトでの利用を想定してephy-devとしました。
wrangler r2 bucket list
[
{
"name": "ephy-dev",
"creation_date": "2023-12-08T15:38:00.065Z"
}
]
WebUIの方を確認してみるとバケットが作成されていることが確認できます。ファイル・フォルダでのアップロードを行うことができます。フォルダに関しては、Finderなどから直接ファイル自体をD&Dするだけで中身がアップロードされました。
ドメインの設定
R2のバケットに対して直接カスタムドメインも設定できるみたいなので、早速設定してみました。カスタムドメインを設定すればCloudflareのCacheが効くなどの恩恵が得られます。
設定はバケットのSettingsから行います。
おそらくですが、サブドメインなしで入力するとそのままメインのドメインとR2のバケットが紐づいてしまうかもしれないので、サブドメインは入れておきましょう。今回はstorage.ephy.devとしています。
Continueを押下して進むと設定は完了します。Cloudflareの管理画面からドメインのWebsiteを開いてDNS設定を確認しに行くと、自動で追加されていることが確認できました。
R2のバケットに戻り、先程アップロードした画像ファイルを開くとCustomDomainsの項目が増えていて、パブリックに参照できるリンクが添えられています。
カスタムドメインに関しては、設定したいR2バケットとドメイン・Websiteを管理しているアカウントが同一である必要があったり、HTTPS必須などの制約があるようです。
カスタムドメインを設定しない場合はCloudflareが提供するr2.devドメインを利用することが出来ます。ただし、「レートリミットなどが設定されているので開発用途に使用してね。」といった感じのことが書かれています。
wranglerからのオブジェクト操作
wranglerからは以下のようなコマンドでオブジェクトを操作します。ヘルプからも確認ができます。
wrangler r2 object help
PUT
R2上での配置先とファイル名、--fileにローカルのファイルを指定という感じです。
wrangler r2 object put ephy-dev/test-put.jpg --file=my_file.jpg
GET
R2上のファイルパスとファイル名を指定して取得します。ファイルは実行した場所に保存されました。
wrangler r2 object get ephy-dev/test-put.jpg
DELETE
R2上のファイルパスとファイル名を指定して削除します。
wrangler r2 object delete ephy-dev/test-put.jpg
Cloudflare WorkersによるR2の操作
Cloudflare R2 - Workers API Usage
Cloudflare Workersのテンプレートを利用してプロジェクトを作成します。npm createコマンドでアレコレ対話式で選択していくだけで初期構築が終わります。
npm create cloudflare@latest
途中のテンプレ内容選択は一旦"Hello World" Workerを選択
├ What type of application do you want to create?
│ type "Hello World" Worker
Workerの方はお試しなので、先ほど作成したバケットとは別のバケットにするために別途作成します。
wrangler r2 bucket create ephy-worker-test
チュートリアルに沿ってwrangler.tomlを修正します。wranglerのwhoamiコマンドを使用すると自身のアカウントIDがわかります。見た感じですが、CloudflareのダッシュボードURLに含まれているハッシュ値みたいなやつがアカウントIDです。
wrangler whoami
アカウントIDの設定と一緒にR2のバケット名も設定します。bindingプロパティはJavaScript上で環境変数としてアクセスするための定数です。
account_id = "YOUR_ACCOUNT_ID"
workers_dev = true
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "ephy-worker-test"
とりあえずチュートリアルの通りにindex.jsを修正します。先程のbindingで設定した定数へのアクセスしているコードがあるので、bindingをMY_BUCKET以外に設定した場合は、適宜修正する必要があります。
hasValidHeader()で認証キーのチェックをし、ALLOW_LISTにはアクセスできるファイルが定義されています。
const ALLOW_LIST = ["cat-pic.jpg"];
const hasValidHeader = (request, env) => {
return request.headers.get("X-Custom-Auth-Key") === env.AUTH_KEY_SECRET;
};
function authorizeRequest(request, env, key) {
switch (request.method) {
case "PUT":
case "DELETE":
return hasValidHeader(request, env);
case "GET":
return ALLOW_LIST.includes(key);
default:
return false;
}
}
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
const key = url.pathname.slice(1);
if (!authorizeRequest(request, env, key)) {
return new Response("Forbidden", { status: 403 });
}
switch (request.method) {
case "PUT":
await env.MY_BUCKET.put(key, request.body);
return new Response(`Put ${key} successfully!`);
case "GET":
const object = await env.MY_BUCKET.get(key);
if (object === null) {
return new Response("Object Not Found", { status: 404 });
}
const headers = new Headers();
object.writeHttpMetadata(headers);
headers.set("etag", object.httpEtag);
return new Response(object.body, {
headers,
});
case "DELETE":
await env.MY_BUCKET.delete(key);
return new Response("Deleted!");
default:
return new Response("Method Not Allowed", {
status: 405,
headers: {
Allow: "PUT, GET, DELETE",
},
});
}
},
};
動作させるためにAUTH_KEY_SECRETをwrangler経由で取得します。
wrangler secret put AUTH_KEY_SECRET
⛅️ wrangler 3.19.0
-------------------
✔ Enter a secret value: … ***********
🌀 Creating the secret for the Worker "***-*****-****"
✨ Success! Uploaded secret AUTH_KEY_SECRET
上記の操作で行った内容は、Workersの管理画面にあるSettingsに設定が追加されています。
先程のbindingsへもtomlの通りに設定されています。
デプロイします。
wrangler deploy
デプロイが完了したら試しにcurlコマンドでworkersのエンドポイントを叩いてみます。your-worker.devは自分のworkerのドメインに置き換えます。
curl https://your-worker.dev/cat-pic.jpg -X PUT --data-binary 'test'
Put cat-pic.jpg successfully!
cat-pic.jpgしか許可していないので以下のcurlを試すと前者はForbiddenになり、後者のみ成功します。
curl https://your-worker.dev/foo
curl https://your-worker.dev/cat-pic.jpg
R2のオブジェクトに対してアクセス制御や細かな処理を自前でやりたいという場合はWorkersを使用して処理するという感じのようです。画像最適化に関してはCloudflareにImagesみたいなサービスがあったような気がするのと、$5からなのでまたいつか触ってみようと思います。
Cloudflare R2 - Workers API Reference
終わりに
シンプルで使いやすいと思いました。Cloudflareにドメイン置いていたりする場合の手軽さもすごいですね。
今回試したこと以外にS3互換APIの提供もありドキュメントも充実しているようなので、機会があったら利用してみたいと思います。