このガイドでは、エンドユーザーからのリクエストに応じて、1 つ以上の Container へリクエストを送れる Worker をデプロイします。この例では、各コンテナが Go で書かれた小さな Web サーバーを実行します。
この例の Worker で、シンプルな Container の使い方を把握し、より複雑なユースケースの出発点にできます。
このガイドでは、Worker のコードとあわせてコンテナイメージをビルドしてプッシュします。デフォルトでは、この処理に Docker ↗ を使います。
wrangler deploy を実行するときは、ローカルで Docker が動いている必要があります。多くの場合、Docker のインストールには Docker Desktop のインストール手順 ↗ に従うのが最も簡単です。Colima ↗ など、ほかのツールでも動作する場合があります。
ターミナルで docker info を実行すると、Docker が正しく動いているかを確認できます。Docker が動いていれば、コマンドは成功します。Docker が動いていない場合、docker info はハングするか、「Cannot connect to the Docker daemon」を含むエラーを返します。
スターターテンプレートから、コンテナ付きの新しい Worker を作成してデプロイするには、次のコマンドを実行します。
npm create cloudflare@latest -- --template=cloudflare/templates/containers-templateyarn create cloudflare --template=cloudflare/templates/containers-templatepnpm create cloudflare@latest --template=cloudflare/templates/containers-templateWorker または Container のコードを変更してデプロイするときは、Wrangler CLI で次のコマンドを実行できます。
npx wrangler deployyarn wrangler deploypnpm wrangler deployデプロイ時、Wrangler は Worker をアップロードし、Docker でコンテナイメージをビルドしてプッシュし、Cloudflare のネットワーク上のコンテナインスタンスを更新します。最初のビルドとプッシュが、通常いちばん時間がかかります。以降のデプロイでは キャッシュされたイメージレイヤーを再利用 ↗ します。
デプロイ後、アカウント内のコンテナとその状態を一覧表示します。
npx wrangler containers listyarn wrangler containers listpnpm wrangler containers listCloudflare Registry のイメージを一覧表示します。
npx wrangler containers images listyarn wrangler containers images listpnpm wrangler containers images listWorker の URL を開きます。https://hello-containers.<YOUR_WORKERS_SUBDOMAIN>.workers.dev のような形式です。
/container/1または/container/2へのリクエストは、特定のコンテナへルーティングされます。/container/以降の各パスは、一意のコンテナに対応します。/lbへのリクエストは、ランダムに選ばれた 3 つのコンテナ間で負荷分散されます。
レスポンス本文を読み、どのインスタンスがリクエストを処理したかを確認します。Worker は応答するがコンテナのルートがまだエラーになる場合は、プロビジョニングを待ってから、ダッシュボードの Containers ↗ ログを確認してください。
最初のコンテナをデプロイできたので、Worker のコード、設定ファイル、コンテナのコード、リクエストのルーティングで何が起きているかを説明します。
Wrangler 設定ファイル で、Worker とコンテナの両方の設定を定義します。
{
"containers": [
{
"max_instances": 10,
"class_name": "MyContainer",
"image": "./Dockerfile",
},
],
"durable_objects": {
"bindings": [
{
"name": "MY_CONTAINER",
"class_name": "MyContainer",
},
],
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["MyContainer"],
},
],
}[[containers]]
max_instances = 10
class_name = "MyContainer"
image = "./Dockerfile"
[[durable_objects.bindings]]
name = "MY_CONTAINER"
class_name = "MyContainer"
[[migrations]]
tag = "v1"
new_sqlite_classes = [ "MyContainer" ]この設定の要点は次のとおりです。
imageは Dockerfile、Dockerfile を含むディレクトリ、またはregistry.cloudflare.com/<YOUR_ACCOUNT_ID>/<IMAGE>:<TAG>のような完全修飾のイメージ参照を指します。class_nameは Durable Object のクラス名 である必要があります。max_instancesは、同時に実行されるコンテナインスタンスの最大数を宣言します。- Durable Object は
new_classesではなくnew_sqlite_classesを使う必要があります。
コンテナイメージは linux/amd64 アーキテクチャで実行できる必要があります。それ以外の制限はほとんどありません。
今デプロイした例では、ポート 8080 でリクエストに応答するシンプルな Golang サーバーです。Worker で設定する MESSAGE 環境変数と、自動生成される環境変数 CLOUDFLARE_DEPLOYMENT_ID を使います。
func handler(w http.ResponseWriter, r *http.Request) {
message := os.Getenv("MESSAGE")
instanceId := os.Getenv("CLOUDFLARE_DEPLOYMENT_ID")
fmt.Fprintf(w, "Hi, I'm a container and this is my message: %s, and my instance ID is: %s", message, instanceId)
}まず、Container ↗ クラスを継承する MyContainer に注目します。
export class MyContainer extends Container {
defaultPort = 8080;
sleepAfter = '10s';
envVars = {
MESSAGE: 'I was passed in via the container class!',
};
override onStart() {
console.log('Container successfully started');
}
override onStop() {
console.log('Container successfully shut down');
}
override onError(error: unknown) {
console.log('Container error:', error);
}
}これはコンテナの基本設定を定義します。
defaultPortは、fetchとcontainerFetchメソッドがコンテナとの通信に使うポートを設定します。コンテナがこのポートでリッスンするまで、リクエストもブロックします。sleepAfterは、一定時間アイドルになったあとコンテナがスリープするまでのタイムアウトを設定します。envVarsは、起動時にコンテナへ渡す環境変数を設定します。onStart、onStop、onErrorは、それぞれコンテナの起動、停止、エラー時に実行されるフックです。
Container クラス自体は DurableObject を継承しているため、サブクラスは Durable Object API 全体を使えます。Durable Object がルーティング、ライフサイクル、永続状態を扱い、コンテナプロセスは Linux VM 内でイメージを実行します。そのため this.ctx.storage を使い、コンテナの再起動後も残り、コンテナ自身の近くに置かれるデータを永続化できます。
詳細は Container クラスのリファレンス と 低レベルの Durable Object container API を参照してください。
リクエストが Cloudflare に入ると、Worker の fetch ハンドラー が呼び出されます。これが受信リクエストを処理するコードです。例のコードの fetch ハンドラーは、異なるルートで 2 通りの方法でコンテナを起動します。
-
/container/へのリクエストは、パスごとに新しいコンテナへ渡されます。新しい Container インスタンスを起動して行います。新しいパスへの最初のリクエストは、以降のリクエストより時間がかかることがあります。新しいコンテナが起動しているためです。if (pathname.startsWith("/container")) { const container = env.MY_CONTAINER.getByName(pathname); return await container.fetch(request); } -
/lbへのリクエストは、複数のコンテナ間で負荷分散します。シンプルなgetRandomヘルパーメソッドを使い、固定数(この例では 3)から ID をランダムに選び、その Container インスタンスへルーティングします。実装する任意のルーティングまたは負荷分散ロジックに置き換えられます。if (pathname.startsWith("/lb")) { const container = await getRandom(env.MY_CONTAINER, 3); return await container.fetch(request); }
これにより、Container の使い方は複数あります。
- ステートレスで交換可能な多数のコンテナへリクエストを送りたいだけなら、負荷分散を使います。
- ステートフルなサービスがある、または個別にアドレス可能なコンテナが必要なら、特定の Container インスタンスをリクエストします。
- 短命のジョブを実行する、コンテナのライフサイクルを細かく制御したい、コンテナのエントリポイントや環境変数をパラメータ化したい、複数のコンテナ呼び出しを連鎖させたい、といった場合も、特定の Container インスタンスをリクエストします。
Containers ダッシュボード ↗ では、Container に関する次のような情報を確認できます。
- ステータスとヘルス
- メトリクス
- ログ
Worker を起動したあと、ダッシュボードのサイドバーで Workers & Pages > Containers を選び、Containers ダッシュボードを開きます。
さらに進めるには、次を試してください。
- Dockerfile を変更して
wrangler deployを実行し、イメージを変更する - Workers Builds とロールアウトの動作は Container のデプロイ を参照する
- ほかのパターンは 例 を参照する
- プラットフォームの動作と制限は よくある質問 を確認する