🦔

Workers for Platforms で Cloudflare for SaaS の限界突破

に公開

プラットフォーム向けの Cloudfalre

Cloudflare for Platforms の dev docs をみると Cloudflare for SaaSWorkers for Platforms の二本立てになっています。

まず Cloudflare for SaaS ですが、Custom Hostnames(SSL for SaaS)を利用することで、Cloudflare のゾーン上で外部ドメイン(バニティドメイン)のリバースプロキシーが可能となります。あわせて Cloudflare が提供するセキュリティやパフォーマンス機能も適用することもできるため、SaaS プロバイダーが顧客の持ち込みドメインでサービス提供するのにうってつけのプラットフォームであり、様々な業種で利用されています

SaaS 向けのアーキテクチャは「スケールすること」が重要なため、いくつかの工夫がされているのですが、課題になるのが一つあります。

Workers の制限です。

たとえば、数万の Custom Hostnames がある場合 Security rulesets などは Custom Metadata でスケールさせることができますが、Workers に関してはアカウントあたりのスクリプト数 500、ゾーンごとのルート数 1000カスタムドメイン数 100 となっており、顧客ごとに Workers の環境を提供したい場合などに足かせになる場合があります。

Workers for Platforms はこんなときに候補となります。

Workers for Platforms 動作概要と参照アーキテクチャ

動作概要および参照アーキテクチャに詳細の記載がありますが、基本構成と動作は下記になります。

  • アカウントに dispatch namespace を作成し、そこに user worker をデプロイ
  • アカウントに dispatch worker をデプロイ、これが user worker へのルーティング行う

Workers for Platforms 基本設定と動作確認

Configure Workers for Platforms に従って進めます。
Paid plan が必要です。

... 12 は逆のほうがわかりやすいかも ...

  1. user worker の作成
    • リクエストに応答する user worker(Hello World!)
  2. dispatch namespace の作成
    • user worker を配置するための環境
      npx wrangler dispatch-namespace create testing
  3. user worker を dispatech namespace にデプロイ
    • user worker 1 を dispatech namespace 2 に配置
      npx wrangler deploy --dispatch-namespace testing
  4. dispatch worker の作成
    • dispatch namespace を Binding
    • dispatch namespace を介した user worker へのルーティング処理
    wrangler.jsonc
    "dispatch_namespaces": [
       {
         "binding": "DISPATCHER",
         "namespace": "testing"
       }
    ]
    
    src/index.js
    export default {
       async fetch(req, env) {
        const worker = env.DISPATCHER.get("customer-worker-1");
        return await worker.fetch(req);
      },
    };
    

  5. テスト
    curl https://my-dispatcher.<your-subdomain>.workers.dev/
    
    Hello World!%
    

この基本設定では user worker は一つだけ静的に指定されていました。

次はリクエストに応じ動的に user worker を選ぶ例になります。
Custom hostanmes のケースだとホスト名ごとに別の Workers に誘導する、などを目指します。

Custom hostnames には dynamic dispatch で対応

dispatcher worker は worker なので、動的に user worker を選択するルーティングロジックをプログラムすることができますね。
Custom hostnames に親和性がありそうなものとして、ドメイン(Workers KV 利用)やパスサブドメインを参照したルーティング例が示されています。

実際に下記の環境で試してみます。

custom hostnames
(顧客ドメイン@外部)
saas domain
(プロバイダードメイン@cloudflare)
1.oymk.click
2.oymk.click
oymk.work
  1. 顧客ドメイン DNS の設定

    • 顧客ドメインの権威サーバーは Custom hostname の Fallback ドメインに CNAME を向け HTTP リクエストを Cloudflare に誘導
    dig 1.oymk.click @ns-535.awsdns-02.net. +noal +an |grep -v ";"
    
    1.oymk.click.		30	IN	CNAME	pxfb.oymk.work.
    
  2. Custom hostnames の設定

    • ワイルドカードで顧客 oymk.click のサブドメインを一括受け入れ
      (TLS 証明書の設定運用を簡素化)
  3. user worker を 2 つ作成、dispatch namespace に展開

    • それぞれ Hello World にホスト名をつけて返すよう設定
    • despatch namespace にデプロイ
    npm create cloudflare@latest 1 -- --type=hello-world
    cd 1
    npx wrangler deploy --dispatch-namespace testing
    
    cd ..
    
    npm create cloudflare@latest 2 -- --type=hello-world
    cd 2
    npx wrangler deploy --dispatch-namespace testing
    
    cd ..
    
  4. dispatch worker をアップデート

    • ワイルドカードで顧客 oymk.click のサブドメインを一括受け入れ
    • ホスト名(ドメイン名の最初のラベル)を取り、同じ名前の user worker 1 2 にリクエストを送付
    tree -L 1
    .
    ├── 1
    ├── 2
    ├── customer-worker-1
    └── my-dispatcher
    
    cd ../my-dispatcher
    
    wrangler.jsonc
    "routes": [
      {
     	"pattern": "*.oymk.click/*",
     	"zone_name": "oymk.work"
      }
    ]
    
    src/index.js
    export default {
      async fetch(request, env) {
        try {
          // Extract user Worker name from subdomain
          // Example: customer1.example.com -> customer1
          const url = new URL(request.url);
          const userWorkerName = url.hostname.split('.')[0];
          // Get user Worker from dispatch namespace
          const userWorker = env.DISPATCHER.get(userWorkerName);
          return await userWorker.fetch(request);
        } catch (e) {
          if (e.message.startsWith('Worker not found')) {
            // User Worker doesn't exist in dispatch namespace
            return new Response('', { status: 404 });
          }
        // Could be any other exception from fetch() or from the dispatched Worker
       return new Response(e.message, { status: 500 });
      }
     }
    };
    
  5. テスト

    • ホスト名ごとにルーティング
    curl https://1.oymk.click/
    Hello World! this is 1%
    
    curl https://2.oymk.click/
    Hello World! this is 2%
    
  6. 拡張
    この要領で user workers の数やルーティングを上限なく増やすことができます。

Workers for Platforms 特徴や制限、可能性

Worker Isolation
dispatch namespace のモードに untrusted(デフォルト)と trusted があります。
モードにより動作や機能に違いが出てくるため、user workers 間のセキュリティと柔軟性のトレードオフを考え、サービスに親和性のある方に決めます。

制限
Workers for Platforms にも制限はあり、実際に検討する際はこのあたりを考慮し、設計を進めることになるでしょう。

さいごになりますが、いちばん大事なことを。

可能性

インターネット上のすべてのアプリケーションをよりプログラマブルに

プログラマブルにスケールするプラットフォーム、というのがコンポンの価値です。
Cloudflare for SaaS に留まらず、その可能性は無限大ということで。

以上です。
Paid plan で試す前にちょっと... の参考になれば幸いです。

Discussion