GitHub Actions + AWS CodeBuildでPRごとの検証環境を作ってみた
はじめに
必要に応じて検証環境の追加・削除などの管理をするのが面倒くさいので、PR作成時に検証環境を構築、PRマージ・クローズ時に検証環境を削除ができないか考えてみました。
今回の作成したGitHub Actions ワークフロー、Terraformなどはこちらのリポジトリにあります。
概要図
どのように実現したか
実現あたり、コンテナイメージのプッシュ、ECS サービスのデプロイはGitHub Actions、Terraformの実行はAWS CodeBuildで行うことにしました。
なぜTerraformの実行はCodeBuildを利用するようにしたかというと、CodeBuildはVPC内のリソース(今回の場合はAurora Serverless)にアクセスできるからです。
これによってアプリケーション、DBマイグレーション時に使用するMySQL ユーザーをTerraformで作成することができます。(検証環境とはいえrootユーザーを使用したくなかったため)
まずはVPC、ALBなどの共通で使用するリソースを作成してきます。
Route53でALBのaliasの値を検証環境で使用するドメインのワイドルカードを指定し、すべての名前解決がALBに向くようにします。
その後、PRのオープン時にGitHub ActionsとAWS CodeBuildを使用してECS、Aurora Serverless、SQSなどの個別リソースをPRごとに作成します。
ECS サービスのTarget Groupは共通リソースとして作成されたALBのListener Ruleに追加されます。
PRのマージ・クローズ時にはGitHub ActionsとAWS CodeBuildを使用してオープン時に作成した個別リソースを削除します。
ワークフロー
PR作成時
PR作成時のワークフローは下記のとおりです。
GitHub ActionsからのCodeBuild実行は以下のとおりです。
step Import source credentials
ではCodeBuildがリポジトリに接続するための認証情報を更新しています。
env:
ENV: pr${{ github.event.pull_request.number }}
TFSTATE_BUCKET: ${{ secrets.TFSTATE_BUCKET }}
IMAGE_TAG: ${{ github.sha }}
jobs:
CreateEnv:
runs-on: ubuntu-20.04
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Import source credentials
run: aws codebuild import-source-credentials --token ${{ secrets.PERSONAL_ACCESS_TOKEN }} --server-type GITHUB --auth-type PERSONAL_ACCESS_TOKEN
- name: Run CodeBuild
uses: aws-actions/aws-codebuild-run-build@v1
with:
project-name: qa-apply
env-vars-for-codebuild: |
ENV,
TFSTATE_BUCKET
PR作成時に実行するCodeBuildの内容は下記のとおりです。
こちらでは、tfenvのインストールとworkspace作成、terraform apply
を行っています。
version: 0.2
phases:
install:
runtime-versions:
golang: 1.16
commands:
- git clone https://github.com/tfutils/tfenv.git ~/.tfenv
- ln -s ~/.tfenv/bin/* /usr/local/bin
- tfenv install 1.0.7
build:
commands:
- cd terraform/qa
- terraform init -backend-config="bucket=$TFSTATE_BUCKET"
- terraform workspace new $ENV
- terraform apply -var qa_common_tfstate_bucket=$TFSTATE_BUCKET -auto-approve
検証環境の個別リソース作成に成功すると下記のように検証環境のURLをコメントします。
URLをクリックすると、アプリケーションがデプロイされています。(今回はデプロイ完了まで待機していないので、反映までタイムラグがあります)
PRへの追加コミット時
追加コミット時のワークフローは下記のとおりです。
今回はDBマイグレーション時のタスク実行、ECS サービスのデプロイはaws-actionsを使わずに面白法人カヤック様が提供しているecspressoを使用しています。
ecspressoを使用した理由としては、タスク定義、サービス定義でtfstateの値をできるからです。
Terraformで構築しているときは本当にこれが便利です。
DbMigrate:
runs-on: ubuntu-20.04
timeout-minutes: 10
needs: [BuildWeb, BuildWorker, BuildMigrate]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Setup ecspresso
uses: kayac/ecspresso@v1
with:
version: v1.6.2
- name: Run DB Migration
working-directory: ./ecspresso/migrate
run: ecspresso run --config config.yaml
DeployApp:
runs-on: ubuntu-20.04
timeout-minutes: 10
needs: DbMigrate
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Setup ecspresso
uses: kayac/ecspresso@v1
with:
version: v1.6.2
- name: Deploy ECS service
working-directory: ./ecspresso/app
run: ecspresso deploy --config config.yaml --no-wait
PRマージ・クローズ時
PRマージ・クローズ時のワークフローは下記のとおりです。
PRマージ・クローズ時に実行するCodeBuildの内容は下記のとおりです。
こちらでは、tfenvのインストールとworkspace削除、terraform destroy
を行っています。
version: 0.2
phases:
install:
runtime-versions:
golang: 1.16
commands:
- git clone https://github.com/tfutils/tfenv.git ~/.tfenv
- ln -s ~/.tfenv/bin/* /usr/local/bin
- tfenv install 1.0.7
build:
commands:
- cd terraform/qa
- terraform init -backend-config="bucket=$TFSTATE_BUCKET"
- terraform workspace select $ENV
- terraform destroy -var qa_common_tfstate_bucket=$TFSTATE_BUCKET -auto-approve
- terraform workspace select default
- terraform workspace delete $ENV
検証環境の個別リソース削除に成功すると下記のようにコメントします。
さいごに
今回は構成から省きましたが、CodeDeployによるBlue/Greenデプロイへの変更、ECS サービスのオートスケーリング追加、コスト削減のため各AWSサービスエンドポイントの追加をしてもよさそうですね。
Discussion