Workersのデプロイコマンド

Page content

Cloudflare Workersのデプロイコマンドと動作の違いについて説明します。Cloudflare Workersのデプロイコマンドと、それによってWorkerの動作がどう変わるかを整理します。各コマンドについて詳しく説明します。


wrangler dev — ローカル開発

Workerはデプロイされず、リクエストはローカルマシン上で処理されます。

フラグによる動作の違い:

  • デフォルト(フラグなし) — Cloudflareのエッジにリクエストをプロキシしつつ、コードはローカルで実行。KV・D1などのバインディングはプレビュー用のサンドボックスを参照します。
  • --local — Miniflareを使った完全ローカルエミュレーション。インターネット不要で動作し、CI環境やオフライン開発に向いています。
  • --remote — コードはローカルで動くが、KVやD1・R2などは本番リソースに接続。「ローカルコード × 本番データ」で検証したい場合に使います(本番データを読み書きするため注意が必要)。

wrangler deploy — 本番デプロイ

コードをビルドしてCloudflareのグローバルエッジネットワーク(300拠点以上)に即時配信します。デプロイ後、数秒以内に全世界に反映されます。

--env で環境を切り替え:

# wrangler.toml
[env.staging]
route = "staging.example.com/*"
vars = { API_URL = "https://api-staging.example.com" }

[env.production]
route = "example.com/*"
vars = { API_URL = "https://api.example.com" }
  • wrangler deploy --env staging → stagingルートにデプロイ、stagingの変数を使用
  • wrangler deploy --env production → 本番ルートにデプロイ、本番の変数を使用

環境ごとに別のWorkerスクリプトとして登録されるため、stagingと本番が独立して動作します。


バージョン管理コマンド(段階的ロールアウト)

大規模なトラフィックへの影響を抑えながら新バージョンを公開したい場合に使います。

# バージョンをアップロードのみ(まだトラフィックには流れない)
wrangler versions upload

# トラフィックの10%だけ新バージョンに流す
wrangler versions deploy --version-id <id> --percentage 10

# 問題があれば即ロールバック
wrangler rollback

コマンドまとめ

コマンド Workerの動作
wrangler dev ローカル実行、デプロイなし
wrangler dev --local 完全オフライン実行
wrangler dev --remote ローカルコード+本番リソース
wrangler deploy 全エッジに即時反映
wrangler deploy --env staging staging環境のみに反映
wrangler versions upload バージョン登録のみ
wrangler versions deploy 割合指定で段階公開
wrangler rollback 前バージョンに戻す

バインディング設定について詳しく説明します。まず全体の構造をひと目で把握できる図から始め、その後各バインディングの詳細と実際のコードを説明します。Workerはすべてのバインディングを env オブジェクト経由で受け取ります。wrangler.toml での宣言と、コード内での使い方をバインディングごとに説明します。


KV Namespace — キー/バリューストア

グローバルに複製される超高速ストア。セッション、設定値、キャッシュに最適です。

# wrangler.toml
[[kv_namespaces]]
binding = "MY_KV"          # env.MY_KV でアクセス
id = "xxxxxxxxxxxxxxxx"    # 本番KVのID
preview_id = "yyyyyyyy"    # wrangler dev 用のプレビューID
// Worker コード
export default {
  async fetch(req: Request, env: Env) {
    // 書き込み(TTLも指定可能)
    await env.MY_KV.put("user:123", JSON.stringify({ name: "Taro" }), {
      expirationTtl: 3600,  // 1時間で自動削除
    });

    // 読み込み
    const val = await env.MY_KV.get("user:123", { type: "json" });

    // 削除
    await env.MY_KV.delete("user:123");

    // キー一覧(prefix で絞り込み可)
    const list = await env.MY_KV.list({ prefix: "user:" });
  }
};

注意点として、KVは結果整合性(書き込み後の伝播に最大60秒かかる場合あり)なので、即時一貫性が必要な用途にはD1を使います。


D1 Database — SQLite互換のリレーショナルDB

