プレスリリースやお知らせ、開発ブログ、会社の活動状況、Mattermost・aws・AI等の技術情報などを発信しています。

CodePipelineでCloudFrontのキャッシュを自動クリアする方法

こんにちは、moriです。
今回は、CodePipelineを使ってCloudFrontのキャッシュクリアを自動化する方法について、簡単なTIPSを紹介します。

最近、CICDのフローをCodePipelineを使ってフロントエンドシステムを構築しました。
構成としては、S3をオリジンに、CloudFrontをフロントに据えた典型的なサーバーレスアーキテクチャです。
さらに、S3のコンテンツはCodeDeployで自動的に更新されるように設定しています。

しかし、ここで1つ問題が発生しました。デプロイのたびにCloudFrontのキャッシュを手動でクリアする必要があるのです。せっかくデプロイを自動化したのに、これでは非効率的ですよね。

そこで今回は、CodePipelineのフロー内でCloudFrontのキャッシュを自動でクリアする方法を試してみたので、その手順を共有します。

Lambda関数の作成

まずはLambda関数を作成しましょう。関数名は「cloudfront_cacheclear」など、わかりやすい名前にすることをおすすめします。

以下がLambda関数のコードです:

import json
import boto3
import os
import time
import random

def unique_string(prefix='cli'):
    return '%s-%s-%s' % (prefix, int(time.time()), random.randint(1, 1000000))

def lambda_handler(event, context):
    # CodePipelineクライアントの作成
    codepipeline = boto3.client('codepipeline')

    try:
        # CloudFront Distribution IDの取得
        distribution_id = os.environ.get('DISTRIBUTION_ID')
        # CloudFrontクライアントの作成
        client = boto3.client('cloudfront')

        # 無効化リクエストを作成
        response = client.create_invalidation(
            DistributionId=distribution_id,
            InvalidationBatch={
                'Paths': {
                    'Quantity': 1,
                    'Items': ['/*']  # 全オブジェクトを無効化
                },
                'CallerReference': unique_string()  # リクエストの一意な識別子
            }
        )

        # レスポンスのログ出力
        print(response)

        # CodePipelineに成功を通知
        codepipeline.put_job_success_result(jobId=event['CodePipeline.job']['id'])

    except Exception as e:
        # エラー時にCodePipelineに失敗を通知
        print(f"Error: {e}")
        codepipeline.put_job_failure_result(
            jobId=event['CodePipeline.job']['id'],
            failureDetails={
                'type': 'JobFailed',
                'message': str(e)
            }
        )

Lambdaに必要なアクセス権の設定

次に、Lambda関数にCloudFrontとCodePipelineへのアクセス権を付与します。キャッシュの削除と、CodePipelineへの処理結果の通知を行うためのポリシーを設定します。IAMポリシーを作成し、Lambdaのロールに作成したポリシーをアタッチしてください。

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "cloudfront:CreateInvalidation",
"Resource": "arn:aws:cloudfront::123456789123:distribution/E1XXXXXXXXXXXX"
},
{
"Action": [
"codepipeline:PutJobSuccessResult",
"codepipeline:PutJobFailureResult"
],
"Effect": "Allow",
"Resource": "*"
}
]
}

環境変数の設定

さらに、Lambdaの環境変数に「DISTRIBUTION_ID」を追加し、CloudFrontのディストリビューションIDを設定します(例:E1XXXXXXXXXXXX)。

CodePipelineへの組み込み

次に、CodePipelineにこのLambdaを組み込みます。

CodePipelineを編集モードにし、S3へのデプロイの後に新しいステージを追加します。

「アクショングループを追加する」を設定していきます。
アクション名に任意の名前を入力し、アクションプロバイダーで「Lambda」を選択します。設定項目が展開されますのでの先ほど作成したLambdaを選びましょう。

設定を保存して、完了となります。

動かしてみて、エラーがなく完了することとキャッシュが削除されることを確認してください。

まとめ

今回のポイントは、CodePipelineに適切にレスポンスを返す部分でした。アクセス権やLambdaの設定を正確に行う必要があるので、ここは注意が必要ですね。

今回の例では、Lambdaを利用することで簡単にCloudFrontのキャッシュクリアを自動化できました。AWSの柔軟性のおかげで、少し足りない部分もLambdaで補完できるのが魅力ですね。

とはいえ、SPAなどの構成でCloudFrontとS3を組み合わせるケースはよくあります。今後は、AWSがさらにこのようなデプロイ後のキャッシュクリアを自動で行えるような機能を提供してくれることに期待しています。

  • B!

おすすめ記事リンク