Github Actionsを用いてReactアプリのCI/CD環境を構築
はじめに
CI/CDとは、アプリケーション開発に自動化を取り入れて、アプリを提供する頻度を高める手法です。
CIは継続的インテグレーション(Continuous Integration)を指し、自動化プロセスを意味します。CIが正常に機能すると、アプリへの新しいコード変更が定期的にビルド、テストされ、迅速かつ容易に共通リポジトリに統合されます。
CDは継続的デリバリー(Continuous Delivery)、または継続的デプロイメント(Continuous Deployment)を指します。開発者による変更をリポジトリから本番環境に自動的にリリースし、顧客が使用できるようにするというものです。運用チームが担当する手動プロセスが多く、アプリケーション提供が遅れるという問題に対処します。
GitHub ActionsはCI/CDツールの一つで、GitHub上で動作するサーバレス実行環境です。複数のActionを組み合わせ、実行する順番を定義することで独自のワークフローを構築できます。他に有名なツールとしてCircleCI、Jenkinsなどがあります。
今回はECS-FargateにデプロイされたReactアプリケーションを用いて、Github Actionsを用いてビルド・デプロイの自動化を行います。
業務にて行なった内容のメモとして執筆します。AWSを使うようになって日も浅いので、誤りや指摘、よりよいやり方などありましたらコメントにて教えていただけると嬉しいです。
前提
・AWS CLIがインストールされていること
手順
ECSを用いたデプロイ環境の準備
ECS-Fargateでデプロイされたリソースを使用します。
こちらの記事(Reactアプリをdocker composeとECS(Fargate)でデプロイする)で手順を公開しているので必要であれば参考にしてください。
Githubリポジトリ用環境変数の設定
CI/CD環境を構築するにあたってAWSのアカウントIDや鍵情報が必要となりますが、それらの情報をそのままリポジトリ上のファイル記載するのは好ましくありません。
今回はGithubのRepository secretsにそれらの情報を登録し、Github Actions用のファイルから参照できるようにします。
作成するのは下記6点です。
- AWS_ACCESS_KEY_ID: アクセスキーID
- AWS_SECRET_ACCESS_KEY: 秘密アクセスキー
- CONTAINER_NAME: コンテナ名
- ECR_REPOSITORY: ECRリポジトリ名
- ECS_CLUSTER: ECSクラスター名
- ECS_SERVICE: ECSサービス名
アクセスキーID、秘密アクセスキーは~/.aws/credentials
にて確認可能です。
CI/CD環境構築用ファイルの作成
↑のGithub ActionsのECSテンプレートのyamlファイルをもとに少し手を加えます。
下記内容にてdeploy.yaml
, task-definition.json
を作成します。
name: Deploy to Amazon ECS
on:
push:
branches: ["main"]
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_REGION: ap-northeast-1
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
CONTAINER_NAME: ${{ secrets.CONTAINER_NAME }}
ECR_REPOSITORY: ${{ secrets.ECR_REPOSITORY }}
ECS_CLUSTER: ${{ secrets.ECS_CLUSTER }}
ECS_SERVICE: ${{ secrets.ECS_SERVICE }}
IMAGE_TAG: ${{ github.sha }}
permissions:
contents: read
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ env.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: ${{ env.ECR_REPOSITORY }}
IMAGE_TAG: ${{ env.IMAGE_TAG }}
run: |
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
- name: Fill in the new image ID in the Amazon ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: task-definition.json
container-name: ${{ env.CONTAINER_NAME }}
image: ${{ steps.build-image.outputs.image }}
- name: Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: ${{ env.ECS_SERVICE }}
cluster: ${{ env.ECS_CLUSTER }}
wait-for-service-stability: true
{
"family": "react-ecs-sample",
"requiresCompatibilities": ["FARGATE"],
"executionRoleArn": "ecsTaskExecutionRole",
"networkMode": "awsvpc",
"cpu": "256",
"memory": "512",
"containerDefinitions": [
{
"name": "react-ecs-sample",
"portMappings": [
{
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp"
}
],
"essential": true
}
]
}
タスクの細部についてはjsonファイルに追記することで設定が可能です。
(参考:https://docs.aws.amazon.com/cli/latest/reference/ecs/register-task-definition.html)
本稿ではcreate-react-app
で作成したプロジェクトがあらかじめデプロイされており、最終的なディレクトリ構成は次のようになります。
.
├── .github
├── .gitignore
├── Dockerfile
├── README.md
├── docker-compose.yaml
├── node_modules
├── package-lock.json
├── package.json
├── public
├── src
├── task-definition.json
└── tsconfig.json
作成した2ファイルをmainブランチにプッシュします。
ECSタスク実行用ロールの作成
プッシュしたことによりGithub Actionsが起動しますが、下記のように失敗しました。
service XXXXXXXXXXXX failed to launch a task with (error ECS was unable to assume the role 'arn:aws:iam::YYYYYYYYYYYY:role/ecsTaskExecutionRole' that was provided for this task. Please verify that the role being passed has the proper trust relationship and permissions and that your IAM user has permissions to pass this role.).
理由はtask-definition.json
の4行目のecsTaskExecutionRole
という名前のリソース名がないからでした。
この値がAmazonECSTaskExecutionRolePolicy
が付与されたロールであれば問題なくECSへのデプロイができますが、Github上にプッシュされているtask-definition.json
にIDなどが含まれたリソース名を記述したくなかったので、
ecsTaskExecutionRole
という名前のロールリソースを新たに作成しました。
構成した環境の確認
create-react-app
で作成したApp.tsx
に<a>React ECS Sample</a>
を追記してプッシュし、再度Github Actionsを起動させてみます。
リソースにアクセスすると追記した内容が反映されていることを確認できました!
参考
使用したコード
Discussion