AWS SAMとCircleCIでのCI/CD環境構築(Node)

kosa3
12 min readDec 19, 2019

--

CircleCI Advent Calendar 20日目、AWS SAMとCircleCIでCI/CDを行う方法を記事にします。

今月12/2にAWSが公式にCircleCI orbsのSAMを正式にサポートするという発表があり、CircleCIユーザにとってはとても興味深い発表だと感じました。今回はSAMでAPIを開発する際にCI/CD環境をさっと構築する方法を記事にしてみました。

# 実現するワークフローとジョブ

上図が実現したワークフローで以下がその内容のjobです。

・単体テスト
・セキュリティテスト
・ビルドテスト
・デプロイ
・E2Eテスト
・ドキュメント生成

今回はCircleCIの設定周り中心に記事化していきたいのでSAMの実装コードは以下リポジトリを参照ください。
RuntimeはNodeを利用しています。

#はじめに

仕様は単純なRestfullなAPIでuser一覧を返却するGETのAPIを作成します。

#1. セットアップ

プロジェクトのテストをするためのセットアップをしていきます。
circleci/node:12.13.1 のイメージをexecutorとしてパッケージをインストールします。

dependencies_yarn_packages のcommandでパッケージのインストール、キャッシュ化、リストアをしています。

commands:
dependencies_yarn_packages:
steps:
- restore_cache:
name: Restore Yarn Package Cache
keys:
- yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}
- yarn-packages-v1-{{ .Branch }}-
- yarn-packages-v1-
- run:
name: Install Dependencies
command: yarn install
- save_cache:
name: Save Yarn Package Cache
key: yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}
paths:
- ~/.cache/yarn
setup:
executor:
name: default
steps:
- checkout:
path: ~/repo
- attach_workspace:
at: .
- dependencies_yarn_packages

#2. セキュリティチェック

プロジェクトの依存パッケージで脆弱性がないかチェックするために yarn audit で確認をします。

security:
executor:
name: default
steps:
- checkout:
path: ~/repo
- attach_workspace:
at: .
- run:
name: Check Audit
yarn audit

#3. 単体テスト

プロジェクトのコードの整合性が担保されていることを確認する単体テストのjobです。

javascript系ではjestやmochaなどのテストライブラリが有名ですが今回はSAMにデフォルトでインストールされているmochaを利用してテストを作ります。

passした簡単なテストケースを今回のプロジェクトでは用意しました。テストするワンライナーコマンドはpackage.jsonかMakefileなどで記述するとCircleCI側で簡単に記述できます。

nyc というライブラリを用いることでテストカバレッジも出力してくれます。カバレッジを見たい時にはCircleCIのArchifactかAWS S3などのストレージサービスでホスティングすると便利です。

今回はCircleCIのArchifactを利用してカバレッジのホスティングをしています。
よりテストケースや対象が増えた場合はcodecovなどのSaasと連携することでより細かく解析されたダッシュボードで可視化することができます。

CircleCIのjobとしては以下のような感じで、バケットなど他のAWSサービスをローカルテストで利用する際にLocalStackというツールを使ってテストをしています。CIでも同様にLocalStackのイメージをexecutorに設定してテストをします。

unit_test_container:
working_directory: ~/repo/users
docker:
- image: circleci/node:12.13.1
- image: localstack/localstack
unit-test:
executor:
name: unit_test_container
steps:
- checkout:
path: ~/repo
- attach_workspace:
at: .
- dependencies_yarn_packages
- run: yarn run test
- store_artifacts:
path: coverage

#4. ビルドテスト

SAMプロジェクトのビルドが正常にパスするか確認します。

orbsの circleci/aws-serverless@1.0.2 を利用してSAMコマンドをインストールしています。orbsの中身としてはHomebrewをインストールしてaws-cli, aws-sam-cliをインストールしています。

build:
working_directory: ~/repo
executor: aws-serverless/default
steps:
- checkout:
path: ~/repo
- attach_workspace:
at: .
- aws-serverless/install
- run: sam build

#5. デプロイ

ここまで実行ができたのでデプロイをしていきます。

