2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Cloudflareを使い倒す Workers 概念編

2
Last updated at Posted at 2025-12-03

どうも、とれいすあっぷと申します。

4日目は「Cloudflareを使い倒す Workers編」ということで、この記事からついに、ちゃんと製品を触っていきます。

この記事では、いつもなんとなくで使っている Cloudflare Workers について、調べて、触って見ます。

Cloudflare Workers って、何。

公式ドキュメントを読みます。

A serverless platform for building, deploying, and scaling apps across Cloudflare's global network with a single command — no infrastructure to manage, no complex configuration

Cloudflare のグローバルネットワークをまたがるアプリケーションを、たった一つのコマンドでビルド、デプロイ、そしてスケーリングするサーバレスプラットフォーム。
管理するインフラも無ければ、複雑なコンフィグもありません。(筆者訳)

私がわかるように言い換えますと、

  • 世界にまたがる Cloudflare network (データセンター) へアプリが置ける
  • 勝手にアプリケーションをビルドして、デプロイして、スケーリングしてくれる
  • VPS とか借りなくていい (= インフラ管理が必要ない)
  • ランタイムのバージョン構成とかも考えなくていい (= 複雑なコンフィグがいらない)

ということですね。

Cloudflare 公式が、Workers を使うと何が期待できるのか書いていました。

With Cloudflare Workers, you can expect to:

  • Deliver fast performance with high reliability anywhere in the world
  • Build full-stack apps with your framework of choice, including React, Vue, Svelte, Next, Astro, React Router, and more
  • Use your preferred language, including JavaScript, TypeScript, Python, Rust, and more
  • Gain deep visibility and insight with built-in observability
  • Get started for free and grow with flexible pricing, affordable at any scale

これも私がわかるようにまとめますと

  • 世界中のどこにいても、高性能かつ高い信頼性のアプリを使えるようになる
  • フルスタック (React, Next, Vue, Nuxt, Svelte, Astro など…) を置ける
  • JavaScript, TypeScript, Python, Rustとかで書いたアプリが動く
  • ビルトインの機能でログやエラーなど、様々な指標が見られる
  • タダで使える!

タダでいろんなフルスタックアプリが動いて激アツ」ということがわかりました。

上から 3 つめの「どんな言語でも動くっぽい?」というのは、実際にはなんでも動くわけではないようです。

仕組みのところで詳しく見ていきますが、Workers を動かしている V8 ランタイムで実行できる JS, WASM に限定されています。

Workers の仕組み

いろんなアプリが動いて激アツなのはわかりましたが、どうやって動いているのでしょうか?
やっぱり、ドキュメントを見ていきましょう。

サーバーレスコードの実行場所:全地球

かっこいいですね。

こういうアプリケーションなら、他のアプリケーションとの兼ね合いを考えれば、コンテナが動いていそうです。

しかし、コンテナを起こして、コードを読んで…ってやっていると、世界からのリクエストには間に合わないですよね。
(AWS Lambda はそういう動作をしますが…)

そこで、JSエンジンの V8 です。

V8 は Google Chrome もとい Chromium 系のブラウザや、Node.js にも採用されている JavaScript エンジンです。

V8 には "Isolate" と呼ばれる、いわば JavaScript 専用の仮想環境みたいな仕組みが備わっています。
そして、V8 たった 1 つで大量に Isolate を生成できます。

Isolate 自体は、それぞれの Isolate から他の Isolate にちょっかいを出せない安全仕様になっています。

コンテクストスイッチングもほぼ存在せず、大量に並列実行しても大きく遅延することはありません。

この安全にできて、高速に大量という恩恵を受けるために、Cloudflare Workers のランタイムは V8 エンジンを使って作られています。

数千のアプリケーションをホストしたとしても Isolate を管理するランタイム自体は 1 つなので、アプリが建てられないメモリ (= アプリ以外に割り当てるメモリ) はランタイム 1 つ分で済むのです。

