Tech系サービスやガジェットの使い心地、自分の作業環境、資産運用について気が向いたときに記録を残しています。

記事内のAmazonアソシエイト適格販売及び、Google Adsenseでお小遣いを得ています。

Gatsby CloudとCloudflareを利用した二重CDNで日本向けに効率よく配信する

TL; DR

  • Firebase Hostingのデプロイに時間がかかる
  • VSCodeでの執筆はやめたくない
  • 日本にエッジがないホスティングでもCloudflare経由でいい感じに配信できた

これまでの構成と課題

これまでは、Gatsby CloudでビルドしたアセットをFirebase Hostingを使ってホスティングしていた。

Gatsby Cloudに日本のCDN Edgeが無いため、TTBFなどの指標が悪く、定性的にも回線品質が良好な自宅のNW環境でもわかりやすくレスポンスが悪かったので、メインコンテンツをホスティングするには不適だと判断。ブログは画像も多いので、基本無料で従量課金もリーズナブルということでFirebase Hostingを使っていた。

ユーザー向けの体験は問題ないが、記事が多くなるにしたがってデプロイに時間がかかりすぎるというデメリットが大きくなってきた。

ビルド時間よりデプロイ時間の方が長い有様

直近では、ビルド時間が数分にもかかわらず10分以上もデプロイにかかってしまうという事態が頻発しており、ちょっとした更新でも反映が遅くストレスが高くなっていた。

ビルドに関してはGatsby Cloudでログを見ることができるのだが、デプロイコマンドは完全にブラックボックスで行われているため改善策が打てなかった。(おそらくファイル数が多すぎるのだと思う)

システム構成も数年変更を入れていない他、流石に心理的限界が来たのでビルド・デプロイのプロセスを見直すことにした。

検討内容

変更のPushから反映までの時間を短くするという観点で、いくつかの案を検討した。

ビルド時間とファイル数は殆どが画像ファイルの最適化によって生み出されるものなので、画像ファイル処理をどうにかするのが基本線。VSCodeと各種フォーマッタによる執筆体験は失わないようにするのが絶対要件。

  1. 現在ローカルファイルで管理している記事データを画像データをContentfulからの配信に切り替える(画像最適化オフロード+コンテンツ管理の外出し)
  2. 画像のみ画像CDNサービスを利用して配信する(画像最適化オフロード+画像管理のみ外出し)
  3. 二重CDNだけど、日本にエッジサーバーのあるCDNを噛ませてGatsby Cloudから配信する(デプロイ時間への対処)

1や2を基本線に考えており、ContentfulでもローカルMarkdownのように編集するツールがあったので1が最も良い候補に見えたのだが、Gatsby MDX v2プラグインではリモートのMDXを扱えない点が決め手になってしまいコンテンツはGitリポジトリ内という前提が新たに追加された。

3の場合、候補はAmazon CloudfrontとCloudflare。Cloudfrontの方が細かい設定に分があるが、DNSをCloudflareで管理していたこともあり運用対象が増えない点・完全無料である点を重視。まずはCloudflareで検証した後、リダイレクトルールなどを細かく設定したい場合はCloudfrontを使うという気構えで実装面の調査に入った。

検証

計画しているサービス間連携は上記の通り。

ユーザーに最も近い配信場所はCloudflareにするつもりだが、Gatsby CloudもCDNを持っているため、二重CDN構成となる上に、Gatsby CloudのCDNルールはかなりの部分隠蔽されている。不測の挙動があった場合はエスパー力が要求されると思われる。

移行前のテストとして、既存のドメインはFirebaseを向けたままテスト用のサブドメインを切ってGatsby Cloud Hostingに登録し、Cloudflare経由での配信を試みた

移行手順

Gatsby CloudはHostingオプションをONにする。

Firebaseのリダイレクト設定をGatsby Cloudで有効にするため、firebase.json に記載されていた内容をgatsby-node.tscreateRedirect構文で置き換える (gatsby-plugin-gatsby-cloudが必要)

設定画面上で独自ドメインを登録すると、SSL証明書を自動発行するためのCNAMEレコード(GatsbyCloud Hostingで割り当てられるドメイン)を指定するよう指示される。

Cloudflare側は、CDNを有効にするため、DNSでProxiedをONにしてレコードを登録する。

リダイレクトループを避けるため、HTTPS接続のみを利用するようSSL/TLS設定を変更することも忘れずに。

Cloudflare DNS Proxyと各ホスティングサービスの組み合わせ

ここで1つ問題が発生する。

Cloudflare DNSでキャッシングのためのProxyを有効にすると、設定上はCNAMEレコードがあるように見えるが、DNSレコードの実体はAレコードでCloudflareのIPアドレスを指す。

developers.cloudflare.com

つまり、Gatsby Cloud側でレコードが正常に設定されているように見えず、いつまで経ってもSSL証明書が発行されない。気持ち悪いので、試しにカスタムドメインGatsby Cloudに登録しない状態でDNSを向けたところ404となってしまった。

実際のアクセスはCNAMEはGatsby Cloudの所持しているサブドメインに向いているため、こちらでSSL証明書が使えれば問題無くクライアント・CDNからアクセスできるため今回はこのWarningを無視することにした。

※Firebaseはサブドメインに指定のレコードが正常登録されない場合、そもそもHostingが機能しない仕様だったが、Gatsby Cloudはカスタムドメインは登録さえすればHostingできるようだ

結果

レスポンスヘッダからCloudflareを介して配信されていることがわかる

レスポンスヘッダより、Cloudfrontを介して配信されていることがわかる。エッジ→オリジンまでもCloudflareのNWで最短ルートを通るようにしてくれるため、Gatsby Cloudのエッジが日本にないにもかかわらずCFでキャッシュが効き10msそこそこでレスポンスが返ってくる状態になってくれた。

HTMLはGatsbyCloudでキャッシュされているがCFではデフォルト設定でキャッシュされない(キャッシュヘッダを見て決めている)ため、CDNキャッシュ用に設定をいじるともう少しよくなりそう。