[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "xxxxxxxxxxxxxxxx"
export default {
  async fetch(req: Request, env: Env) {
    // 単一クエリ
    const user = await env.DB.prepare(
      "SELECT * FROM users WHERE id = ?"
    ).bind(123).first();

    // 複数行取得
    const { results } = await env.DB.prepare(
      "SELECT * FROM users WHERE active = 1"
    ).all();

    // バッチ実行(複数クエリをアトミックに)
    await env.DB.batch([
      env.DB.prepare("INSERT INTO logs (msg) VALUES (?)").bind("started"),
      env.DB.prepare("UPDATE users SET last_seen = ? WHERE id = ?")
        .bind(Date.now(), 123),
    ]);
  }
};

マイグレーションは wrangler d1 migrations apply DB --remote で実行します。


R2 Bucket — オブジェクトストレージ

S3互換で、画像・動画・大容量ファイルの保存に使います。エグレス(転送)料金が無料なのが大きな特徴です。

[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "my-app-assets"
preview_bucket_name = "my-app-assets-dev"  # dev用
export default {
  async fetch(req: Request, env: Env) {
    const url = new URL(req.url);
    const key = url.pathname.slice(1);  // "/image.png" → "image.png"

    if (req.method === "PUT") {
      // アップロード
      await env.MY_BUCKET.put(key, req.body, {
        httpMetadata: { contentType: req.headers.get("Content-Type") ?? "" },
        customMetadata: { uploadedBy: "worker" },
      });
      return new Response("OK");
    }

    // ダウンロード
    const obj = await env.MY_BUCKET.get(key);
    if (!obj) return new Response("Not found", { status: 404 });

    return new Response(obj.body, {
      headers: { "Content-Type": obj.httpMetadata?.contentType ?? "application/octet-stream" },
    });
  }
};

Durable Objects — ステートフルなオブジェクト

リアルタイムコラボや WebSocket セッション管理など、「1箇所で状態を持つ」用途に使います。

[[durable_objects.bindings]]
name = "ROOM"
class_name = "ChatRoom"

[[migrations]]
tag = "v1"
new_classes = ["ChatRoom"]
// Durable Object クラス(同じWorkerファイルに定義)
export class ChatRoom {
  state: DurableObjectState;
  constructor(state: DurableObjectState) {
    this.state = state;
  }

  async fetch(req: Request) {
    // 永続ストレージへの読み書き
    const count = (await this.state.storage.get<number>("count")) ?? 0;
    await this.state.storage.put("count", count + 1);
    return new Response(`count: ${count + 1}`);
  }
}

// Worker 本体
export default {
  async fetch(req: Request, env: Env) {
    // IDによって「どのインスタンスか」を決定
    const id = env.ROOM.idFromName("room-general");
    const stub = env.ROOM.get(id);
    return stub.fetch(req);  // そのインスタンスへ転送
  }
};

Queues — 非同期メッセージキュー

Workerをプロデューサー(送信側)とコンシューマー(受信側)に分けて設定します。

# 送信側(Producer)
[[queues.producers]]
binding = "MY_QUEUE"
queue = "my-task-queue"

# 受信側(Consumer)
[[queues.consumers]]
queue = "my-task-queue"
max_batch_size = 10       # 一度に処理するメッセージ数
max_batch_timeout = 5     # 秒
max_retries = 3
export default {
  // Producer: キューにメッセージを送る
  async fetch(req: Request, env: Env) {
    await env.MY_QUEUE.send({ userId: 123, action: "welcome_email" });
    return new Response("Queued!");
  },

  // Consumer: バッチでメッセージを受け取る
  async queue(batch: MessageBatch, env: Env) {
    for (const msg of batch.messages) {
      console.log(msg.body);  // { userId: 123, action: "welcome_email" }
      msg.ack();              // 処理完了を通知
    }
  }
};

Service Bindings — Worker間のゼロレイテンシ通信

複数のWorkerを連携させる際に使います。インターネットを経由せず内部で直接呼び出されます。

[[services]]
binding = "AUTH_SERVICE"
service = "my-auth-worker"  # 別Workerの名前
export default {
  async fetch(req: Request, env: Env) {
    // 別のWorkerをHTTPリクエストと同じ感覚で呼び出せる
    const authRes = await env.AUTH_SERVICE.fetch(
      new Request("https://internal/verify", {
        method: "POST",
        body: JSON.stringify({ token: req.headers.get("Authorization") }),
      })
    );

    if (!authRes.ok) return new Response("Unauthorized", { status: 401 });
    return new Response("Hello, authenticated user!");
  }
};

環境変数とシークレット

バインディングではないですが、実務でよく使う設定です。

[vars]
ENVIRONMENT = "production"
API_BASE_URL = "https://api.example.com"

シークレット(APIキーなど)はコマンドで設定し、wrangler.toml には書きません:

wrangler secret put STRIPE_SECRET_KEY
# → プロンプトが出て、値を入力するとCF側に暗号化保存される

コード内ではどちらも env.ENVIRONMENTenv.STRIPE_SECRET_KEY と同じように参照できます。