Cloudflare Workers による FaaS・Cloudflare Workers KV による Key-Value Store を試してみた

CDN プロバイダとして知られる Cloudflare だが、最近以下のようなサービスを展開している。

いずれも無料枠があり、クレジットカード入力もなく無料で利用し始められるのが特徴。

今回はこの中の上2つ、FaaS と NoSQL サービスである、Cloudflare Workers および Cloudflare Workers KV を試してみる。

目次

Cloudflare へのアカウント登録

予め、Cloudflare のアカウントを登録しておこう。

普通に Sign Up するだけ。クレジットカード入力が必要なくて安心。

仕様と制約

Workers・Workers KV ともに、無料枠ではいくつかの制限事項がある。前述のとおりクレカ入力していないので、いきなり課金が発生することはないが、大規模なアプリを無料枠で動かそうとするのは無理があるので、よくよく注意してほしい。

初めに Workers の制限を確認する。

→ AWS Lambda などと比べるとメモリが少なく、実行時間の制約も厳しめ。ゴリゴリとバックエンド処理をやらせる用途には向かず、プロキシ的な利用がギリギリだろう。以下のサンプルコード集も参考に。

次に Workers KV の制限。

読み書きの回数に上限があるので、リクエスト数の多いアプリのバックエンドとして使おうとすると、すぐレート制限に引っ掛かってしまうだろう。

CLI ツール「Wrangler」をインストールする

Workers プロジェクトはブラウザのダッシュボード上からでも作成できるが、ローカル開発環境が用意できたりして便利なので、Cloudflare が提供する公式 CLI ツールの Wrangler を使っていく。

npm でグローバルインストールすれば良いが、裏は Rust 製なので Cargo でもインストールできるみたい。

$ npm i -g @cloudflare/wrangler

$ wrangler --version
wrangler 1.17.0

Wrangler でログインする

続いて、wrangler login コマンドを使ってログインする。

$ wrangler login
Allow Wrangler to open a page in your browser? [y/n]
y
💁  Opened a link in your default browser: https://dash.cloudflare.com/wrangler?【……】
⠒   Waiting for API token...

# ブラウザが開くので許可を進めていく

💁  Validating credentials...
✨  Successfully configured. You can find your configuration file at: /home/neo/.wrangler/config/default.toml

# ログイン成功・トークンが書かれたファイルが出来ているので確認する
$ cat ~/.wrangler/config/default.toml
api_token = "【API トークン】"

# ログインユーザを確認する
$ wrangler whoami

  ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
  │                                                                                                  │
  │      👋  You are logged in with an API Token, associated with the email 'neos21@gmail.com'!      │
  │                                                                                                  │
  ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯

+----------------------------+----------------------------------+
| Account Name               | Account ID                       |
+----------------------------+----------------------------------+
| Neos21@gmail.com's Account | 【アカウント ID】                |
+----------------------------+----------------------------------+

こんな感じ。

試しに KV を作ってみるかと思ったけど、KV は Workers プロジェクトを作ってからでないと作成できなかった。KV は紐付けた Workers からのみ呼び出しができるようだ。

# KV から先には作れない
$ wrangler kv:namespace create practice
Error: wrangler.toml not found

Workers プロジェクトを作成する

というワケで、先に wrangler generate コマンドを使って Workers プロジェクトを作る。

# Workers プロジェクトを作る。この時点では Publish はされておらずダッシュボードには何も出ない
$ wrangler generate practice
 Creating project called `practice`...
 Done! New project created /home/neo/practice
🕵️  You can find your zone_id in the right sidebar of a zone's overview tab at https://dash.cloudflare.com
🕵️  You can copy your account_id below
+----------------------------+----------------------------------+
| Account Name               | Account ID                       |
+----------------------------+----------------------------------+
| Neos21@gmail.com's Account | 【アカウント ID】                |
+----------------------------+----------------------------------+
🕵️  You will need to update the following fields in the created wrangler.toml file before continuing:
- account_id

コマンドで指定した名前どおり、practice/ というディレクトリができ、その下に各種ボイラープレートファイルが生成されている。

プロジェクトに関連する情報は、wrangler.toml という設定ファイルに書いていく。アカウント ID やゾーン ID など、クレデンシャルっぽい雰囲気の項目もあるのだが、これらは wrangler.toml にベタ書きして GitHub 公開しても大丈夫。

コンソールに表示されていたアカウント ID を、生成された wrangler.toml に記載する。他のファイルは適当に調整した。

name = "practice"
type = "javascript"

