メインコンテンツへスキップ
見出し画像

エコシステムを使い倒せ!Cloudflare Workers×D1×KV×AI Gatewayで構築するモダンサーバーレス基盤

    こんにちは!Accel-Hack(アクセルハック) 開発チームです。

    社内AIアシスタント「Airi」の開発プロセスをお届けする開発記ブログ。
    第7回目となる今回は、Airi のシステム全体を支えるインフラ基盤について詳しくご紹介します。

    前回の Vol.6 では、エッジ環境に最適化された軽量Webフレームワーク「Hono」を採用し、APIルーターとしての基盤を構築したお話をしました。

    今回は、その Hono アプリケーションが動作するステージであり、データベースやキャッシュ、非同期処理、LLMプロキシまでをすべて内包する強力なプラットフォーム 「Cloudflare(クラウドフレア)」 のフルスタックサーバーレスエコシステムについて解説します。

    個人開発からスタートアップ、さらには大規模エンタープライズまで、インフラ運用コストと管理のオーバーヘッドを極限まで削減しつつ、超高速なレスポンスを実現するモダンなインフラ設計の全貌に迫ります!


    1. 導入:インフラ運用コスト「ほぼゼロ」を目指すAIアシスタントの設計

    私たちが社内アシスタント「Airi」を開発するにあたり、設計の初期段階から強く意識していたのが 「インフラの運用管理コストを徹底的に削減すること」 でした。

    スタートアップや小規模な開発チームにおいて、インフラのパッチ当てやスケーリング設定、複雑なネットワークセキュリティの構築に時間を取られるのは、プロダクトの価値創造という観点から大きな機会損失になります。
    また、Slack Appのようにインタラクティブな応答が求められるシステムでは、サーバーの「コールドスタート(起動遅延)」によるもっさりとした動作は、ユーザー体験(UX)を著しく損ないます。

    これらの課題を解決するための要件は以下の通りでした。

    1. マネージドサービスであり、プロビジョニングやスケーリングの管理が不要なこと

    2. コールドスタートが極めて短く、ユーザーがストレスを感じない応答速度であること

    3. データベース、キャッシュ、非同期処理、そしてAIリクエストの制御がシンプルに連携できること

    4. 初期の運用コスト(ランニングコスト)を最小限に抑えられること

    これらすべての要件に完璧な答えを出してくれたのが、Cloudflareが提供する開発者向けプラットフォームでした。


    2. なぜ Cloudflare なのか? フルスタックサーバーレスがもたらす開発革命

    従来、サーバーレスでリレーショナルデータベースやメッセージキュー、キャッシュなどを含むフルスタックな構成を作ろうとすると、AWS(Lambda + RDS + ElastiCache + SQS)などを組み合わせるのが一般的でした。
    しかし、これらを連携させるためには、VPC(仮想プライベートネットワーク)の設計やIAMロールの細かな設定、接続プールの管理など、インフラエンジニアでなければ頭を抱えるような複雑な構築作業が必要になります。

    一方で、Cloudflare のエコシステムは「最初からすべてが密結合かつセキュアに統合されている」のが最大の特徴です。

    ① インフラ管理からの解放と圧倒的な起動速度

    Cloudflare Workers は、一般的なコンテナや仮想マシンベースのサーバーレス(AWS Lambda など)とは異なり、Google Chrome でも使われている V8 エンジンの「Isolate(分離環境)」技術を採用しています。これにより、コンテナの起動を待つ必要がなく、コールドスタートは実質ゼロ(数ミリ秒以下)で動作します。

    ② Wrangler CLI によるシームレスなローカル開発とデプロイ

    Cloudflare の開発ツールである wrangler を使用すると、ローカル環境でも本番とほぼ同じエッジ環境をエミュレート(Miniflare)して開発できます。
    また、bun run deploy のようなコマンド一発で、世界中に張り巡らされた Cloudflare のエッジネットワークへ数秒でコードがデプロイされます。

    ③ 開発者を惹きつける強力な無料枠

    Cloudflare の各サービス(Workers, D1, KV など)には非常に寛大な無料枠が設定されています。
    社内ツールとして数十人〜数百人規模で運用するレベルであれば、月々のサーバー費用はほぼゼロ円(無料枠内)で運用することが可能です。


    3. Airi を支える Cloudflare ファミリーとその役割

    Airi のインフラは、単にプログラムが動くサーバーがあるだけではありません。
    データの保存、セッション管理、バックグラウンドでの非同期処理、そしてLLMリクエストの仲介まで、すべて Cloudflare の機能群で完結しています。

    システム構成の全体像は以下のようになっています。

    画像

    それぞれのコンポーネントが、Airi においてどのような役割を担っているのかを詳しく解説します。

    ① Cloudflare Workers(アプリケーション実行基盤)

    Airi のメインロジックが動作するエッジサーバーです。
    Hono で記述された Web API や、Slack App からのリクエストを受け取る Webhook レシーバーとして機能します。
    世界中のユーザーに最も近いエッジサーバーで動作するため、リクエストを受信してから応答を開始するまでのネットワーク遅延が極限まで抑えられます。

    ② Cloudflare D1(エッジ向けサーバーレスデータベース)

    SQLite をベースにした、Cloudflare 純正のサーバーレスリレーショナルデータベースです。
    Airi では、ユーザーの登録情報、Slack チャンネルの設定、勤怠打刻のログなどを保存しています。
    エッジ環境から直接超低レイテンシでアクセスでき、データベースのプロビジョニングや接続プールの制限を気にする必要がありません。
    また、スキーマのマイグレーションも wrangler コマンドで簡単に管理できます。

    ③ Cloudflare KV(超高速 Key-Value ストア)

    読み込み処理が非常に高速に行える、グローバルに分散された Key-Value データベースです。
    Airi では主に以下の用途で使用しています。

    • ユーザーのログインセッション情報

    • OAuth 認証時の一時的なステート(state パラメータ)の保持

    • 頻繁に参照されるが、変更頻度の低いキャッシュデータ

    数ミリ秒で読み込めるため、APIの応答速度向上に大きく貢献しています。

    ④ Cloudflare Queues(非同期メッセージキュー)

    信頼性の高い非同期処理を実現するためのメッセージキューイングサービスです。
    Slack などのチャットインターフェースでは、「リクエストを受け取ってから3秒以内にレスポンス(HTTP 200 OK)を返さなければならない」という厳しいタイムアウト制限があります。
    しかし、GitHub のプルリクエスト情報を収集したり、Google Calendar と同期したりする重い外部 API 連携では、3秒以内に処理が完了しないケースがあります。
    そこで、Airi ではリクエストを受け取ると、一度そのタスク情報を Cloudflare Queues に投げ、即座に Slack へ「処理を受付しました」と応答を返します。
    その後、バックグラウンドで Workers がキューからタスクを取り出して時間をかけて重い非同期処理を実行します。
    万が一、外部 API の一時的な障害で処理が失敗しても、自動的にリトライが行われるため、タスクの消失を防ぐことができます。

    ⑤ Cloudflare AI Gateway(LLMリクエストプロキシ)

    Airi は、Anthropic (Claude) や Google (Gemini) などの LLM と通信する AI アシスタントです。
    Cloudflare AI Gateway は、これらの外部 LLM API へのリクエストを中継するプロキシとして動作します。
    AI Gateway を挟むだけで、以下の恩恵を受けることができます。

    • リクエストのキャッシュ: 同じ質問やプロンプトに対する回答をエッジ側でキャッシュし、API通信コストを節約しつつ、ミリ秒単位で超高速に応答します。

    • リクエストのロギングと分析: どの機能がどれくらいトークンを消費したのか、どのようなエラーが発生したのかを Cloudflare のダッシュボードで一元管理できます。

    • レート制限とリトライ: LLM API のレート制限にかかった際のフォールバック処理をプロキシ側で制御できます。


    4. 実践:Airi における wrangler.toml の構成とバインディング

    これらの強力な Cloudflare ファミリーを Hono アプリケーションから利用するためには、設定ファイルである wrangler.toml で「バインディング」を定義するだけです。

    以下は、Airi で実際に使用されている wrangler.toml の設定例です(機密情報はダミーに変更しています)。

    # wrangler.toml
    name = "airi"
    main = "index.ts"
    compatibility_date = "2024-04-01"
    compatibility_flags = ["nodejs_compat"]
    
    # フロントエンド静的アセットの設定 (SPAとの統合)
    [assets]
    directory = "./frontend/dist"
    binding = "ASSETS"
    
    # テキストファイルなどのバンドルルール
    [[rules]]
    type = "Text"
    globs = ["**/*.md", "**/*.html", "**/*.txt"]
    fallbacks = []
    fallthrough = true
    
    # 環境変数 (シークレットは wrangler secret put で別途登録)
    [vars]
    APP_URL = "https://airi.example.com"
    FREEE_CLIENT_ID = "YOUR_FREEE_CLIENT_ID"
    GITHUB_CLIENT_ID = "YOUR_GITHUB_CLIENT_ID"
    
    # Cloudflare KV のバインディング
    [[kv_namespaces]]
    binding = "CF_AIRI_KV"
    id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    
    # Cloudflare D1 (データベース) のバインディング
    [[d1_databases]]
    binding = "CF_AIRI_DB"
    database_name = "airi-db"
    database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    
    # Cloudflare Queues (プロデューサー側) のバインディング
    [[queues.producers]]
    binding = "GITHUB_QUEUE"
    queue = "airi-github"
    
    # Cloudflare Queues (コンシューマー側) のバインディング
    [[queues.consumers]]
    queue = "airi-github"
    max_batch_size = 1
    max_batch_timeout = 5
    max_retries = 2
    retry_delay = 30
    
    # 定期実行 (Cron Triggers) のスケジュール設定
    [triggers]
    crons = [
        "0 20 * * 1-5", # 平日夜の自動日報サマリー作成用
        "0 0 * * *",     # 日次データクリーンアップ用
    ]

    TypeScript / Hono 側でのバインドの受け取り

    このように wrangler.toml で指定した binding の名前(例:CF_AIRI_DB や CF_AIRI_KV)は、Workers のランタイムによってグローバルなコンテキストに注入されます。
    Hono では、以下のように環境変数の型(AppEnv)を定義し、ジェネリクスとして渡すことで、コード全体で型安全にインフラリソースを操作できます。

    import type { D1Database, KVNamespace, Queue } from "@cloudflare/workers-types";
    
    export type AppEnv = {
      APP_URL: string;
      CF_AIRI_KV: KVNamespace;
      CF_AIRI_DB: D1Database;
      GITHUB_QUEUE: Queue;
      // ...
    };
    
    // Hono インスタンスの初期化
    const app = new Hono<{ Bindings: AppEnv }>();
    
    app.get("/users", async (c) => {
      // c.env を通じて、自動的に型補完された D1 や KV にアクセス可能!
      const db = c.env.CF_AIRI_DB;
      const { results } = await db.prepare("SELECT * FROM users").all();
    
      return c.json(results);
    });

    SDKのインポートコードや複雑なデータベースクライアントの初期化(ホスト名やポート指定、認証情報の受け渡しなど)を一切書くことなく、c.env.CF_AIRI_DB を呼び出すだけでデータベースと通信できるこのスマートさは、Cloudflare サーバーレス最大の魅力です。


    5. 学びと成果:インフラ管理コストの最小化とAIエージェントの未来

    Airi のインフラ基盤を Cloudflare に一本化したことで、開発チームは多くの素晴らしい恩恵を得ることができました。

    1. インフラの管理コストが「ゼロ」になった サーバーの死活監視やOSのアップデート、スケールアウト設定といった従来の運用業務から完全に解放されました。

    2. 開発メンバーは純粋に「機能(TypeScript コード)」の追加だけに集中できています。

    3. ローカル開発と本番環境のギャップが極小化した Wrangler によるローカルエミュレータ(Miniflare)の完成度が高く、「ローカルでは動いたけれど本番環境だけでバグが出る」といったインフラ由来のトラブルがほぼ発生しなくなりました。

    4. 爆速のリリースサイクル Wrangler CLI と GitHub Actions を組み合わせた CI/CD フローにより、git push から数分後には、世界中のエッジサーバーに新機能が安全にデプロイされます。
      デプロイ中のサービス停止(ダウンタイム)も発生しません。


    6. おわりに

    Airi の開発において、Cloudflare は単なる「サーバーの置き場所」ではなく、開発スピードを何倍にも加速させるための統合型プラットフォームとして機能しています。
    Workers, D1, KV, Queues, そして AI Gateway という強力な構成パーツが最初からパズルのように噛み合っているからこそ、Airi は小さく産んで大きく育てるアジャイルな開発を継続できています。

    さて、インフラ基盤が整ったところで、次に重要になるのが 「データベース内のデータをいかに安全かつ直感的に操作するか」 です。
    次回は、Cloudflare D1 と組み合わせて Airi の型安全なデータアクセスレイヤーを支えている、「Vol. 8: 型安全なデータベース操作「Drizzle ORM」」 について解説します!

    スキーマ定義と TypeScript の型をシームレスに同期させる快適なデータモデリングの裏側をお届けしますので、ぜひ楽しみにお待ちください!


    この記事は以下の体制で作成されました。

    • ドラフト作成・執筆: Airi (社内AIアシスタント)

    • アイデア出し・レビュー: CTO

    • デザイン: 事務スタッフ

    Accel-Hackでは、テクノロジーを駆使して世の中の課題を解決していく仲間を募集しています。
    私たちの取り組みに少しでも興味を持っていただけたら、ぜひ採用ページや会社サイトも覗いてみてくださいね。


    あなたへのおすすめ