🏗️
GitHub ActionsでECSデプロイワークフロー
はじめに
現在、社内ではインフラの標準化が進んでおり、TerraformでAWS構築をしています。
そこで、CodeBuildを使った標準化が存在していますが、あえてActionsで作成を行いました。
できるだけ簡潔に。ほぼコピペで動くことをポリシーとして。
実装した内容
- Stg, Prd環境別デプロイ
- ECRへプッシュ
- task-definition.jsonの取得
- task-definition.jsonの書き換え
- task-definition.jsonの反映
デプロイするコンテナ
- Nginx
- Wordpress
今回はWordpressのアプリということで、上記二つのみですがコンテナ定義を変更するだけなので、モダンな環境にしても動くと思われます。
実装
tl;dr
今回は二つのコンテナを使用するため、再利用性を考慮してビルド処理を別ファイルに切り出しています。
.github/actions/container-build/action.yml
name: Container Build
inputs:
ecr-repository-uri:
required: true
description: ECRリポジトリのURI
dockerfile-path:
required: true
description: Dockerfileのパス
build-context:
required: true
description: Docker build の context パス
outputs:
container-image:
value: ${{ steps.meta.outputs.tags }}
description: ビルドしたコンテナイメージ
runs:
using: composite
steps:
- uses: aws-actions/amazon-ecr-login@v2
- uses: docker/metadata-action@v5
id: meta
with:
images: ${{ inputs.ecr-repository-uri }}
tags: |
type=raw,value=latest
- uses: docker/build-push-action@v5
with:
push: true
file: ${{ inputs.dockerfile-path }}
context: ${{ inputs.build-context }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
.github/workflows/deploy.yml
name: Deploy
on:
push:
branches:
- staging
- main
workflow_dispatch:
env:
ROLE_ARN: arn:aws:iam::${{ secrets.AWS_ID }}:role/${{ secrets.ROLE_NAME }}
SESSION_NAME: gh-oidc-${{ github.run_id }}-${{ github.run_attempt }}
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- name: Set environment variables for staging
if: github.ref == 'refs/heads/staging'
run: |
echo "TASK_DEFINITION_NAME=stg-app" >> $GITHUB_ENV
echo "TASK_DEFINITION_FAMILY=stg-app" >> $GITHUB_ENV
echo "CLUSTER_NAME=stg" >> $GITHUB_ENV
echo "SERVICE_NAME=app" >> $GITHUB_ENV
echo "NGINX_ECR_REPOSITORY_URI=${{ vars.NGINX_ECR_REPOSITORY_URI_STAGING }}" >> $GITHUB_ENV
echo "WORDPRESS_ECR_REPOSITORY_URI=${{ vars.WORDPRESS_ECR_REPOSITORY_URI_STAGING }}" >> $GITHUB_ENV
- name: Set environment variables for main
if: github.ref == 'refs/heads/main'
run: |
echo "TASK_DEFINITION_NAME=prd-app" >> $GITHUB_ENV
echo "TASK_DEFINITION_FAMILY=prd-app" >> $GITHUB_ENV
echo "CLUSTER_NAME=prd" >> $GITHUB_ENV
echo "SERVICE_NAME=app" >> $GITHUB_ENV
echo "NGINX_ECR_REPOSITORY_URI=${{ vars.NGINX_ECR_REPOSITORY_URI_MAIN }}" >> $GITHUB_ENV
echo "WORDPRESS_ECR_REPOSITORY_URI=${{ vars.WORDPRESS_ECR_REPOSITORY_URI_MAIN }}" >> $GITHUB_ENV
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ env.ROLE_ARN }}
role-session-name: ${{ env.SESSION_NAME }}
aws-region: ap-northeast-1
- uses: ./.github/actions/container-build/
id: build-nginx
with:
ecr-repository-uri: ${{ env.NGINX_ECR_REPOSITORY_URI }}
build-context: .
dockerfile-path: docker/nginx/Dockerfile
- uses: ./.github/actions/container-build
id: build-wordpress
with:
ecr-repository-uri: ${{ env.WORDPRESS_ECR_REPOSITORY_URI }}
build-context: .
dockerfile-path: docker/wordpress/Dockerfile
- name: Get current ECS task definition
id: get-task-definition
run: |
aws ecs describe-task-definition \
--task-definition ${{ env.TASK_DEFINITION_NAME }} \
--query taskDefinition \
--output json > task-definition.json
- name: Render new ECS task definition (Nginx)
id: render-nginx
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: ${{ steps.get-task-definition.outputs.task-definition }}
container-name: nginx
task-definition-family: ${{ env.TASK_DEFINITION_FAMILY }}
image: ${{ steps.build-nginx.outputs.container-image }}
- name: Render new ECS task definition (WordPress)
id: render-wordpress
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: ${{ steps.render-nginx.outputs.task-definition }}
container-name: wordpress
image: ${{ steps.build-wordpress.outputs.container-image }}
- name: Deploy ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
cluster: ${{ env.CLUSTER_NAME }}
service: ${{ env.SERVICE_NAME }}
task-definition: ${{ steps.render-wordpress.outputs.task-definition }}
wait-for-service-stability: false
解説
AWS認証
まずAWS認証の権限についてはOIDCを使用しています。下記記事を参考にしました。${{ secrets.AWS_ID}}
, ${{secrets.ROLE_NAME}}
についてはここで作成したIAM情報をGitHubのシークレットに保存してください。
大まかな処理の流れ
- GitHub Actionsが発火したブランチ別に環境変数を取得
- AWS認証
- Dockerfileをビルドし、ECRにプッシュ
-
task-definition.json
の取得 -
task-definition.json
の書き換え -
task-definition.json
の反映
AWSへの操作については下記Actionを使用しています。
注意点
wait-for-service-stability: false
としていますが、trueとした場合、ECSが安定状態になるまで待機をします。GitHub Actionsは実行時間の従量課金のため、デプロイを実行した時点で処理を終了させています。
ちなみに、現在の実行時間は1デプロイあたり2m弱くらいです。
Discussion