orbsのdeployジョブを使うとデフォルトでSAMテンプレートのvalidateとbuild、deployまでを実行してくれます。(validateはオプションで制御可能)

そのためジョブの実行時間が少し長くなるため#4のbuildテストが不要な場合ジョブを外しても良いかもしれません。

ビルドとデプロイのジョブを分けたい場合は、#4で事前にビルドしたものを使うために persist_workspaceattach_workspace を用いてsamのorbsでcliをインストール or pipでのaws-cli, aws-sam-cliをインストールして事前に作成した samconfig.toml からデプロイをすることでより効率的にデプロイをすることができます。

orbsを使う場合は以下でデプロイができます。

jobs:
- aws-serverless/deploy:
name: deploy
stack-name: production-stack
s3-bucket: S3_BUCKET_NAME
template: ./template.yaml
requires:
- unit-test
- security

orbs を使わずにデプロイするには #4の aws-serverless/install からsamのデプロイコマンドを利用する、あるいは以下のようにpipでインストールしてデプロイするかです。

build_container:
working_directory: ~/repo
docker:
- image: circleci/python:3.7-stretch
deploy:
executor:
name: build_container
steps:
- checkout:
path: ~/repo
- attach_workspace:
at: .
- run:
name: Install awscli
command: |
sudo apt-get update
sudo apt-get install -y python-pip python-dev
sudo pip install awscli aws-sam-cli
- run:
name: SAM Deploy
command: |
sam deploy

また、今回は扱っていませんがデプロイする時にAssumeRoleを用いることでよりセキュアなデプロイが可能になるので実際に試す場合は以下を参照ください。

#6. E2Eテスト

デプロイが完了すればデプロイしたプロジェクトが正しく動作しているかのテストをしなければいけません。条件によって意図せぬ結果を返さないかを自動テストしてくれる仕組みをE2Eで実現しています。

javascriptでは TestCafePuppeteer などのブラウザテストライブラリがあります。

今回は Puppeteermocha chai を合わせてテストをしていきます。

以下e2eジョブのコマンド内にてyarnでテストを実行する前にいくつかのパッケージをインストールしています。これらがないと`fails on load with shared library libXtst.so.6` というエラーがCircleCIで出て止まってしまうためインストールしています。
エラー原因としてはコンテナ内でchromeが見つけられず自動テストに失敗してしまうため依存パッケージをインストールしています。

e2e:
executor:
name: default
steps:
- checkout:
path: ~/repo
- attach_workspace:
at: .
- dependencies_yarn_packages
- run:
name: Run Puppeteer E2E Test
command: |
sudo apt-get install libpangocairo-1.0-0 libx11-xcb1 libxcomposite1 libxcursor1 libxdamage1 libxi6 libxtst6 libnss3 libcups2 libxss1 libxrandr2 libgconf2-4 libasound2 libatk1.0-0 libgtk-3-0
yarn run e2e

#7. ドキュメント生成

最後にドキュメントの更新をします、OpenAPI(Swagger)をArchfact or ストレージサービスに残したいです。
今回はCircleCIのArchfactにstoreしています。

swagger_ui_container:
working_directory: ~/repo
docker:
- image: swaggerapi/swagger-ui:v3.19.3
swagger:
executor:
name: swagger_ui_container
steps:
- checkout:
path: ~/repo
- run:
name: install ca-certificates for circleci
command: |
set -x
apk add --no-cache ca-certificates
- run:
name: create swagger-ui
command: |
sed -i "s|https://petstore.swagger.io/v2/swagger.json|swagger.yml|g" /usr/share/nginx/html/index.html
cp /usr/share/nginx/html/* docs/dist
cp docs/swagger.yml docs/dist
- store_artifacts:
path: docs/dist

実際に以下のように出力されていることがわかりました。

# まとめ

以上でAWS SAMのAPIに利用するCircleCIのCI/CD環境ができました。

その他にも静的解析やslackなどの通知、承認フローなど必要な場合は付け足していけたらと思います。

最後にAdvent Calendarは初参加でしたが、今後もアウトプットを継続していきたいです。

--

--

No responses yet