CircleCI でAWS S3 + CloudFrontを利用したデプロイ (Nuxt.js編)

S3で静的サイトのホスティングは容易に可能ですが、無料SSLを利用できるCloudFrontにサイトをデプロイする方法を紹介します。今回は、Nuxt.jsで開発したサイトをCircleCIを利用して自動デプロイすることにします。

CloudFrontとはCDNサービスで世界中に配置されたEdge locationを利用してコンテンツの配信を行う仕組みです。
流れとしては以下のようになります。

  1. IAMユーザの作成
  2. S3バケットの作成
  3. CloundFront distributionの作成
  4. CircleCIセットアップ
  5. .circleci/config.ymlの編集
  6. デプロイ

IAMユーザの作成

AWSマネージメントコンソール でIAMユーザを作成します。
権限ポリシーは AmazonS3FullAccess CloudFrontFullAccess を割り当てます。面倒であればAdmin権限で。

S3バケットの作成

同じくAWSマネージメントコンソールでの作業です。任意の名前で作成するだけで特に設定は必要ありません。後ほどCloudFront distributionを作成した際に必要な設定が反映されます。

CloudFront distributionの作成

AWSマネージメントコンソールにて、distributionを作成します。
Webでの利用になりますので、Webで作成を開始します。

次に必要な設定をします。
今回は Nuxt.jsでビルドしたアプリをS3にアップし、index.htmlがルートファイルとなりますので、以下の設定です。

  • Origin Domain Name: 作成したS3バケットを選択
  • Origin ID: 自動入力
  • Restrict Bucket Access: Yes を選択
  • Origin Access Identity: Create a New Identity を選択
  • Comment: 自動入力
  • Grant Read Permissions on Bucket: Yes, Update Bucket Policy を選択
  • Default Root Object: index.html を入力

Origin Access Identity (OAI) を作成することでS3コンテンツへのアクセスをOAI経由のみに制限します。
Grant Read Permisisons on Bucket を有効にすることで、S3バケット側のPermission設定がこのOAIで自動的に更新されます。

下層ページの403エラー対応

/index.html であればこれまでの設定で問題ありませんが、それ以外のページを表示しようとすると403エラーとなってしまいます。これを避けるための設定を行います。

Distributionのエラーページ設定にて以下の画像の通り設定します。

CircleCIセットアップ

今回は githubでの master ブランチへのpushをトリガーにして、自動デプロイする設定とします。

環境変数の登録

Project Settingsにて環境変数を登録します。必要な環境変数は以下です。

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_REGION
  • CF_DISTRIBUTION_ID

CF_DISTRIBUTION_ID は config.yml で指定するものなので任意でOK

config.ymlの編集

.circleci/config.yml を以下のように編集します。

version: 2.1
orbs:
  aws-s3: circleci/aws-s3@1.0.15

jobs:
  build:
    docker:
      - image: circleci/node:12
    steps:
      - checkout
      - restore_cache:
          name: Restore Yarn Package Cache
          keys:
            - yarn-packages-{{ checksum "yarn.lock" }}
      - run:
          name: Setup Step
          command: yarn install
      - save_cache:
          name: Save Yarn Package Cache
          key: yarn-packages-{{ checksum "yarn.lock" }}
          paths:
            - ~/.cache/yarn
      - run:
          name: Build Step
          command: NODE_ENV=production yarn generate
      - persist_to_workspace:
          root: ~/project
          paths:
            - dist
  deploy:
    docker:
      - image: circleci/python:3.6-jessie
    steps:
      - attach_workspace:
          at: ~/project
      - aws-s3/sync:
          from: dist
          to: 's3://nuxt-sandbox'
          overwrite: true
      - run: aws cloudfront create-invalidation --distribution-id $CF_DISTRIBUTION_ID --paths '/*'

workflows:
  version: 2
  build-deploy:
    jobs:
      - build:
          filters:
            branches:
              only: master
      - deploy:
          requires:
            - build
          filters:
            branches:
              only: master

builddeploy というjobを用意して、それらをworkflowsで順番に実行するというものです。
それぞれのjobでdockerイメージを利用します。(buildではnode, deployではpython)

  • build: Nuxt.jsアプリケーションのビルド処理
  • deploy: AWS S3へのソースアップロードおよびCloudFrontキャッシュのクリア

job間で共通のworkspaceを参照する設定もあります。
deploy の中でのjob stepsでs3, CloudFrontへの処理が定義されています。

workflowsのそれぞれのjobでmasterブランチへの反映をトリガーとする設定をしています。
これで、masterへプッシュすると同時にCircleCI workflows が実行されます。

デプロイ

masterブランチへの反映と同時に処理が走り、CircleCIコンソールで処理結果が確認できます。

成功したら、CloudFrontで定義されているドメインにアクセスしてサイトを確認しましょう!

以上