account_id = "07100c21a5c21a0afb93ab435ba46712"
workers_dev = true
route = ""
zone_id = ""
/**
 * Main
 */
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request));
});

/**
 * Response With Hello World Text
 * 
 * @param {Request} _request Request
 */
async function handleRequest(_request) {
  return new Response('Hello World', {
    headers: { 'content-type': 'text/plain' }
  });
}

ローカル実行してみる

ファイルが用意できたら、wrangler dev コマンドでローカルに Workers を立ち上げてみる。

$ wrangler dev
💁  watching "./"
👂  Listening on http://127.0.0.1:8787
[2021-07-08 09:38:39] GET practice.neos21.workers.dev/ HTTP/1.1 200 OK
[2021-07-08 09:38:40] GET practice.neos21.workers.dev/favicon.ico HTTP/1.1 200 OK

http://127.0.0.1:8787/ にアクセスすると、Hello World とレスポンスがあった。index.js の内容に沿ってリクエストが処理され、レスポンスされていることが確認できた。

Cloudflare Workers に公開する

動作確認ができたら、wrangler publish コマンドで実際に公開してみる。

$ wrangler publish
✨  Basic JavaScript project found. Skipping unnecessary build!
✨  Successfully published your script to
 https://practice.neos21.workers.dev

コレで公開できた。https://practice.neos21.workers.dev/ にアクセスすると Hello World とレスポンスがあった。

ブラウザで見られるダッシュボードにも、プロジェクトが表示されるようになった。初回表示までは2・3分待つ必要あり。

KV を作成する

続いて KV を作成していく。

$ wrangler kv:namespace create kv
🌀  Creating namespace with title "practice-kv"
✨  Success!
Add the following to your configuration file:
kv_namespaces = [ 
         { binding = "kv", id = "32d76002a7784decb07151acf413098b" }
]

「名前空間の名前」としては、プロジェクト名と指定した名前空間をハイフンで結合した、practice-kv というモノになる。

後述するが index.js 内で参照する名前空間としては、この内の kv 部分だけ記述すれば良い。index.js で変数名として使用するためか、名前空間にはハイフンが使えず、アンダースコアでしか区切れない。

ひとまず、何やらコンソールに「コレを追記しろ」と出力されているので、この内容を wrangler.toml に追記しておく。

# Worker 名 : `https://【この Worker 名】.【アカウント名】.workers.dev/` で公開できる
name = "practice"
# `$ worker build` コマンドでのビルド方法を指定する・`javascript` にすると Webpack が使われる
type = "javascript"
# `webpack.config.js` を自前で用意した場合は `webpack_config` プロパティで指定する

# アカウント ID
account_id = "07100c21a5c21a0afb93ab435ba46712"
# `workers.dev` にデプロイする場合は `true` にする
workers_dev = true
# `workers.dev` ではなく独自ドメインで公開する際に指定する・`workers.dev` で公開する場合は空文字で良い
route = ""
# `workers.dev` で公開する場合は空文字で良い
zone_id = ""

# KV : ↓ コレを追記した
kv_namespaces = [
  { binding = "kv", id = "32d76002a7784decb07151acf413098b" }
]

Wrangler CLI で KV の参照・操作

Workers KV は原則、紐付けた Workers からしかアクセスできないのだが、ログイン済の Wrangler CLI であれば、wrangler.toml の内容を参照しながら、KV にアクセスできる。

# 名前空間名を指定してキーをリスト表示する
$ wrangler kv:key list --binding 'kv'
[]

# JSON 配列っぽい値を `test` というキー名で登録する
$ wrangler kv:key put 'test' '[ { "id": 1, "text": "Hello World" } ]' --binding 'kv'
✨  Success

# 登録したキー名が見えた
$ wrangler kv:key list --binding 'kv'
[{"name":"test"}]

# 登録したデータが見えた
$ wrangler kv:key get 'test' --binding 'kv'
[ { "id": 1, "text": "Hello World" } ]

# この内容はダッシュボード上でも確認できる (= 実際にアップされている)

開発環境用の KV を作る

このままでも、wrangler publish したスクリプトから当該 KV へのアクセスはできるのだが、wrangler dev で立てたローカル開発環境からはこの KV が参照できない。

そこで、--preview オプションを使用し、開発環境用の KV を別途作成する。

# 開発環境 (`wrangler dev`) 用にプレビュー KV を作る
$ wrangler kv:namespace create 'kv' --preview
🌀  Creating namespace with title "practice-kv_preview"
✨  Success!
Add the following to your configuration file in your kv_namespaces array:
{ binding = "kv", preview_id = "9f23b9bb89db4af7a2eca3230e50780f", id = "32d76002a7784decb07151acf413098b" }

