【CI/CD】GitHub ActionsからECSにアプリケーションをデプロイする
はじめに
以前、以下の記事で、CloudFormationを使って自作のアプリケーションをECS上で動かすハンズオンを実施しました。
ここができたら、今度はデプロイまで自動化しちゃおうということで、GitHubにpushしたらECSにアプリケーションを自動でデプロイするパイプラインを作成することとしました。
構成
AWSの環境に関しては前回で構築が完了しているので、GitHub周りの設定をしていきます。
GitHub Acitonsとは
GitHubが提供するタスク自動化サービスとなります。GitHubのイベントをトリガーにしてワークフローを起動することができます。例えばmasterブランチにpushされた、Pull Requestが作成されたなどのイベントを検知して、deployを実行するなどのことができるようになります。
ハンズオン
GitHub Actionsの設定
-
まずはGitHubにログインし、リポジトリに移動し、そこの
Actions
タブをクリックします。
-
テンプレートが複数表示されます。
-
今回はDjangoのサンプルアプリケーションのDockerイメージを使うので、
Django
を選択します。set up this workflow
をクリックします。
-
デフォルトでファイルが出来上がるので任意のファイル名(ここでは
django.yml
) を入力して、start commit
を押下します。
これでworkflowが完成!簡単!
ワークフローファイルの変更(django.yml)
ローカルにPullしてdjango.yml
を変更していきます。
ファイルを以下のようにします。
name: Django CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
max-parallel: 4
matrix:
python-version: [3.8, 3.9]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run Tests
run: |
python3 manage.py test
- 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: 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: ${{ secrets.AWS_ECR_REPO_NAME }}
IMAGE_TAG: ${{ github.sha }}
run: |
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
- 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: ./aws/task-definition.json
container-name: django-app
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: django-service
cluster: django-cluster
wait-for-service-stability: true
これをmasterブランチにpushすると、ローカルで編集したdjangoアプリケーションがそのままECRリポジトリにpushされて、さらに稼働中のアプリケーションに反映されます!
workflowファイルの詳細
上記で作成したファイルの詳細を見ていきましょう
以下はテンプレートですでに出来上がっている個所です。
name
はworkflowの名前なので任意で大丈夫です。on
はworkflowの起動トリガーを表していて、今回の場合は、masterブランチへのpushと、masterブランチへのpull requestをトリガーにしてworkflowを起動することになります。
name: Django CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
以下に関してもテンプレートですでに出来上がっている個所です。
jobs
が起動するジョブを記述するセクションです。
build
はjobsのIDを表していて実はbuild
でなくても良かったりします。
strategy
で、それぞれのジョブを実行する様々なバリエーションを定義できます。max-parallel
でジョブの並列最大実行数を定義できますし、matrix
でランタイムの選択をする子ができます。
runs-on: ubuntu-latest
は、GitHub上でホストされているubuntuで処理が実行されることを意味しています。
steps
はジョブ内で実際に処理する内容をグルーピングします。
基本的にname
でワークフロー名を記述し、そこに処理したい内容をrun
に記載していきます。use
は、コミュニティで定義されたアクションを利用する際に記述します。uses: actions/checkout@v2
はactions/checkout@v2
という名前のコミュニティアクションのv2 を取得するようにジョブに指示するという意味になります。
with
はアクションによって定義される入力パラメータのmap
です。キーと値を持ちます。
jobs:
build:
runs-on: ubuntu-latest
strategy:
max-parallel: 4
matrix:
python-version: [3.8, 3.9]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run Tests
run: |
python3 manage.py test
ここからは自分でアクションを記述していきます。
まずは、AWSのクレデンシャル情報を登録します。すでにコミュニティで準備している、aws-actions/configure-aws-credentials@v1
を利用します。入力として、クレデンシャル情報を渡してあげる必要があります。
secrets
で定義されている値AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
を渡しています。secrets
は、GitHubのレポジトリの画面で、[Setting] > [Secrets]から登録することができます。ちなみに、一度登録すると参照ができなくなるので値を忘れてしまった場合はUpdateする必要があります。
- 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
次に、ECRへのログイン処理と、ECRレポジトリへのコンテナイメージのPushを行います。
ECRへのログイン処理には、コミュニティアクションaws-actions/amazon-ecr-login@v1
を利用します。また、ログイン処理の実行結果を利用するために、このアクションにはid
でIDlogin-ecr
を付与します。
そして、次のアクションで実際にコンテナイメージのbuildとpushを行います。ここでは、env
を使って環境変数の設定を行います。
その中で、login-ecr
の処理の結果取得されたRegistory情報を環境変数にセットしています。
IMAGE_TAG
には、${{ github.sha }}
をセットしていますが、これは実行時にそのワークフローの実行のトリガとなったコミットのハッシュ文字列に置き換えられます。
- 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: ${{ secrets.AWS_ECR_REPO_NAME }}
IMAGE_TAG: ${{ github.sha }}
run: |
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
ここまででECRにコンテナイメージを行っているので、ここからは実際にECSタスクの更新処理を記述します。
まずはタスク定義の更新処理です。それにはコミュニティアクションのaws-actions/amazon-ecs-render-task-definition@v1
を利用します。入力には、task-definition
, container-image
, image
を指定する必要があります。image
は上記でpushしたコンテナイメージを利用するため、build-image
の処理結果を取得して値をセットします。
task-definition
は実際にGitHubレポジトリにタスク定義ファイルを配置します。タスク定義ファイルはAWSのECSの画面から取得して加工したものを利用します。
最後に更新されたタスク定義をもとに、ECSにデプロイ処理を実行します。
こちらもコミュニティアクションaws-actions/amazon-ecs-deploy-task-definition@v1
を利用します。入力には、task-definition
, service
, cluster
, wait-for-service-stability
を指定します。task-definition
にはtask-def
で更新されたタスク定義を利用します。service
, cluster
には該当のECSサービス、ECSクラスター名を指定します。
wait-for-service-stability
をtrue
にすることで、ECSサービスの安定稼働まで実行完了を待つことができるようになります。
- 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: ./aws/task-definition.json
container-name: django-app
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: django-service
cluster: django-cluster
wait-for-service-stability: true
まとめ
今回はGitHub Actionsを利用して、GithubへファイルをPushすることで、コンテナイメージの作成からECSのデプロイまでのCICDパイプラインを作成しました。ほとんどがコミュニティアクションで構成することができるので簡単に構築することができました。
Discussion