本投稿は TECOTEC Advent Calendar 2020 の16日目の記事です。
こんにちは。決済認証システム開発事業部の杉本です。
本ブログには2度目の登場となります。 前回の記事では Google Apps Script について書きましたが、その際に今後の課題としていたもの……は未解決です。
本稿はそれより少し前、昨年のQiita Advent Calendarに参加した記事の、続きと言えなくもない、実際そんなに関係ない話です。
さて今日は2020年12月12日です。何の日だか、皆様ご存知でしょうか。
2020……2020……
1212……1212……
ご覧の通り循環(circulation)していますね。これは紛う方なきなでk……いやCircleCI記念日。
※ 循環数列の英訳は recurring sequence です。あと12月12日は「漢字の日」だそうです。
……という前フリを用意していたのですが、私の筆が遅く12日に間に合わず、16日の記事に変更となりました。
そこで12/16は何の日なのかと検索してみますと、実に111年前、 山手線が運行開始した日 だそうです。
山手線と言えば 環状線 ですが、当初は右側が繋がっていない「C」の字型運転だったようで。
ここまで要素が揃っていると、運命を感じてしまいます。逃れることのできない円環の理のよう。
というわけで、私がこの1年の間にやってみたCircleCIの使い方を、ここに記録したいと思います。
概要
- ひとつのリポジトリから、それぞれ異なるインスタンス、異なるディレクトリにデプロイしたい
- AWS Amplify を組み込んだWebアプリを、Amplifyコンソールを使わずにデプロイしたい
というような、ちょっと変わった要望に応えるための記法を紹介します。
本論
基本の流れ
まずはGitHubのソースをCircleCI経由でデプロイする際の基本的な流れを記載します。
- GitHubの対象リポジトリでPush
- WebhookでCircleCIが稼働
- CircleCIがDockerコンテナを立ち上げて、その中で対象ブランチをCheckoutする
- Dockerコンテナに引っ張ってきたソースを、なんやかやする
- いろいろいじくって整えたものを、CodeDeployに渡す/s3に配置する
- (CodeDeployに渡した場合)CodeDeployが対象ソースをインスタンスにデプロイする/(s3に配置した場合)CloudFrontのInvalidationを実行する
図にするとこんな感じ。