ダッシュボードを確認すると、`practice-kvpreview`_ という名前空間の名前で KV が生成されている。名前が違うだけで、KV の動作としては変わりないようだ。

コンソール出力されている内容を参考にして、wrangler.tomlkv_namespaces 部分を次のように修正する。

kv_namespaces = [
  { binding = "kv", id = "32d76002a7784decb07151acf413098b", preview_id = "9f23b9bb89db4af7a2eca3230e50780f" }
]

最初に作成した KV の記述をそのままに、preview_id プロパティを追加し、practice-kv_preview の ID を記載している。

開発環境用の KV に Wrangler CLI でアクセスする

Wrangler CLI でプレビュー環境にアクセスするには、次のように --preview を付けながら操作すれば、先程試したコマンドと変わらずに KV が操作できる。

# 名前空間名を指定してキーをリスト表示する (`--preview` オプションだけ追記していることに注意)
$ wrangler kv:key list --binding 'kv' --preview
[]
# `practice-kv` の方には先程データを投入したが、`practice-kv_preview` にはまだ何もデータが入っていないので、キー一覧も空になっている

# JSON 配列っぽい値を `test` というキー名で登録する
$ wrangler kv:key put 'test' '[ { "id": 1, "text": "Hello World Preview" } ]' --binding 'kv' --preview
✨  Success

# キーが追加されている
$ wrangler kv:key list --binding 'kv'
[{"name":"test"}]

# 登録されたデータが確認できるが、`practice-kv` とは異なる値であることが分かる
$ wrangler kv:key get 'test' --binding 'kv'
[ { "id": 1, "text": "Hello World Preview" } ]
# この内容はダッシュボード上でも確認できる (= 実際にアップされている)

Workers スクリプトから KV を参照する

Wrangler CLI から KV の参照・操作ができたので、いよいよ Workers スクリプトを修正し、Workers から KV を参照・操作できるようにしていく。

/**
 * Main
 */
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request));
});

/**
 * Response With KV Value
 * 
 * @param {Request} _request Request
 */
async function handleRequest(_request) {
  const content = await kv.get("test");  // 変数 `kv` は Cloudflare Workers によって KV の名前空間名 `kv` がそのまま変数名に使われて自動的に定義されている
  console.log(`Console Log : $${content}`);
  return new Response(content, {
    headers: { 'content-type': 'application/json' }
  });
}

今回はまずはデータの取得だけ。いきなり kv.get() とかいうメソッドを叩いているが、ココで出てくる kv というのは、wrangler.tomlbinding = "kv" と指定している、名前空間名である。コレがいきなりグローバル変数として定義された状態になっているので、そいつの get()put() メソッドを呼んで、当該 KV を操作していくことになる。

ローカル開発環境で動作確認 (プレビュー用 KV と接続)

index.js の内容を確認するため、wrangler dev コマンドでローカル開発環境を起動する。wrangler.toml ファイルの preview_id 指定により、プレビュー用 KV に接続していることが分かる。

$ wrangler dev
💁  watching "./"
👂  Listening on http://127.0.0.1:8787

# ブラウザで <http://127.0.0.1:8787> にアクセスしてみる
Console Log : $[ { "id": 1, "text": "Hello World Preview" } ]
[2021-07-08 12:00:46] GET practice.neos21.workers.dev/ HTTP/1.1 200 OK

公開して実際に動作確認 (本番用 KV と接続)

続いて wrangler publish で公開する。

$ wrangler publish
✨  Basic JavaScript project found. Skipping unnecessary build!
✨  Successfully published your script to
 https://practice.neos21.workers.dev

https://practice.neos21.workers.dev/ にアクセスすると、先程までは Hello World とボイラープレートファイルの内容を答えていたが、今度は [ { "id": 1, "text": "Hello World" } ] とレスポンスがあった。

ココで注目したいのは、Publish すると、kv_preview ではなく kv からデータから読み取られている点だ。

以上

Cloudflare Workers および Cloudflare Workers KV の初歩はココまで。今回作成した Workers のコードをコミットした GitHub リポジトリと、実際に本番公開している Workers の URL は次のとおり。最新のコードの内容は、次回の記事で紹介するウェブアプリ向けのモノになっているので、過去のコミットログを遡って確認してみてほしい。

次回は Cloudflare Pages でデプロイしたフロントエンドから、この Cloudflare Workers を呼び出して KV を利用するアプリを作ってみる。

参考文献

その他参考にしたページは以下。