AWS:CloudFrontのキャッシュをLaravelからクリア

0
69

現在開発中のシステムではLaravel(EC2)経由でアップロード・生成されたファイルをS3のバケットに配置し、これを静的ウェブサイトホスティング機能でWebアクセス可能にしていますが、インターネットからのアクセスはCloudFrontを通すようにしており、前述の公開ファイル群はCloudFrontでキャッシュされます。

これらのファイルは時々更新され、更新結果は速やかに公開したいのですが、この時キャッシュが邪魔になります。
そこで更新に合わせてキャッシュをクリアする処理を行いたいと思います。

AWS SDK for PHP(aws-sdk-php)インストール

まずは「AWS SDK for PHP」をインストールしておく必要があります。
実のところ、私の環境ではインストール済みだったのですが、直接インストールした記憶がないので、他のパッケージインストール時に依存パッケージとして合わせてインストールされたものと推測します。
もし直接インストールするのであればcomposerで以下のように実施できるようです。

composer require aws/aws-sdk-php

なおLaravelに関しては「aws/aws-sdk-php-laravel」というパッケージも用意されているようです。「aws/aws-sdk-php」との違いは今ひとつ不明。私の環境には「aws/aws-sdk-php」の方がインストールされていました。

キャッシュクリア処理実装

キャッシュクリアは以下のような処理になります。

$distribution_id = "CloudFront上の対象ディストリビューションのID";
$paths = [
    'キャッシュクリア対象のパス(page/hoge/*等)',
];      

$client = new CloudFrontClient([
    'region'  => 'リージョン(ap-northeast-1等)',
    'version' => '2020-05-31',
]);     

$client->createInvalidation([
    'DistributionId' => $distribution_id,
    'InvalidationBatch' => [
        'Paths' => [ 
            'Quantity' => count($paths),
            'Items' => $paths, 
        ],      
        'CallerReference' => time(), 
    ],      
]); 

クラス「CloudFrontClient」は先にインストールした「aws-sdk-php」で提供されるクラスです。

インスタンス生成時には「region」と「version」を指定しています。
ただ、「region」に指定すべきリージョンが何を意味するものかが今ひとつ不明です。操作対象であるCloudFrontはリージョンに属していません。とりあえず、呼び出す側のEC2が属するリージョン(ap-northeast-1)を指定しています。
また、CloudFrontClientではAPIとしていくつかのバージョンが提供されている模様で、使用するバージョンを「version」として指定します。上記で指定している「2020-05-31」は現時点で最新のAPIバージョンです。
ネット情報では他にもいくつかのパラメータを指定している例が見受けられましたが、とりあえず上記で問題なさそうです。
ひょっとすると「region」や「version」も省略可能かもしれませんが、現時点では未確認です。

メソッド「createInvalidation」でキャッシュのクリアができるようです。
DistributionId」にはCloudFront上の対象ディストリビューションのIDを指定します。
「Paths」には文字通り無効化するページに相当するパスを指定しますが、ワイルドカード指定で特定の階層配下の全てのパスをクリア対象に指定できます。「Paths」の中身は「Quantity」と「Items」で、後者では対象パスを配列形式で複数指定でき、その数を前者で指定します。
CallerReference」では呼び出しごとに一意の値を指定する必要があるようです。上記では単純にタイムスタンプを使用していますが、複数プロセスでの同時実行等も考慮する必要がある場合はより厳密に一意性を保証する必要があるかと思います。

ロールへのポリシー追加

EC2からCloudFrontの操作を行うためには、EC2にその権限が必要になります。
ある程度環境構築が進んだEC2であれば既にIAMロールが割り当てられていると思うので、そこに同権限に関するポリシー「CloudFrontFullAccess」を追加するだけです。

実行

上記で準備ができたので、実際にキャッシュをクリアしてみます。
クリア処理を実行する前に対象ページ(ファイル)にアクセスし、更新前の情報が見えている(キャッシュの情報が有効になっている)ことを確認した上で改めてクリア処理を実行し、今度は更新結果が参照できることを確認します。

また、同時にクリア対象以外のページ(ファイル)も更新し、クリア処理実施後にクリア対象のパス以外のページ(ファイル)は更新前の情報が見えていることを確認することで、特定のパスに関するキャッシュのみがクリアされていることも合わせて確認しておくと確実です。

総括

ブラウザのキャッシュなどもそうですが、キャッシュは不要な通信量を減らせるメリットがあるものの、元情報が更新されているにも関わらず古い情報を出力し続けるという問題を生じさせる場合もあります。

恩恵を受けつつも更新結果は即時反映されるよう、キャッシュをうまくコントロールして行きたいと思います。