6
2

More than 3 years have passed since last update.

CircleCIをローカルで動かしながらNuxt.jsの静的サイトをAWS S3にデプロイする

Last updated at Posted at 2020-11-12

TL;DR

  • CircleCIでビルド, テスト, デプロイを順序立てて実行するにはWorkflowsを使う
  • Workflowsはローカル実行できないため、どうしてもローカルで確認したい場合は各ステップを build に切り出す
  • デプロイ先となるAWSのアクセスキーなどはCircleCIのEnvrionment Variablesに登録する
  • CircleCI CLIのローカル実行ではEnvrionment Variablesを -e オプションで設定できる

サンプルプロジェクト

今回はNuxt.jsで作ったフロントエンドプロジェクトをビルド/テスト/デプロイします。

create-nuxt-app は次の設定で作りました。

create-nuxt-app v3.4.0
✨  Generating Nuxt.js project in .
? Project name: map-sample
? Programming language: JavaScript
? Package manager: Yarn
? UI framework: Vuetify.js
? Nuxt.js modules: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Linting tools: ESLint, Prettier, StyleLint
? Testing framework: Jest
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Static (Static/JAMStack hosting)
? Development tools: jsconfig.json (Recommended for VS Code if you're not using typescript)
? Continuous integration: None
? Version control system: Git

CircleCIのプロジェクト立ち上げ方

CircleCIのProjectsにはアカウント作成に使ったGitHub/Bitbucketのリポジトリが並んでいます。

image.png

このリポジトリの Set Up Project から設定できますが、リポジトリにあるCircleCIの設定ファイルを使用するUse Existing Configを選ぶと CIが即実行されます。 CircleCI側に環境変数の設定が必要でも即実行されます。

image.png

そのため、プロジェクトを新しく立ち上げる場合は次の手順がおすすめだと考えています。

  1. GitHub/Bitbucketにリポジトリを作成する
  2. CircleCIのSet Up ProjectからAdd Configをクリックして最低限動作する設定をリポジトリに追加する
  3. リポジトリをローカルにcloneして開発を始める
  4. 設定ファイル .circleci/config.yml を編集してCircleCI CLIで設定ファイルのバリデーションとローカル実行する。
  5. CircleCIのプロジェクト設定から必要な設定をする
  6. GitHub/BitbucketのリポジトリにpushしてCircleCIのサービスで実行する

すでにCircleCIの設定ファイルがある場合は、Use Existing Configをクリックして実行されたジョブを停止させるか失敗するまで待ちます。

複数のジョブに順序を設定する場合はWorkflowsを用いる

次の一連の作業をCircleCIに実行させます。

  1. Nuxtなどのプロジェクトから静的サイトを生成する
  2. プロジェクトのテストを実行する
  3. 生成された静的サイトをS3にデプロイする

この場合、Workflowsという機能を使います。 この機能を使わないと build ジョブのみが実行されます。

設定ファイルの全体は次の通りです。

.circleci/config.yml
version: 2.1
orbs:
    aws-s3: circleci/aws-s3@1.0.11
jobs:
  build:
    docker:
      - image: circleci/node:lts
    working_directory: /tmp/work
    steps:
      - checkout
      - restore_cache:
          name: Yarn パッケージのキャッシュの復元
          keys:
            - yarn-packages-{{ checksum "src/yarn.lock" }}
      - run:
          name: 依存関係のインストール
          command: yarn install --frozen-lockfile
          working_directory: src
      - save_cache:
          name: Yarn パッケージのキャッシュの保存
          key: yarn-packages-{{ checksum "src/yarn.lock" }}
          paths:
            - ~/.cache/yarn
      - run: 
          name: 静的サイトのビルド
          command: yarn generate
          working_directory: src
      - persist_to_workspace:
          root: .
          paths:
            - src

  test:
    docker:
      - image: circleci/node:lts
    working_directory: /tmp/work
    steps:
      - attach_workspace:
          at: .
      - run: 
          name: テスト(Jest)
          command: yarn test
          working_directory: src
      - persist_to_workspace:
          root: .
          paths:
            - src

  deploy:
    docker:
      - image: circleci/python:3.7-stretch
    working_directory: /tmp/work
    steps:
      - attach_workspace:
          at: .
      - aws-s3/sync:
          from: src/dist
          to: 's3://$AWS_TARGET_BUCKET'
          arguments: |
            --acl public-read \
            --cache-control "max-age=86400"
          overwrite: true

workflows:
  build-deploy:
    jobs:
      - build
      - test:
          requires:
            - build
      - deploy:
          requires:
            - test

workflows にWorkflowsで実行したいジョブを記述します。 requires を指定することでジョブに順序を設定できます。

フロントエンドのビルドはcircleci/node

Node.jsを用いて開発しているため circleci/node のイメージを使います。 yarn install などYarnもこのイメージに入っています。

ステップ実行前の working_directory はその通り checkout などを実行する前に設定しようとするため、リポジトリ内のディレクトリは指定できません。

Monorepoなどの構成でステップに使うディレクトリを指定したい場合はステップ内で working_directory を設定します。

.circleci/config.yml
jobs:
  build:
    docker:
      - image: circleci/node:lts
    working_directory: /tmp/work
    steps:
      - checkout
      - run: 
          name: yarnパッケージの取得
          command: yarn install
          working_directory: src
      - run: 
          name: 静的サイトのビルド
          command: yarn generate
          working_directory: src
      - persist_to_workspace:
          root: .
          paths:
            - src

環境変数を使う場合

process.env など環境変数を使う場合はCircleCIのEnvironment Variablesで設定したものが使えます。

packages.json
  env: {
    mapsKey: process.env.MAPS_KEY,
  },

CircleCIのダッシュボードからプロジェクトを開き、Project SettingsのEnvironment Variablesをで設定できます。

image.png

CircleCI CLIでローカル実行する場合は -e オプションを任意の数だけ追加して環境変数を渡すことができます。

circleci local execute -e KEY1=VALUE1 -e KEY2=VALUE2

Yarnパッケージのキャッシュ

また、Yarnパッケージは変更がなければ次回のビルドでキャッシュを使うことができます。これによりビルドが高速化します。

https://circleci.com/docs/ja/2.0/yarn/ をほぼそのまま使うと次の通りになります。
checksum のコマンドだけステップで指定する working_directory の影響を受けないため個別に設定する必要があります。

.circleci/config.yml
jobs:
  build:
    docker:
      - image: circleci/node:lts
    working_directory: /tmp/work
    steps:
      - checkout
      - restore_cache:
          name: Yarn パッケージのキャッシュの復元
          keys:
            - yarn-packages-{{ checksum "src/yarn.lock" }}
      - run:
          name: 依存関係のインストール
          command: yarn install --frozen-lockfile
          working_directory: src
      - save_cache:
          name: Yarn パッケージのキャッシュの保存
          key: yarn-packages-{{ checksum "src/yarn.lock" }}
          paths:
            - ~/.cache/yarn
      - run: 
          name: 静的サイトのビルド
          command: yarn generate
          working_directory: src
      - persist_to_workspace:
          root: .
          paths:
            - src

AWS S3のデプロイはcircleci/python + aws-s3 Orb

一方で、AWS S3にデプロイする場合はAWS CLIが動作するPythonの環境が必要です。イメージは circleci/python:3.7-stretch を使っています。

CircleCIのEnvironment Variablesは次を設定します。

  • AWS_REGION
  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY

AWS CLIをインストールするステップとデプロイに必要なコマンドを実行するステップをそのまま入れても対応できます。

aws-s3 Orbを使うとAWS CLIをインストールするステップを記述する必要がなくなり、コマンド実行も簡単な形で書くことができます。
aws-s3 Orbを使った場合もAWS CLIのインストールから始まるため実行時間はほぼ変わりません。

Orbを使う場合は、 versions: 2.1 と宣言してから 使用するOrbを定義します。次にstepsでOrbを指定して引数を渡すとつかうようになります。

.circleci/config.yml
version: 2.1
orbs:
    aws-s3: circleci/aws-s3@1.0.11

...

  deploy:
    docker:
      - image: circleci/python:3.7-stretch
    working_directory: /tmp/work
    steps:

...

- aws-s3/sync:
          from: src/dist
          to: 's3://$AWS_TARGET_BUCKET'
          arguments: |
            --acl public-read \
            --cache-control "max-age=86400"
          overwrite: true

--acl public-read をつけないとバケットのWebホスティングを有効にしても403 Forbiddenになります。

ジョブで複数のimageを設定する方法は難しい

NodeでビルドしながらPython製のAWS CLIを使ったデプロイをしたい、を実現する方法としてジョブで使うイメージを複数指定する方法があります。

しかし、現在のバージョンで組み合わせられるイメージを見つけることができませんでした。

.circleci/config.yml
jobs:
  build:
    docker:
      - image: circleci/node:14.15.0
      - image: circleci/python:3.7

Error:
Unexpected environment preparation error: Error response from daemon: can't join IPC of container 53363ebc1e04ac6613b863d3fe80f6f28757182d7e725250c8981f55b8c4d3b2: non-shareable IPC (hint: use IpcMode:shareable for the donor container) > > > Step failed
Task failed

ジョブ間のデータはやり取りされない: persist_to_workspace を使う

ジョブを続けて書いてWorkflowsで連結しても 前のジョブで生成したデータにはアクセスできません。

次のジョブに移る前に persist_to_workspace と宣言してから、次のジョブで attach_workspace を使ってデータを取り出します。

persist_to_workspacerootはジョブの作業ディレクトリから相対/絶対パスで指定し、pathsはその中で次のジョブに残したいディレクトリを指定します。

attach_workspaceatは同様にジョブの作業ディレクトリから相対/絶対パスで指定します。

.circleci/config.yml
jobs:
  build:
    docker:
      - image: circleci/node:lts
    working_directory: /tmp/work
    steps:
      - run: 
          name: yarnパッケージの取得
          command: yarn install
          working_directory: src
      - run: 
          name: 静的サイトのビルド
          command: yarn generate
          working_directory: src
      - persist_to_workspace:
          root: .
          paths:
            - src

  test:
    docker:
      - image: circleci/node:lts
    working_directory: /tmp/work
    steps:
      - attach_workspace:
          at: .
      - run: 
          name: テスト(Jest)
          command: yarn test
          working_directory: src

CircleCI CLIのローカル実行ではWorkflowsはサポートされない

Workflowsを指定しても build ジョブだけが実行されます。Workflowを通して動作確認したい場合はローカルではなくCircleCIのサービスで実行する必要があります。

ジョブを選んで実行する方法が見つからなかったので、各ジョブを切り出して build ジョブとして実行するようにしています。
もちろん「静的サイトのビルドをしないと deploy ジョブで必要な dist にファイルが生成されない」など前のジョブに依存する場合は前提となる状態を再現しています。

ローカル実行は persist_to_workspace もサポートされない

persist_to_workspace を使ったジョブで circleci local exec を実行すると次のメッセージが表示されます。
こちらもCircleCIのサービス側で実行すると正しく処理されます。

Warning: skipping this step: Missing workflow workspace identifiers, this step must be run in the context of a workflow

参考

ワークフローを使用したジョブのスケジュール - CircleCI
https://circleci.com/docs/ja/2.0/workflows/

CircleCI2.0のWorkflowを試してみる - Qiita
https://qiita.com/sawadashota/items/ba89382d563bc90bb5cd

環境変数の使用 - CircleCI
https://circleci.com/docs/ja/2.0/env-vars/

CircleCI のローカル CLI の使用 - CircleCI
https://circleci.com/docs/ja/2.0/local-cli/#limitations-of-running-jobs-locally

デプロイの構成 - CircleCI
https://circleci.com/docs/ja/2.0/deployment-integrations/

Nuxt.js+CircleCIで静的ページをAWSのS3へデプロイする - Qiita
https://qiita.com/nishinoshake/items/21af46b4101392ffc666

CircleCI での Yarn (npm の代替) の使用 - CircleCI
https://circleci.com/docs/ja/2.0/yarn/

Configuring CircleCI - CircleCI
https://circleci.com/docs/2.0/configuration-reference/#persist_to_workspace

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2