Cloudflare Workers のリソース使用のイメージ
Cloudflare Workers のリソース使用のイメージ
(https://www.cloudflare.com/ja-jp/developer-platform/products/workers/ より引用した画像)

話を戻しまして、Cloudflare Workers は V8 エンジンの上で動いているというお話でした。

V8 は JS エンジンであるとともに、WebAssembly も動くエンジンです。

詳細は他の記事を参照いただきたいですが、WebAssembly はいろんな言語で書いたものをコンパイルして WebAssemblyにするので、例えば C, C++, C#, Rust, Go, Kotlin, etc...で書いたコードも WebAssembly になります。

つまり、V8 で動かせて怪しくないアプリなら何でも Workers で動かせるのです。やったぁ!


といった具合で、V8 を乗っけた Cloudflare Workers Runtime が全世界にある Cloudflare のデータセンターに乗っかっているのです。

そして世界の誰かがアプリケーションにアクセスすると、その人に一番近いデータセンターが Workers でアプリケーションを走らせて、素早く結果を返してくれているわけですね。

外部サービスにつながる Workers が無敵すぎる件

Cloudflare Workers は env オブジェクトの Bindings を通して、Cloudflare が持っている他の製品にアクセスできます。

一例として AI, D1 (Database), KV (Key-Value Store) などがあります。

ここらへんは今後扱っていくので、今は「Cloudflare 製品は Workers アプリケーションとして使えるんだなあ」と思ってもらえると良いと思います。

気になる方は是非、以下のページから。

Workers を使ってみる

さて、知識のインプットは終わりです。Workers を使ってみましょう。

どうせ今後出す記事のほとんどで Bindings を使っていきますので、今回はシンプルに Workers だけを使ってみましょう。

ここから先は、Cloudflare のアカウントを持っていることを前提とします。
作ってないよ、という方はこちらから手順に沿って作成してください。

ここでは、Tutorial の A/B テストを実装してみます。

A/B テストがなにか、って話は割愛しますが、ゴールは

  • あるリンクにアクセスしたとき、自動的に 2 つあるウェブページのどちらかを表示する
  • 一度表示するページが決まったら、Cookie ベースでずっとその表示先を表示する

とします。

開発環境
  • node v24.11.1
  • npm v11.6.2
  • pnpm v10.22.0

※これ以降、プロジェクト自体はこのページに沿って作っていきます。

1. Worker Project を作る

まずは適当にディレクトリを作ります。

そして、そのディレクトリの中で、Cloudflare Workers Project を作ります。

Console
cf-use-up-worker-basic> pnpm create cloudflare@latest .

──────────────────────────────────────────────────────────────────────────────────────────────────────────
👋 Welcome to create-cloudflare v2.54.5!
🧡 Let's get started.
📊 Cloudflare collects telemetry about your usage of Create-Cloudflare.

Learn more at: https://github.com/cloudflare/workers-sdk/blob/main/packages/create-cloudflare/telemetry.md
──────────────────────────────────────────────────────────────────────────────────────────────────────────

╭ Create an application with Cloudflare Step 1 of 3
│
├ In which directory do you want to create your application?
│ dir ./.
│
╰ What would you like to start with?
  ● Hello World example
  ○ Framework Starter
  ○ Application Starter
  ○ Template from a GitHub repo
  ◁ Go back

  Select from barebones examples to get started with Workers

ここで、Hello World example のままエンターキーを押します。

╰ Which template would you like to use?
  ○ Worker only
  ○ Static site
  ● SSR / full-stack app
  ○ Worker + Durable Objects
  ○ Worker + Durable Objects + Assets
  ○ Workflow
  ○ Scheduled Worker (Cron Trigger)
  ○ Queue consumer & producer Worker
  ○ API starter (OpenAPI compliant)
  ◁ Go back

--(上矢印2回押すと)----------------

For sites with a backend API, or server-side rendering (SSR). Uses Static Assets with a Worker.

  ╰ Which template would you like to use?
  ● Worker only
  ○ Static site
  ○ SSR / full-stack app
  ○ Worker + Durable Objects
  ○ Worker + Durable Objects + Assets
  ○ Workflow
  ○ Scheduled Worker (Cron Trigger)
  ○ Queue consumer & producer Worker
  ○ API starter (OpenAPI compliant)
  ◁ Go back

  For sites with a backend API, or server-side rendering (SSR). Uses Static Assets with a Worker.

テンプレート、何使う?って聞いてくれるので、上矢印を 2 回押して Worker only を選択し、エンターキーを押します。

╰ Which language do you want to use?
  ● TypeScript
  ○ JavaScript
  ○ Python (beta)
  ◁ Go back

実装言語を聞いてきますので、TypeScript のままエンターキーを押します。

ブワーッと初期化をしてくれるので、お茶 :tea: を啜って待ちます。

したらば、

╰ You're in an existing git repository. Do you want to use git for version control?
  Yes / No

git で管理しますか?って聞いてくるので、好きに選択していただき、

╭ Deploy with Cloudflare Step 3 of 3
│
╰ Do you want to deploy your application?
  Yes / No

Deploy しますか?って聞いてくるので、一旦 No を選択しておきます。

これでプロジェクトのセットアップは終わりです。

2. コードを書く

を参考に、コードを書いていきます。

src/index.ts
const NAME = 'myExampleABTest';

export default {
	async fetch(req: Request): Promise<Response> {
		const url = new URL(req.url);

		if (url.pathname.endsWith('.ico'))
			return new Response(null, { status: 404 });

		if (url.pathname.startsWith('/a') || url.pathname.startsWith('/b')) {
			return fetch(req)
		}

		const cookie = req.headers.get('cookie');
		if (cookie && cookie.includes(`${NAME}=a`)) {
			url.pathname = '/a' + url.pathname;
		} else if (cookie && cookie.includes(`${NAME}=b`)) {
			url.pathname = '/b' + url.pathname;
		} else {
			const group = Math.random() < 0.5 ? 'a' : 'b';
			if (group === 'a') {
				url.pathname = '/a' + url.pathname;
			} else {
				url.pathname = '/b' + url.pathname;
			}

			let res = await fetch(url);
			res = new Response(res.body, res);

			res.headers.set('Set-Cookie', `${NAME}=${group}; path=/;`);
			return res;
		}

		return fetch(url);
	},
} satisfies ExportedHandler;

元のコードから変更したところといえば

  • A/B をわかりやすくした
  • favicon.ico を 404 で返すようにした

くらいです。

コードの解説ですが、今回のケースでは、/ にアクセスしたら Cookie を見に行きます。

Cookie が書き込まれていたら、取ってくる htmlpathab に切り替えます。

Cookie がなければ、新しくアクセスしてきたと判断して、乱数で ab を設定し、pathab に切り替えます。

で、Workers から切り替えた path に向かってリクエストを飛ばして、取ってきた html をブラウザに返します。

リクエストの動き方

起動してみましょう!

Console
> pnpm run dev

 ⛅️ wrangler 4.47.0
───────────────────
╭──────────────────────────────────────────────────────────────────────╮
│  [b] open a browser [d] open devtools [c] clear console [x] to exit  │
╰──────────────────────────────────────────────────────────────────────╯
⎔ Starting local server...
[wrangler:info] Ready on http://127.0.0.1:8787

サーバーが動きました。
ブラウザで http://127.0.0.1:8787 を開きます。

………開きません。

待てど暮らせど、開きませんね。

Cloudflare Workers はページリンクをもらっていますが、肝心のリンク先がないのです。

ということで、一旦 Ctrl + C で止めましょう。

肝心の html も Workers から返せるようにする

html を静的リソースとして、Workers にもたせることができます。

ということで、まずは assets ディレクトリを切ります。

そして、2 つ html ファイルを書きます。

assets/a.html
<html>
	<head>
		<title>Page A</title>
	</head>
	<body>
		<h1>Welcome to Page A</h1>
		<p>This is the A version of the A/B test.</p>
	</body>
</html>
assets/b.html
<html>
	<head>
		<title>Page B</title>
	</head>
	<body>
		<h1>Welcome to Page B</h1>
		<p>This is the B version of the A/B test.</p>
	</body>
</html>

そして、wrangler.jsonc をいじって、html ファイルを返せるようにします。

wrangler.jsonc
{
	"$schema": "node_modules/wrangler/config-schema.json",
	"name": "cf-use-up-worker-basic-ab-testing",
	"main": "src/index.ts",
	"compatibility_date": "2025-11-15",
	"observability": {
		"enabled": true
	},
	"assets": { "directory": "./assets/", "binding": "ASSETS" }
}

これで、Workers が html ファイルを返してくれるようになります。

そして、pnpm dlx wrangler typesenv の型定義を更新します。

で、デプロイできるようにコードを修正します。(詳細は省略)

src/index.ts
const NAME = 'myExampleABTest';

export default {
-	async fetch(req: Request): Promise<Response> {
+	async fetch(req: Request, env: Env): Promise<Response> {
		const url = new URL(req.url);

		if (url.pathname.endsWith('.ico'))
			return new Response(null, { status: 404 });

		if (url.pathname.startsWith('/a') || url.pathname.startsWith('/b')) {
-			return fetch(req)
+			return env.ASSETS.fetch(req)
		}

		const cookie = req.headers.get('cookie');
		if (cookie && cookie.includes(`${NAME}=a`)) {
			url.pathname = '/a' + url.pathname;
		} else if (cookie && cookie.includes(`${NAME}=b`)) {
			url.pathname = '/b' + url.pathname;
		} else {
			const group = Math.random() < 0.5 ? 'a' : 'b';
			if (group === 'a') {
				url.pathname = '/a' + url.pathname;
			} else {
				url.pathname = '/b' + url.pathname;
			}

-			let res = await fetch(url);
+			let res = await env.ASSETS.fetch(url);
			res = new Response(res.body, res);

			res.headers.set('Set-Cookie', `${NAME}=${group}; path=/;`);
			return res;
		}

-		return fetch(req)
+		return env.ASSETS.fetch(req)
	},
- } satisfies ExportedHandler;
+ } satisfies ExportedHandler<Env>;

早速 pnpm run dev で実行して、http://127.0.0.1:8787 にアクセスしてみましょう。

image.png

Page A が表示されました!(この画面は人により異なります。)

開発者モードを開いて、Cookie を見てみますと

image.png

値が a になっていることが確認できました。
(Page B が見えていたら b になっているはずです。)

ここの値を a から b (b なら a) にしてみましょう。
そしてリロードしてみますと、

image.png

Page B になりました。

Cookie を消してみましょう。
50% の確率で Page B が Page A になります。

私はなりませんでした。
なった皆さんは、明日なくした靴下の片方が見つかります。おめでとうございます。

3. デプロイ

動くことがわかりましたので、Cloudflare の世界ネットワークに乗っけてみます。

wrangler login で、Wrangler にデプロイするアカウントを教えます。

> pnpm dlx wrangler login

すると、勝手にブラウザが開いて、ログインを要求されます。

image.png

で、リダイレクトしますので、内容を読んで、許可します。

image.png

閉じていいよ!って出ますので、閉じます。

そしたら、いよいよデプロイです。

> pnpm dlx wrangler deploy

実行するだけで、うにゃうにゃしてくれます。

 ⛅️ wrangler 4.47.0
───────────────────
🌀 Building list of assets...
✨ Read 2 files from the assets directory hogehoge\assets
🌀 Starting asset upload...
No updated asset files to upload. Proceeding with deployment...
Total Upload: 1.03 KiB / gzip: 0.46 KiB
Your Worker has access to the following bindings:
Binding            Resource      
env.ASSETS         Assets

Uploaded hogehoge (5.22 sec)
Deployed hogehoge (1.35 sec)
  https://hogehoge.yourname.workers.dev
Current Version ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Deployed の下にある workers.dev のリンクにアクセスしてみましょう。

image.png

Cloudflare に乗っかった A/B テストの完成です。

まとめ

Cloudflare Workers について、ざっくりとした概要、そして仕組みをまとめました。
そして、実際に A/B テストを作ってみて、デプロイまでこぎつけました。

Cloudflare Workers はいくらでも便利な使い方ができそうです。

▼ 一覧

ぜひ、いろんなことをやってみてください。

Cloudflare ことはじめとして、参考になれば幸いです。

Appendix

この記事を書くうえで参考にしたドキュメントです。ぜひ読んでみてください。

Cloudflare Workers が出来上がった背景

V8 について

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?