Amazon S3+CloudFront環境へGitHub Actionsをつかってデプロイする

静的サイトの配信のために、Amazon S3にファイルを設置してCloudFrontで配信する方法はよく行われていると思いますが、私の管理するアプリケーションでもこのような構成のものがあります。

というわけで、もっとかんたんにデプロイできるようにしたいな~ということで、GitHub Actionsでデプロイできるようにしたので、備忘録としてまとめました。

成果物のWorkflow

こんなかんじのWorkflowを定義します。私のアプリケーションの場合は事前にnode環境のセットアップ(actions/setup-node@v1)をしたり、ビルド( npm run build )してからS3にファイルを設置していますが、このへんはそれぞれのケースに応じて調整します。 Workflowのトリガは、今回は workflow_dispatch として任意のタイミングで実行することとしましたが、このへんもそれぞれのケースに応じて調整するとよさそうです。

name: Deploy to s3
on: workflow_dispatch

jobs:
  upload:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      # 成果物を生成する
      - uses: actions/setup-node@v1
        with:
          node-version: '16.x'
      - name: Cache dependencies
        uses: actions/cache@v2
        with:
          path: |
            **/node_modules
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
      - run: npm install
      - run: npm run build

      # S3にアップロードしてInvalidationリクエストを投げる
      - uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: (region)
      - run: aws s3 sync ./build s3://example-bucket
      - run: aws cloudfront create-invalidation --distribution-id (distribution-id) --paths "/*"

やっていることは概ねこんな感じです。

  • aws-actions/configure-aws-credentials@v1 をつかって認証情報をセットアップする
    • これを使うとawsコマンドを認証が済んだ状態+Regionをセットした状態で使うことができます。
    • (region) を任意のRegionに設定します。
  • aws s3 sync コマンドでビルドした成果物(など)をS3 Bucketに送信する
    • example-bucket の部分は任意のBucket名に置き換えます。
    • S3への各種リクエストにはお金がかかります。頻繁にこのActionsを実行する場合はこのことも考慮される必要がありそうです。
  • aws cloudfront create-invalidation でファイルの無効化を行い、CDNのサーバのコンテンツを差し替える( --paths "/*" とすることですべてのファイルを無効化する)
    • (distribution-id) の部分は任意のDistribution IDに置き換えます。
    • Invalidationにはお金がかかります。 CloudFrontのドキュメント によると、1000件までの無効化パスまでは無料のようです。頻繁にこのActionsを実行する場合はこのことも考慮される必要がありそうです。

Workflowを動かすためのAWSアクセスキーの準備

各種awsコマンドが使えるように、アクセスキーを準備します。上記Actionsで用いるコマンド( aws s3 sync , aws cloudfront create-invalidation)には以下の権限が必要です。 (s3 sync に必要な権限は、 こちらの記事 を参照しました)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::(bucket-name)/*"
            ]
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::(bucket-name)"
            ]
        },
        {
            "Sid": "VisualEditor2",
            "Effect": "Allow",
            "Action": [
                "cloudfront:CreateInvalidation"
            ],
            "Resource": [
                "arn:aws:cloudfront::(aws-account-id):distribution/(distribution-id)"
            ]
        }
    ]
}
  • (bucket-name) はアップロード先のBucket名を設定します。
  • (aws-account-id) は、アカウントIDを設定します。
  • (distribution-id) は、CloudFrontのDistribution ID を設定します。

これらのアクセス権限を持つIAM Userを作成し、アクセスキーとシークレットアクセスキーを取得します。これらを AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY として、それぞれGitHubリポジトリのSecretsに保存します

これで、さきほど定義したWorkflowが動作するようになります。

そのほか参考にしたもの

aws.amazon.com


ビルドやアップロード周りを自動化することで、うっかりアップロードしちゃいけないファイルをアップロードするなどのミスが減るので、気軽にデプロイができるようになりますね。ではでは~