Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[おまけ資料]複数ドメインに散らばってしまった画像…! 運用中のPHPアプリに後からCDNを導...

Suguru Ohki
March 23, 2025
3

[おまけ資料]複数ドメインに散らばってしまった画像…! 運用中のPHPアプリに後からCDNを導入する…!

「複数ドメインに散らばってしまった画像…! 運用中のPHPアプリに後からCDNを導入する…!」
https://speakerdeck.com/suguruooki/fu-shu-domeinnisan-rabatutesimatutahua-xiang-dot-dot-dot-yun-yong-zhong-nophpapurinihou-karacdnwodao-ru-suru-dot-dot-dot

こちらの補足や調査した際に書いたことをまとめた資料です。もし必要であればご活用ください。

Suguru Ohki

March 23, 2025
Tweet

More Decks by Suguru Ohki

Transcript

  1. 1. パフォーマンスへの影響 接続オーバーヘッド 例:3つのS3ドメインの場合 - domain1.s3.amazonaws.com → DNS解決 + TCP接続

    + TLS - domain2.s3.amazonaws.com → DNS解決 + TCP接続 + TLS - domain3.s3.amazonaws.com → DNS解決 + TCP接続 + TLS 結果:接続確立に3倍の時間が必要 2025-03-23 スー | TechTrain 7
  2. アップロードルート %%{init: {'theme': 'base', 'themeVariables': { 'background': 'transparent', 'primaryColor': 'transparent',

    'primaryBorderColor': '#ffffff', 'primaryTextColor': '#ffffff', 'lineColor': '#ffffff', 'arrowheadColor': '#ffffff', 'edgeLabelBackground': '#3D3D5C' }}}%% flowchart TB subgraph "アップロード元" User["TechTrainのユーザーの フロントエンド"] Mentor["TechTrainのメンターの フロントエンド"] CS["自社のCSの管理画面 (laravel-admin)"] end subgraph "バックエンド" 2025-03-23 スー | TechTrain 18
  3. デフォルトのキャッシュ動作: Cloudflareはデフォルトでオリジンサーバーの Cache-Control ヘッダーなどの指示を尊重し、 Cache-Control: private ・ no- store ・

    no-cache ・ max-age=0 の場合はコンテンツをキャッシュしません (Default Cache Behavior · Cloudflare Cache (CDN) docs)。逆にオリジンが public かつ max-age に正の値を設定している場合や、将来日時の Expires ヘッ ダーがある場合はその指示に従いキャッシュします (Default Cache Behavior · Cloudflare Cache (CDN) docs)。ただしHTMLやJSONといった動的コンテンツは 拡張子に基づきデフォルトではキャッシュされず、主に画像・動画・CSS/JSな ど静的ファイル(特定の拡張子一覧)を標準でキャッシュします (Default Cache Behavior · Cloudflare Cache (CDN) docs)。例えばHTMLは明示的に設定しない限 りキャッシュされません。加えて、レスポンスに Set-Cookie ヘッダーが含まれ る場合もデフォルトではキャッシュ対象外となります (Default Cache Behavior · Cloudflare Cache (CDN) docs)。 2025-03-23 スー | TechTrain 23
  4. キャッシュ制御とカスタマイズ: CloudflareはCache Rules機能によって詳細なキ ャッシュ設定の調整が可能です (Cache Rules · Cloudflare Cache (CDN)

    docs)。 これにより、どのリソースをキャッシュ対象にするか、どのくらいの期間・どの 場所(エッジ)にキャッシュするか、またリクエスト条件に応じた動的な処理を 設定できます (Cache Rules · Cloudflare Cache (CDN) docs)。たとえばCache Rules(以前の「ページルール」を含む)を使ってHTMLなどもキャッシュする (“Cache Everything”)ルールを作成したり、特定パスのEdge Cache TTL(エッ ジ側のTTL)を強制設定したりできます。Edge Cache TTLはCloudflareネットワ ーク上でオブジェクトをキャッシュする最大期間を指定するもので、プランによ って最小値の制限があります(Freeプランは最小2時間、Proは1時間、 Business/Enterpriseでは1秒まで設定可能) (Edge and Browser Cache TTL · Cloudflare Cache (CDN) docs) (Edge and Browser Cache TTL · Cloudflare Cache (CDN) docs)。ブラウザへのCache-Controlは通常オリジンの指示を尊重します が、Cloudflare側でBrowser Cache TTL設定を上書きすることもできます (Edge and Browser Cache TTL · Cloudflare Cache (CDN) docs)(「既存ヘッダーを尊 2025-03-23 スー | TechTrain 24
  5. キャッシュパージ(削除・無効化): Cloudflareではインスタントパージによって グローバルなエッジキャッシュから対象コンテンツを即座に削除できます (Purge cache · Cloudflare Cache (CDN) docs)。標準では指定したURL(単一ファ

    イル)毎のパージが推奨されますが、他にも**「すべてパージ(Purge Everything)」**や、(Enterpriseプラン限定で)タグ(Cache-Tag)やホスト名 単位、URLプレフィックス単位でのパージが可能です (Purge cache · Cloudflare Cache (CDN) docs) (Purge cache · Cloudflare Cache (CDN) docs)。たとえばレス ポンスに付与したCache-Tagを基に関連する複数のコンテンツを一括でパージす ることができます(この機能はEnterprise専用) (Purge cache · Cloudflare Cache (CDN) docs)。パージはCloudflareダッシュボードやAPI経由で実行でき、即時に 全エッジから当該オブジェクトが消去されるため、新しいコンテンツをすぐ配信 できます。APIでは最大30個のタグ・ホスト・プレフィックスを1リクエストで パージ可能です (Purge Cached Content - Cloudflare API)。 2025-03-23 スー | TechTrain 25
  6. エッジネットワークとその他: Cloudflareは世界300都市以上にエッジサーバーを 展開する大規模ネットワークを持ち、すべてのプランで同じエッジロケーション からコンテンツ配信が可能です(Freeプランでも広範囲カバー)。またAPIサポ ートも充実しており、キャッシュ設定やページルール、Cache Rulesの作成、キ ャッシュ分析など多くの操作をREST APIやGraphQLで自動化できます。DDoS攻 撃対策については、Cloudflareは全プラン・全サービス共通でレイヤ3/4/7に対す る無制限・無償の常時オンDDoS保護を提供しています

    (About Cloudflare DDoS protection · Cloudflare DDoS Protection docs)。そのネットワーク容量は348 Tbps 以上に達し、これまで記録された最大級の攻撃も性能低下なく軽減した実績があ ります (DDoS Protection & Mitigation Solutions | Cloudflare)。加えてアプリケー ション層の保護にはWAF(Web Application Firewall)も提供されており、上位プ ランで高度なルールセットを利用できます。 2025-03-23 スー | TechTrain 26
  7. デフォルトのキャッシュ動作: Akamaiではユーザーがプロパティマネージャ (Property Manager)で配信ルールを設定する形になっており、デフォルト動 作はその設定次第です。一般的には「Caching」動作の中でオリジンのヘッダー を尊重するか否か、TTLを固定値にするか、といったポリシーを決めます。例え ば「Honor Origin Cache-Control」オプションを有効にすると、オリジンが返 す

    Cache-Control および Expires ヘッダーの指示をエッジサーバーがそのまま 尊重します (Learn about Akamai's caching)。この場合、オリジンが private や no-store を指定すればAkamaiもキャッシュせず、 max-age や s-maxage を指 定すればその値だけキャッシュします。一方、オリジンの指示を無視して独自の TTLを設定することも可能で、「オリジンヘッダーを無視して常に30分キャッシ ュ」のようなルールを指定できます。また「オリジン指示を尊重するが最大TTL は1時間まで」や「オリジンが何も指示しない場合はデフォルトで10分キャッシ ュ」等の細かな制御もルールエンジンで実現できます。TTL値について最小制限 はなく、要件に応じて**1秒や0秒(都度検証)**も設定可能です (What's the minimum age for a Cache-Control header with Akamai?)。HTTPステータスコード 2025-03-23 スー | TechTrain 28
  8. キャッシュキーとカスタマイズ: Akamaiはデフォルトでホスト名+パス+クエリ 全文をキャッシュキーとしていますが、プロパティのルール設定により細かなキ ーの構成変更が可能です。Akamaiの**「Cache ID Modification」というビヘイビ ア(動作)を用いることで、どのクエリパラメータ・ヘッダー・Cookieをキャ ッシュキーに含めるか(あるいは無視するか)を指定できます (Cache ID

    Modification - Akamai TechDocs)。例えば「特定のトラッキングパラメータは 無視」「モバイルとPCでUser-Agentに基づき別キャッシュにする」「特定の Cookie値ごとに別々にキャッシュする」といった柔軟な設定が可能です (Cache ID Modification - Akamai TechDocs)。デフォルトではすべてのクエリ文字列が キーに含まれますが、不要なパラメータは除外してキャッシュ効率を高めること が推奨されます。またAkamaiは変換後のキャッシュキー(Cache ID)を取得す る機能**も備えており、デバッグ目的で Pragma: akamai-x-get-cache-key ヘッ ダーを付けてリクエストするとAkamaiが使用している実際のキーやTTL情報を確 認できます (Akamai Cache rest url based on the query string pattern)。オリジン ごとに別キャッシュにするか(ホスト名のキー包含)、デバイスや地域で分ける 2025-03-23 スー | TechTrain 29
  9. キャッシュパージ: Akamaiは強力なパージ機能を提供しており、管理画面もしく はAPI経由でエッジキャッシュ上のコンテンツを短時間で無効化できます。 AkamaiのFast Purge API (CCU v3)では、URL単位(またはAkamai独自の ARL=Resource Locator)、CPコード単位(コンテンツプロバイダ毎のグルー

    ピング)、あるいはキャッシュタグ単位でパージリクエストを送信できます (Fast Purge API - Akamai TechDocs)。パージ方法として**「Invalidate(無効 化)」と「Delete(削除)」の2種類があり、Invalidateはエッジ上にオブジェク トを残しつつ以後のリクエストではオリジンから再検証させる「ソフトパージ」 に相当し、Deleteはエッジから即座にオブジェクトを消し去る動作です (Invalidate and delete methods - Akamai TechDocs)。一般的にはInvalidate (ソフトパージ)が推奨されており、これにより次回アクセス時にオリジンから 新鮮なコンテンツを取得します。一方、コンテンツそのものを完全に削除したい 場合や機密データの誤配信時などはDeleteを使います。パージ要求は通常数秒〜 数十秒程度でグローバルに反映され、Akamaiによれば「数秒でエッジネットワ 2025-03-23 スー | TechTrain 30
  10. デフォルトのキャッシュ動作: Fastlyは内部にVarnishベースのキャッシュエンジ ンを使用しており、HTTPの標準仕様に沿ってオリジンからのレスポンスヘッダ ーを解釈します。オリジンから受け取ったレスポンスがキャッシュ可能かどう か、そしてどの程度の期間キャッシュすべきかを自動判定しますが、その際の優 先順位は Surrogate-Control → Cache-Control: s-maxage

    → Cache- Control: max-age → Expires の順序です (HTTP caching semantics | Fastly Documentation)(オリジンがFastly用に Surrogate-Control ヘッダーを返せばそ れを優先的に適用)。適切なキャッシュ指示がない場合、Fastlyはデフォルトで2 分のTTLを割り当てます (HTTP caching semantics | Fastly Documentation) (HTTP caching semantics | Fastly Documentation)。例えばHTTP 200 OKでキャッシュ関 連ヘッダーが無いコンテンツは2分間だけキャッシュし、その後はオリジンに再 確認します (HTTP caching semantics | Fastly Documentation)。キャッシュ不能 オブジェクトについてもHTTPステータスごとに既定があります(例えば500エ ラーはどんな指示があってもキャッシュされない等) (HTTP caching semantics | 2025-03-23 スー | TechTrain 32
  11. デフォルトのキャッシュ動作: CloudFrontではディストリビューションの「キャ ッシュビヘイビア」設定によってキャッシュ挙動が決まります。パスパターンご とにビヘイビアを定義し、その中で「オリジンの指示を使う」か「カスタムTTL を使用する」かを選択します。デフォルトではCloudFrontはオリジンのCache- Control/Expiresヘッダーを尊重するモードになっています。例えばオリジンが Cache-Control: no-cache や no-store

    を返した場合、CloudFrontはそのオブジ ェクトをキャッシュしません。一方でオリジンが何のキャッシュ指示も返さない 場合でも、CloudFrontはデフォルトTTL=24時間を適用してコンテンツをキャッ シュします (Manage how long content stays in the cache (expiration) - Amazon CloudFront)(※この挙動は以前のデフォルト設定で、現在はCache Policy未使用 時に適用されます)。したがって明示的な制御をしないと、動的HTMLであって もCloudFront側で丸一日キャッシュされてしまう可能性があります。必要に応じ てビヘイビア設定でMinimum/Default/Maximum TTLをカスタマイズすること で、オリジンヘッダーがない場合のTTLや上限値を変更できます (Manage how long content stays in the cache (expiration) - Amazon CloudFront)。たとえば「最 2025-03-23 スー | TechTrain 34
  12. キャッシュキーとキャッシュポリシー: AWS CloudFrontでは2020年末に**「キャ ッシュポリシー (Cache Policy)」という仕組みが導入され、キャッシュキーの内 容を細かく制御できるようになりました (Control the cache

    key with a policy - Amazon CloudFront)。キャッシュポリシーでは、どのHTTPヘッダー・ Cookie・クエリストリングをキャッシュキーに含めるかを指定できます (Control the cache key with a policy - Amazon CloudFront)。例えば「言語ヘ ッダー( Accept-Language )をキーに含めて言語別に別キャッシュにする」「特定 のCookie(ログインセッションなど)はキーに含めない(全ユーザ共通キャッ シュにする)」といった設定がGUI上で容易に行えます。デフォルトではクエリ ストリングはすべてキーに含めず無視**(つまり同一パスならクエリが異なって も同一オブジェクトとしてキャッシュ)またはすべて含めるかを選択できます が、カスタムキャッシュポリシーでは必要なクエリパラメータだけホワイトリ スト指定してキーに含めることができます。Cookieやヘッダーも同様で、「重要 なCookieだけキーに含め他は無視」「デバイス判定用にUser-Agentヘッダー(の 一部)をキーに含める」等が可能です。なお、キャッシュキーに含めないヘッダ 2025-03-23 スー | TechTrain 35
  13. キャッシュパージ(無効化): CloudFrontでは**「無効化 (Invalidation)」リクエス トを発行することで、特定パスのオブジェクトを全エッジからパージできます (Invalidate files to remove content -

    Amazon CloudFront)。無効化は基本的に パス文字列の完全一致かワイルドカード( * )指定で行い、たとえ ば /images/* と指定するとそのパス配下の全オブジェクトを対象にできます。 CloudFrontの無効化は即時ではなく、各エッジロケーションに指示が伝達され るまで通常数十秒〜数分程度**かかります (Check AWS Cloudfront invalidation complete time? - Stack Overflow)。一般には1~2分で完了するケースが多いです が、キャッシュ規模やサーバー負荷によっては数分以上要することもあります。 無効化要求はマネジメントコンソール上またはAWS API/CLIから発行でき、自動 デプロイ時に新コンテンツに合わせて古いパスをパージするといった運用が可能 です。料金面では月に1回あたり無効化パス1000個分までは無料で、それ以上は 追加コストとなる点も考慮が必要です。なおCloudFrontにはFastlyやCloudflareの ような「タグ付けによる一括パージ」機構はありません。したがって、動的サイ トで多数の関連オブジェクトを一度に無効化したい場合はワイルドカード指定や 2025-03-23 スー | TechTrain 36
  14. エッジネットワークとその他: AWS CloudFrontはAWSグローバルインフラ上に 展開されており、90都市以上・47か国にわたる400以上のエッジロケーションを 持つと報告されています (400 Amazon CloudFront Points of

    Presence | Networking & Content Delivery)。各エッジからのミス時にはリージョナルエッジ キャッシュ(中継キャッシュ)も活用する多層構造で、高いキャッシュヒット率 とオリジン負荷分散を実現しています。API対応はAWSの他サービス同様に充実 しており、CloudFormationやTerraformでの設定管理、SDK/CLIによるプログラム 的なディストリビューション設定変更・無効化要求の送信などが可能です。但 し、CloudFrontの設定変更は即時反映ではなく、一般にデプロイ適用まで数分〜 15分程度を要します(設定を変更すると「変更のプロパゲーション」に時間がか かるため)。DDoS対策については、CloudFront自体がAWS Shield標準版の保護 下にあり、ネットワーク層の攻撃は自動軽減されます。さらにオプションの AWS Shield Advancedを有効化することで大規模攻撃に対する拡張保証が得ら れ、WAFとの統合でアプリ層(L7)の攻撃も対処できます (400 Amazon CloudFront Points of Presence | Networking & Content Delivery)。CloudFrontは 2025-03-23 スー | TechTrain 37
  15. 項 目 Cloudflare Akamai Fastly デ フ ォ ・一部静的拡張子の みデフォルトでキャ

    ッシュ(HTMLは未 キャッシュ) (Default Cache Behavior · Cloudflare Cache (CDN) docs) ・オリジンのCache- Controlを基本尊重 (Free/Pro/Busは常 に有効) (Default ・デフォルト動 作はプロパティ 設定次第(デフ ォルトで何もキ ャッシュしない 構成も可能) ・典型的にはオ リジン指示を尊 重する設定を使 用(Expiresや 2025-03-23 スー | TechTrain 40
  16. CloudFront導入の具体的なステップ CloudFrontディストリビューションを作成 カスタムオリジンを設定 (複数ドメイン対応) 各S3バケットを個別のオリジンとして登録 必要に応じてオリジンパスを設定 ACM (AWS Certificate Manager)

    でHTTPS証明書を設定 Route 53 でDNS設定を変更 (CNAMEレコードをCloudFrontのドメインに向け る) コードの修正 (画像URLをCDNのドメインに変更) 2025-03-23 スー | TechTrain 43
  17. 3. 移行時の注意点とテスト方法 (詳細) 段階的テストの実施: 一部のトラフィックのみCDN経由にする (カナリアリリース) 特定のユーザーグループのみテストに参加させる キャッシュの一時的無効化: テスト中はキャッシュを無効化し、オリジンからのレスポンスを確認 CloudFrontのInvalidationを利用

    ロールバック戦略の策定: 問題発生時の切り戻し手順を事前に準備 DNSの切り替え時間を考慮 コードスニペット (例): 環境変数でCDNのURLを管理し、切り替えを容易にする 2025-03-23 スー | TechTrain 44
  18. 複数S3ドメインを単一CDNドメインに統合するメリット おそらくセッションでは紹介しきれないがこんなメリットもある。 1. 単一ドメイン管理: images.example.com で全てアクセス可能 2. 接続の最適化: HTTP/2, HTTP/3

    の恩恵を最大化 3. 一貫したキャッシュ管理: 統一されたポリシー設定 4. パフォーマンス向上: CDNエッジロケーションによる高速配信 5. 柔軟なオリジン構成: バックエンド変更もフロントエンドは不変 2025-03-23 スー | TechTrain 48
  19. 確認ポイント: レスポンスヘッダー内の以下の項目をチェックする。 ヘッダー名 内容 X-Cache Miss from cloudfront ならキャッシュされていない。 Hit

    from cloudfront ならキャッシュされている。 Cache- Control no-cache , no-store , private , max-age=0 などを指定していれ ば、原則キャッシュされない。 2025-03-23 スー | TechTrain 53
  20. 例 (curl): curl -I https://image.example.dev/path/to/image.png 出力例 (キャッシュされていない場合): HTTP/2 200 content-type:

    image/png cache-control: no-cache ... x-cache: Miss from cloudfront X-Cache が Miss ならば正しく動いている。 2025-03-23 スー | TechTrain 54
  21. ② AWS CloudFrontのモニタリング機能を利用する CloudFrontの標準ログ(CloudWatchまたはS3)にアクセスして、特定のパスがキャ ッシュヒットしているかどうかを確認できる。 AWSマネジメントコンソール > CloudFront > ディストリビューション

    > ログ設 定 CloudWatch LogsまたはS3へログを送る設定にする。 ログの中で x-edge-result-type をチェックする: Miss や RefreshHit ならオリジンアクセス Hit ならキャッシュを返却 2025-03-23 スー | TechTrain 55
  22. 方法A(推奨): S3ウェブサイトホスティングのリダイレクト機能を使う S3バケットの「Static website hosting」を設定。 Redirect requests 設定を使い、新しいドメインに転送する。 例: Old

    URL: https://old-bucket.s3.ap-northeast-1.amazonaws.com/foo.jpg ↓ New URL: https://image.example.dev/foo.jpg S3の中身を移動済みかによっても詳細は変わってくる 2025-03-23 スー | TechTrain 58
  23. 設定方法: AWSコンソールで対象のS3バケットを開く 「Properties」→「Static website hosting」を選択 「Redirect requests for an object」を選択して、以下を設定

    Host name: image.example.dev Protocol: https この設定で全ての既存リクエストがCloudFrontに強制リダイレクトされる。 2025-03-23 スー | TechTrain 59
  24. 例えば、次のようなLambda関数を設定する。 'use strict'; exports.handler = (event, context, callback) => {

    const request = event.Records[0].cf.request; const headers = request.headers; const hostHeader = headers.host[0].value; // 古いS3ドメインの場合リダイレクトする const oldBucketDomain = 'old-bucket.s3.ap-northeast-1.amazonaws.com'; const newDomain = 'image.example.dev'; if (hostHeader === oldBucketDomain) { const redirectResponse = { status: '301', statusDescription: 'Moved Permanently', headers: { location: [{ key: 'Location', value: `https://${newDomain}${request.uri}` }] } }; callback(null, redirectResponse); } else { callback(null, request); } }; 2025-03-23 スー | TechTrain 61
  25. 参考資料 AWS CloudFront ドキュメント Cloudflare のCDNについて 【入門】CDNとは?仕組みやメリットを図入りで分かりやすく Webサイトがブンブン 速くなるCDNの基礎知識 CDNのエッジで実行する系が面白い

    Amazon CloudFront のキャッシュ仕様についてあらためて調べてみた CloudFront がオブジェクトをキャッシュする期間を指定する Web配信のキャッシュ戦略についてまとめてみた キャッシュにおける歓喜と苦痛 CDN 導入時に気をつけるポイント 2025-03-23 スー | TechTrain 64