この設計図を、ymlファイルの記述に落とし込んでいきます。
/.circleci/config.yml ファイルは 1リポジトリでひとつ となりますので、develop・staging・productionの各環境用の処理をすべて記載することになります。
とは言え、環境毎に変わるのはAWSの認証情報、CodeDeployのアプリケーション・グループ名/s3のバケット名くらいで、行うべきことは同じであるというケースも多いかと思います。
そういった場合は、 references を定義し、各jobからは環境変数 environment を渡した上で参照を行うのが効果的です。references の中で ${ENVIRONMENT_NAME} と環境変数を参照することで、同じ処理を再利用することができます。
そして、 workflows のセクションで、「どのブランチに対するPushで、どのjobを動かすか」を定義します。しかし、ただGitHub + CircleCIを連携しただけですと、対象リポジトリのすべてのブランチへのPushでワークフローを回そうとしてしまいますので、フローの最初に実行される job で、稼働させるべきブランチをホワイトリストで設定しておきましょう。また、AWSの認証情報など機密性の高い値については、config.ymlに直接記載するのではなく、 context にて管理し、 workflows から各環境のjob毎に参照するようにします。
今回は develop・staging・productionの各環境に対応するブランチを用意したとします。さらに、 production へは管理者が認めた時のみデプロイが行われるよう、 approve も挟んでおきます。 type: approval のジョブは、CircleCIのコンソール上から承認を行うと成功するものになります。
……といったような考慮を加えた上で、ソースをCodeDeployに渡すシンプルな構成で、サンプルを記載いたします。
references:
commands:
push: &push
command: |
# AWS CLIを利用して、CodeDeployのデプロイ用ソースとして、s3にソースをpushする
echo upload source
aws deploy push \
--application-name ${AWS_CODEDEPLOY_APPLICATION_NAME} \
--s3-location s3://${AWS_CODEDEPLOY_SOURCE_BUCKET}/${CIRCLE_BRANCH}/${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME}/${CIRCLE_WORKFLOW_ID}.zip
deploy: &deploy
command: |
# AWS CLIを利用して、前の"push"でアップロードしたソースをCodeDeployで展開する
echo execute codedeploy
aws deploy create-deployment \
--application-name ${AWS_CODEDEPLOY_APPLICATION_NAME} \
--deployment-group-name ${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME} \
--s3-location bucket=${AWS_CODEDEPLOY_SOURCE_BUCKET},key=${CIRCLE_BRANCH}/${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME}/${CIRCLE_WORKFLOW_ID}.zip,bundleType=zip
version: 2.1
# この辺はおまじないのようなもの
# cf) https://aibou.hateblo.jp/entry/2020/04/30/145117
executors:
aws-cli:
environment:
AWS_PAGER: ""
docker:
- image: amazon/aws-cli
jobs:
build:
docker:
- image: circleci/php:7.4
working_directory: ~/circleci-build
steps:
- checkout
deploy_develop:
executor: aws-cli
working_directory: ~/circleci-deploy
environment:
AWS_CODEDEPLOY_APPLICATION_NAME: develop
AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME: app
AWS_CODEDEPLOY_SOURCE_BUCKET: codedeploy-circleci-source-develop
steps:
- checkout # /root/circleci-deploy にGitのソースを落とす
- run: echo deploy_develop
- run: *push # /root/circleci-deploy 以下のソースを.zip圧縮してs3にあげる
- run: *deploy # あげた.zipファイルをCodeDeployでインスタンスに展開する
deploy_staging:
executor: aws-cli
working_directory: ~/circleci-deploy
environment:
AWS_CODEDEPLOY_APPLICATION_NAME: staging
AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME: app
AWS_CODEDEPLOY_SOURCE_BUCKET: codedeploy-circleci-source-staging
steps:
- checkout
- run: echo deploy_staging
- run: *push
- run: *deploy
deploy_production:
executor: aws-cli
working_directory: ~/circleci-deploy
environment:
AWS_CODEDEPLOY_APPLICATION_NAME: production
AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME: app
AWS_CODEDEPLOY_SOURCE_BUCKET: codedeploy-circleci-source-production
steps:
- checkout
- run: echo deploy_production
- run: *push
- run: *deploy
workflows:
version: 2
build-and-deploy:
jobs:
- build:
filters:
branches:
only:
- develop
- staging
- production
- approve-deploy:
type: approval
requires:
- build
filters:
branches:
only: production
- deploy_develop:
requires:
- build
filters:
branches:
only: develop
context: AWS-DEVELOP
- deploy_staging:
requires:
- build
filters:
branches:
only: staging
context: AWS-STAGING
- deploy_production:
requires:
- build
- approve-deploy
filters:
branches:
only: production
context: AWS-PRODUCTION
アレンジ
では、この基本フローを頭に入れた上で、上記要件に適う記述を行っていきましょう。
①ひとつのブランチから、異なるインスタンス、異なるディレクトリにデプロイする
複数のAPIサーバを建てて、それぞれで異なるAPIが稼働するようにするけれど、基本構造やライブラリは共通だから、ソース管理はひとつのリポジトリにしたい……というケースが考えられます。またその際、サーバ毎にドキュメントルートを変えることもあるでしょう。
「どのインスタンスにデプロイするか」は、CodeDeployのデプロイグループの設定です。CodeDeployにて必要なアプリケーション・デプロイグループを用意した上で、CircleCIでは 「同じソースを複数のデプロイグループに渡す」 ように記述します。
問題は「異なるディレクトリにデプロイする」ほうです。CodeDeployでのデプロイ先は、指示書である appspec.yml に destination として定義します。しかし、この appspec.yml はルートにひとつしか置けず、CircleCIの指示書 config.yml と違って、その中で環境毎に記述を分けることもできません。そしてこのファイルはデプロイ操作の冒頭で参照されるため、デプロイするソースが出来た時点で、ルートに適切なものが置かれていなければなりません。
そのため、 appspec.yml については、 CircleCIでデプロイソースを用意する時に、環境に応じたファイルを「appspec.yml」としてルートに配置する 必要があります。
※ Jenkinsでは、「環境毎に異なるappspec.ymlファイルを利用する」というオプションがあり、同様のことを設定ひとつでやってくれるようになっています。
以上の条件で、ソース管理とconfig.ymlをアレンジしてみましょう。
ソース管理
develop・staging・productionの環境ごとにCodeDeployアプリを命名し、その中でデプロイ対象(APPLI1, APPLI2とする)ごとにグループを定義するようにします。
ルート
└ appspec
└ ${CodeDeployアプリ名}
└ ${CodeDeployグループ名}.yml
ルート └ appspec └ develop └ appli1.yml └ appli2.yml └ staging └ appli1.yml └ appli2.yml └ production └ appli1.yml └ appli2.yml
それぞれの中身は以下のように記述します。
AfterInstallでは、ソースのデプロイ後に行うこと(PHPであれば、 composer install だったり、cacheの削除だったり)を記述したshellを実行するようにしています。
version: 0.0
os: linux
files:
- source: /
destination: /var/www/appli1
permissions:
- object: /var/www/appli1
owner: teco
group: teco
hooks:
AfterInstall:
- location: sh/deploy/afterInstall.sh
runas: teco
version: 0.0
os: linux
files:
- source: /
destination: /var/www/appli2
permissions:
- object: /var/www/appli2
owner: teco
group: teco
hooks:
AfterInstall:
- location: sh/deploy/afterInstall.sh
runas: teco
config.ymlの調整
前項のように管理した.ymlファイルを、正しく「appspec.yml」として置くジョブ appspec を新たに用意します。
その上で、「appspec.ymlを置く→デプロイ用ソースをs3にpushする→CodeDeployを実行する」という一連の流れを、APPLI1・APPLI2のそれぞれについて実行するように、記述を拡張します。
references:
commands:
appspec_appli1: &appspec_appli1
command: |
# 環境に応じたディレクトリから.ymlファイルをコピーし、rootに「appspec.yml」として配置する
echo arrange appspec for ${AWS_CODEDEPLOY_APPLICATION_NAME}.${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME_APPLI1}
cp -f appspec/${AWS_CODEDEPLOY_APPLICATION_NAME}/${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME_APPLI1}.yml appspec.yml
push_appli1: &push_appli1
command: |
echo upload source
aws deploy push \
--application-name ${AWS_CODEDEPLOY_APPLICATION_NAME} \
--s3-location s3://${AWS_CODEDEPLOY_SOURCE_BUCKET}/${CIRCLE_BRANCH}/${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME_APPLI1}/${CIRCLE_WORKFLOW_ID}.zip
deploy_appli1: &deploy_appli1
command: |
echo execute codedeploy
aws deploy create-deployment \
--application-name ${AWS_CODEDEPLOY_APPLICATION_NAME} \
--deployment-group-name ${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME_APPLI1} \
--s3-location bucket=${AWS_CODEDEPLOY_SOURCE_BUCKET},key=${CIRCLE_BRANCH}/${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME_APPLI1}/${CIRCLE_WORKFLOW_ID}.zip,bundleType=zip
appspec_appli2: &appspec_appli2
command: |
echo arrange appspec for ${AWS_CODEDEPLOY_APPLICATION_NAME}.${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME_APPLI2}
cp -f appspec/${AWS_CODEDEPLOY_APPLICATION_NAME}/${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME_APPLI2}.yml appspec.yml
push_appli2: &push_appli2
command: |
echo upload source
aws deploy push \
--application-name ${AWS_CODEDEPLOY_APPLICATION_NAME} \
--s3-location s3://${AWS_CODEDEPLOY_SOURCE_BUCKET}/${CIRCLE_BRANCH}/${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME_APPLI2}/${CIRCLE_WORKFLOW_ID}.zip
deploy_appli2: &deploy_appli2
command: |
echo execute codedeploy
aws deploy create-deployment \
--application-name ${AWS_CODEDEPLOY_APPLICATION_NAME} \
--deployment-group-name ${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME_APPLI2} \
--s3-location bucket=${AWS_CODEDEPLOY_SOURCE_BUCKET},key=${CIRCLE_BRANCH}/${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME_APPLI2}/${CIRCLE_WORKFLOW_ID}.zip,bundleType=zip
version: 2.1
executors:
aws-cli:
environment:
AWS_PAGER: ""
docker:
- image: amazon/aws-cli
jobs:
build:
docker:
- image: circleci/php:7.4
working_directory: ~/circleci-build
steps:
- checkout
deploy_develop:
executor: aws-cli
working_directory: ~/circleci-deploy
environment:
AWS_CODEDEPLOY_APPLICATION_NAME: develop
AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME_APPLI1: app1
AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME_APPLI2: app2
AWS_CODEDEPLOY_SOURCE_BUCKET: codedeploy-circleci-source-develop
steps:
- checkout
- run: echo deploy_develop
# 「appspec.ymlを置く→デプロイ用ソースをs3にpushする→CodeDeployを実行する」を、対象それぞれに行う
- run: *appspec_appli1
- run: *push_appli1
- run: *deploy_appli1
- run: *appspec_appli2
- run: *push_appli2
- run: *deploy_appli2
# 後略
これを実行すると、appli1は、appli1グループの指定したインスタンスにデプロイされた後、その中の /var/www/appli1 に展開されます。一方appli2は、appli2グループのインスタンスの、 /var/www/appli2 に展開されることになります。
.envファイルも同じ発想で、環境ごとに以下のように用意しておくことができます。
ルート └ env └ develop └ appli1.env └ appli2.env └ staging └ appli1.env └ appli2.env └ production └ appli1.env └ appli2.env
こちらはCircleCIでデプロイソースを作成する際に配置してもよいですし、デプロイ後にAfterInstallにて実行するshellで配置することもできます。後者の場合には、実行されるshellはデプロイ先のディレクトリではなく、 /opt/codedeploy-agent/deployment-root/... という、デプロイ用の一時置き場にあるものだということに注意が必要です。感覚が混乱するので、shellの冒頭で、デプロイ先のディレクトリに移動しておくとよいかと。
いずれの場合でも、環境に応じたenvファイルを「.env」として配置した後は、cacheを消すことを忘れずに。
#!/bin/sh
echo "start"
echo ${APPLICATION_NAME}
echo ${DEPLOYMENT_GROUP_NAME}
cd /var/www/${DEPLOYMENT_GROUP_NAME}
echo "change permission"
sudo chmod -R 0777 storage
sudo chmod -R 0777 bootstrap/cache
echo "put envfile"
cp -au env/${APPLICATION_NAME}/${DEPLOYMENT_GROUP_NAME}.env .env
echo "cache clear"
php artisan cache:clear
php artisan config:cache
# 後略
幕間:SDKなどで、環境ごとに異なる証明書ファイルを配置したい(ただしAutoScalingのインスタンス間では共通とする)
.pemだったり.keyだったりのファイルは、あまりバージョン管理にあげたくないな、と思います。
外部ライブラリの証明書は、storage や vendor の下に置くように指示されることがありますが、そもそもそれらのディレクトリはGit管理していないことも多いはず。
しかし、同じサービスに対して複数台のサーバが稼働しているような、ELBにAutoScalingでぶら下がっているような構成の場合、そのインスタンス間では同じ証明書を持っていなければなりません。
このような場合には、AutoScalingのbaseとなるインスタンスにて、 /var/www 配下に対象のファイルを持っておき、CodeDeployのAfterInstallで(.envファイルと同じように)配置することができます。
# 前略
cp -au /var/www/certificate.pem storage/certificate.pem
# 後略
みたいな具合に。
他にもやり方はあると思いますが、一例としてご紹介しました。
②AWS Amplify を組み込んだWebアプリを、Amplifyコンソールを使わずにデプロイしたい
Amplifyを組み込んだWebアプリを、色々な事情があってGitで管理している場合は、CircleCIのDockerコンテナの上でamplify-cliを利用してbuildしていきます。
基本的には、ローカル環境でAmplifyを稼働させた時と同様に
- amplify-cliをはじめ、必要なパッケージをインストール
- AWS認証情報を設定
- Amplifyプロジェクトをpull
- Webアプリ用ソースをbuild
を行うことになります。
CircleCIのconfig.ymlを書く上で気にするのは、以下3点です。
- 環境ごとに異なる.envファイルを配置すること → これまでと違い、「CodeDeployの後に」はできませんので、CircleCIの中で配置します。
- amplify-cliは対話型のインターフェイスであること → それ用の書き方がありますので紹介します(実は公式ドキュメントに載っています)。
- buildしたものをdeployすること → EC2上で動かす場合は、①のようにCodeDeployに渡します。s3 + CloudFrontで動かす場合は、s3にあげた後でCloudFrontのキャッシュを消します。
あとは①でご紹介したように、環境変数を参照できるように references を利用して、指示を書いていけば完成です。
CircleCI上でAmplifyを引っ張ってきて、buildの後、s3 + CloudFrontの環境にデプロイする場合の config.yml は、以下のようになります。
references:
commands:
install_package: &install_package
command: |
# 必要なパッケージをインストール。aws-amplify/cliはバージョン上がるとエラー起こすことがあるので、確認環境で正常に動いたバージョンに固定するのが吉
echo Install yarn
npm install yarn
yarn install
echo Install aws-amplify CLI
sudo npm install -g @aws-amplify/cli@4.32.1
# Amplifyの操作を行うために参照する、AWS認証情報を設定
echo aws amplify configure
aws configure set amplify.aws_access_key_id ${AWS_AMPLIFY_ACCESS_KEY_ID}
aws configure set amplify.aws_secret_access_key ${AWS_AMPLIFY_SECRET_ACCESS_KEY}
aws configure set amplify.region ${AWS_DEFAULT_REGION}
aws configure set amplify.output json
echo Show AWS CLI and Amplify Versions
aws --version
amplify --version
# 環境に応じた.envファイルを、「.env」として配置
echo Put envfile
cp -f env/${AWS_DEPLOYMENT_GROUP_NAME}.env .env
amplify_setting: &lify_setting
command: |
# デプロイ先の環境に対応するAmplifyリソースをリモートからpullする
# 本来は対話型のインターフェイスで実行していくものだが、以下のように書くことで動かすことができる
echo Checkout Amplify Environment
amplify pull \
--amplify "{\
\"projectName\":\"${AWS_AMPLIFY_APP_NAME}\",\
\"appId\":\"${AWS_AMPLIFY_APP_ID}\",\
\"envName\":\"${AWS_AMPLIFY_APP_ENV}\",\
\"defaultEditor\":\"Visual Studio Code\"\
}" \
--frontend "{\
\"frontend\":\"javascript\",\
\"framework\":\"vue\",\
\"config\":"{\
\"SourceDir\":\"src\",\
\"DistributionDir\":\"dist\",\
\"BuildCommand\":\"npm run-script build\",\
\"StartCommand\":\"npm run-script serve\"\
}"\
}" \
--providers "{\
\"configLevel\":\"project\",\
\"useProfile\":true,\
\"profileName\":\"amplify\"\
}" \
--yes
amplify_deploy: &lify_deploy
command: |
# buildして、dist/以下に出来たソースを、CloudFrontのソースに設定したs3バケットに配置後、CloudFrontのキャッシュを削除する(Invalidationを実行する)
echo Build project
yarn build
echo Deploy to s3 and invalidate CloudFront cache
aws s3 sync ./dist s3://${AWS_CLOUDFRONT_SOURCE_BUCKET} --delete
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DISTRIBUTION_ID} --paths "/*"
version: 2.1
orbs:
aws-cli: circleci/aws-cli@1.2.1
executors:
node:
docker:
- image: circleci/node:12.4.0
jobs:
build_and_test:
executor: node
working_directory: ~/circleci-build
steps:
- checkout
- run:
name: 'Show node and NPM versions'
command: |
node -v
npm -v
- run:
name: 'install yarn'
command: |
npm install yarn
yarn -v
- restore_cache:
key: v1-dependencies-{{ .Branch }}-{{ checksum "package-lock.json" }}
- run: yarn install
- save_cache:
paths:
- node_modules
key: v1-dependencies-{{ .Branch }}-{{ checksum "package-lock.json" }}
- run:
name: 'Run tests'
command: |
echo test skip
deploy_develop:
executor: node
working_directory: ~/circleci-deploy
environment:
AWS_AMPLIFY_APP_NAME: sample
AWS_AMPLIFY_APP_ENV: develop
AWS_DEPLOYMENT_GROUP_NAME: develop
AWS_CLOUDFRONT_SOURCE_BUCKET: cloudfront-source-develop
AWS_CLOUDFRONT_DISTRIBUTION_ID: ******
steps:
- checkout
- restore_cache:
key: v1-dependencies-{{ .Branch }}-{{ checksum "package-lock.json" }}
- aws-cli/install
- run: *install_package
- run: *amplify_setting
- run: *amplify_deploy
deploy_staging:
executor: node
working_directory: ~/circleci-deploy
environment:
AWS_AMPLIFY_APP_NAME: sample
AWS_AMPLIFY_APP_ENV: staging
AWS_DEPLOYMENT_GROUP_NAME: staging
AWS_CLOUDFRONT_SOURCE_BUCKET: cloudfront-source-staging
AWS_CLOUDFRONT_DISTRIBUTION_ID: ******
steps:
- checkout
- restore_cache:
key: v1-dependencies-{{ .Branch }}-{{ checksum "package-lock.json" }}
- aws-cli/install
- run: *install_package
- run: *amplify_setting
- run: *amplify_deploy
deploy_production:
executor: node
working_directory: ~/circleci-deploy
environment:
AWS_AMPLIFY_APP_NAME: sample
AWS_AMPLIFY_APP_ENV: production
AWS_DEPLOYMENT_GROUP_NAME: production
AWS_CLOUDFRONT_SOURCE_BUCKET: cloudfront-source-production
AWS_CLOUDFRONT_DISTRIBUTION_ID: ******
steps:
- checkout
- restore_cache:
key: v1-dependencies-{{ .Branch }}-{{ checksum "package-lock.json" }}
- aws-cli/install
- run: *install_package
- run: *amplify_setting
- run: *amplify_deploy
workflows:
version: 2
build-and-deploy:
jobs:
- build_and_test:
filters:
branches:
only:
- develop
- staging
- production
- approve-deploy:
type: approval
requires:
- build_and_test
filters:
branches:
only: production
- deploy_develop:
requires:
- build_and_test
filters:
branches:
only: develop
context: AWS-DEVELOP
- deploy_staging:
requires:
- build_and_test
filters:
branches:
only: staging
context: AWS-STAGING
- deploy_production:
requires:
- build_and_test
- approve-deploy
filters:
branches:
only: production
context: AWS-PRODUCTION
EC2上で稼働させる場合は、buildまでの手順は変わりません(.envもCircleCIの処理の中で配置します)が、CodeDeployの appspec.yml が必要になりますので、①同様に環境ごとに用意し、CircleCI内でデプロイ先に応じたものを配置するようにします。
Amplifyを使わない、シンプルなWebアプリを、EC2上にデプロイするための記述は以下のようになります。
references:
commands:
install_package: &install_package
command: |
# 必要なパッケージのインストール、envファイルの配置
echo Install yarn
npm install yarn
yarn install
aws --version
echo Put envfile
cp -f env/${AWS_CODEDEPLOY_APPLICATION_NAME}.env .env
appspec: &appspec
command: |
# 環境に応じた appspec.yml ファイルの配置
echo arrange appspec for ${AWS_CODEDEPLOY_APPLICATION_NAME}.${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME}
cp -f appspec/${AWS_CODEDEPLOY_APPLICATION_NAME}.yml appspec.yml
build: &build
command: |
# buildしてデプロイ用ソースを作成
echo Build project
yarn build
push: &push
command: |
# CodeDeployのデプロイ用ソースとして、s3にソースをpush
echo upload source
aws deploy push \
--application-name ${AWS_CODEDEPLOY_APPLICATION_NAME} \
--s3-location s3://${AWS_CODEDEPLOY_SOURCE_BUCKET}/${CIRCLE_BRANCH}/${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME}/${CIRCLE_WORKFLOW_ID}.zip
deploy: &deploy
command: |
# pushしたソースをCodeDeployに渡してデプロイ
echo execute codedeploy
aws deploy create-deployment \
--application-name ${AWS_CODEDEPLOY_APPLICATION_NAME} \
--deployment-group-name ${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME} \
--s3-location bucket=${AWS_CODEDEPLOY_SOURCE_BUCKET},key=${CIRCLE_BRANCH}/${AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME}/${CIRCLE_WORKFLOW_ID}.zip,bundleType=zip
version: 2.1
orbs:
aws-cli: circleci/aws-cli@1.2.1
executors:
node:
docker:
- image: circleci/node:12.4.0
jobs:
build_and_test:
executor: node
working_directory: ~/circleci-build
steps:
- checkout
- run:
# 中略
deploy_develop:
executor: node
working_directory: ~/circleci-deploy
environment:
AWS_CODEDEPLOY_APPLICATION_NAME: develop
AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME: sample
AWS_CODEDEPLOY_SOURCE_BUCKET: codedeploy-circleci-source-spa-develop
steps:
- checkout
- restore_cache:
key: v1-dependencies-{{ .Branch }}-{{ checksum "package-lock.json" }}
- aws-cli/install
- run: echo deploy_develop
- run: *install_package
- run: *appspec
- run: *build
- run: *push
- run: *deploy
# 後略
また、実際に稼働させるソースは、buildしてできた /dist 以下のものですので、 appspec.yml 内の記述も①とは少し変える必要があります。
version: 0.0
os: linux
files:
- source: /dist
destination: /var/www/sample
permissions:
- object: /var/www/sample
owner: teco
group: teco
むすびに
CircleCIは自動テストも主要な役割でありますが、そこまで書くとヒュージな記事になってしまいますので、今回はビルド・デプロイに焦点を当ててご紹介いたしました。
開発対象の要件に合わせて、今後も色々な調整、組み換えを試して見たいと思います。
なお、表題のアルファベットを眺めてみると、頭文字でe,fが欠けていますが、偶然の産物です。
参考記事
CodeDeployのライフサイクルについて詳しい。 sqlazure.jp
Amplify入りデプロイに悩んでいた時に見つけた光明。 github.com
AmplifyのCLI操作は公式ドキュメントを参照すべし。 docs.amplify.aws
Amazon Web Services、『Powered by Amazon Web Services』ロゴ、[およびかかる資料で使用されるその他の AWS 商標] は、米国および/またはその他の諸国における、Amazon.com, Inc. またはその関連会社の商標です。