Webサイト発注虎の巻ダウンロード
Webサイト発注虎の巻ダウンロード

CircleCIを利用して、AWS S3に静的サイトを自動デプロイする

づや

こんにちは、エンジニアのづやです。

今回はCIツールでは定番のSaas型のCI/CDサービスCircleCIを使ってみたいと思います。
※この記事を書いてる際のconfig.ymlのバージョンは2.1です。


 

料金

料金は下記の通りとなっておりまして、無料枠でもある程度使えますが、ビルド時間に制限があります。各プランの詳細を見たい方はこちら

料金 備考
Free 0$/月 ビルド時間: 最大 6,000 分/月
Performance 15$/月 毎月ビルド時間 6,000 分が付属。以降は使った分だけお支払い。5ユーザーシート付属。
Scale 2000$/月 ビルド時間枠もユーザー シート数も、ニーズに合わせてカスタマイズ可能。

CircleCIを使って行いたいこと

今回やりたいことは以下となります

  • Node.jsを利用したビルドを行う
  • S3にビルド後のファイルをアップロードする
  • developブランチへのpushで開発用の環境へデプロイ
  • releaseブランチへのpushで本番環境へデプロイ

Gitリポジトリと連携する

GitHubもしくはBitbucketなどのGITリポジトリと連携する必要があります。それぞれのアカウントにログインして、画面からポチポチしていくだけですぐに設定が完了します。

以下の公式ページから、繋いでみてください

対象にしたいリポジトリを選択できれば、とりあえずOKです。その後は対象のリポジトリに/.circleci/config.ymlを作成すると、そのymlファイルの内容に従い処理を行ってくれます。そこの内容が今回のメインとなります。

ローカルでのテスト

基本的にpushしたときに動くのですが、config.ymlを変更するたびにpushして動くのを待っていると待ち時間とかがとてもつらいです。ローカルでテストできる環境が整備されているので、それを設定します。

公式の手順がしっかりしているので、それをみながら設定しました。環境がMACのため、homebrew経由でインストールします。

brew install --ignore-dependencies circleci

dockerをいれてたので、上記コマンドを打ちます。

 

circleci setup

インストールできたらsetupコマンドを打つのですが、APIトークンが必要なので、Personal API Tokensページから発行しておいて、上記コマンドを実行します。途中でAPIトークンを聞かれるので作成したAPIトークンを入力してください。

そしたら.circleciが存在するディレクトリに移動して、ファイルのチェックや実行が行えます。

 

circleci config validate

ファイルの構文チェックは上記となります。よく構文ミスるので、構文ミスのたびにpushしてビルドして確認はしんどいので大変ありがたいです。

 

circleci config process .circleci/config.yml > process.yml
circleci local execute -c process.yml --job JOB名

ジョブの実行(2.1の場合)です。詳細は後述しますが、ymlに記載のJOBを単体で実行することができて、こいつが大変便利です

実際にconfig.ymlを作成してみた

実際に作成してみたものがこちらです。

version: 2.1

executors:
  awscli_container:
    docker:
      - image: infrastructureascode/aws-cli
        environment:
          AWS_DEFAULT_REGION: ap-northeast-1
    working_directory: /home/circleci/example

  nodejs_container:
    docker:
      - image: circleci/node:16.12
    working_directory: /home/circleci/example

jobs:
  build:
    executor: nodejs_container
    steps:
      - checkout
      - restore_cache:
          key: dependency-cache-{{ checksum "package-lock.json" }}
      - run:
          name: 'npm install'
          command: npm install
      - save_cache:
          key: dependency-cache-{{ checksum "package-lock.json" }}
          paths:
            - ./node_modules
      - run:
          name: 'production build'
          command: npm run prod
      - persist_to_workspace:
          root: /home/circleci/example
          paths:
            - ./*

  dev-deploy:
    executor: awscli_container
    environment:
      AWS_S3_BUCKET_NAME: "dev.example.liginc.co.jp"
    steps:
      - attach_workspace:
          at: /home/circleci/sample
      - run:
          name: "Deploy to S3 if branch is develop."
          command: |
            export AWS_ACCESS_KEY_ID=${DEV_AWS_ACCESS_KEY}
            export AWS_SECRET_ACCESS_KEY=${DEV_AWS_SECRET_ACCESS_KEY}
            aws s3 sync /home/circleci/example/public s3://${AWS_S3_BUCKET_NAME}/ --exact-timestamps --delete

  prod-deploy:
    executor: awscli_container
    environment:
      AWS_S3_BUCKET_NAME: "example.liginc.co.jp"
    steps:
      - attach_workspace:
          at: /home/circleci/example
      - run:
          name: "Deploy to S3 if branch is Release."
          command: |
            export AWS_ACCESS_KEY_ID=${PROD_AWS_ACCESS_KEY}
            export AWS_SECRET_ACCESS_KEY=${PROD_AWS_SECRET_ACCESS_KEY}
            aws s3 sync /home/circleci/example/public s3://${AWS_S3_BUCKET_NAME}/ --exact-timestamps --delete

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

      - prod-deploy:
          requires:
            - build
          filters:
            branches:
              only:
                - release

「executors」で実行環境の設定を、「jobs」で実際のビルドだったりの処理を、「workflows」で実際のjobを実行する順番を記載しています。

executors

後々のjobで使用するコンテナを定義しています。今回はnodejsを利用したビルドを行うコンテナnodejs_containerと、AWS CLIを利用してS3にファイルを送信するawscli_containerの2個のコンテナを指定しています。

- imageにてコンテナのdockerイメージを指定しています。nodejs_containerはCircle Ciが提供しているnodejsのイメージとなり自分で使っているバージョンを指定します。

awscli_containerはdocker hubのものを指定しました。

jobs

ここが実際行うビルドだったりのコマンドを定義する箇所になります。今回はnodejsでビルドを行い公開ファイルを生成する「build」と、開発環境にデプロイする「dev-deploy」、本番環境にデプロイする「prod-deploy」を定義しています。

buildに関しては、package-lock.jsonを利用して、キャッシュを行い、必要ないときはnpm installはしないようにしています。

npm install
npm run prod

commandが実際に実行するコマンドのため、キャッシュを考えなければ、上記が今回のビルドを行なっているコマンドとなります。後ほど、違うjobにて生成したファイルを利用するために、persist_to_workspaceを指定しています。

dev-deploy、prod-deployに関してはデプロイ先が違うだけでやっていることは一緒です。attach_workspaceを指定して、ビルドしたファイルにアクセスできるようにしています。

${DEV_AWS_ACCESS_KEY}などクレデンシャルな情報は、環境変数を利用しています。環境変数はCircleCiの管理画面のProject Setting → Environment Variablesから設定しています。

このjobに関しては、もっと効率よくかけるのではないかとちょっと思っています。jobを呼ぶときにパラメータとして渡せばよかった気がしています。

workflows

ここでは、jobを実行する順番と、動作するブランチの指定を行っています。作成したjobの名前が記載されており、dev-deploy、prod-deployはビルドの実行が終わるまで、実行されないようにrequiresにて指定しています。

またそれぞれfiltersを利用して、対象のブランチ以外では動作しないように指定されています。

むすび

Circle Ciはconfig.ymlがパッとみだと理解しづらいなぁと思っていたのですが、一つ一つ分解してみていくとけっこう頑張れます。

もっと使いこなして、人がやらなくていい仕事を減らしていきたいです。