Dockerfileとタスク定義の変更を既存のFargateに自動デプロイするGithub Actionsを設定した

Dockerfile とタスク定義ファイルが変更され、レポジトリに Push される度にプロセスを自動実行する Github Actions を設定します。
2020.06.24

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こちらの記事を参考にタスク定義が更新される度に既存環境の Fargate へ自動デプロイをする Github Actions を設定したので手順を書き残しておくことにしました。

参考: GitHub Actions からサクッと Fargate にデプロイしてみた

ケースシナリオ

Dockerfile とタスク定義ファイルが変更され、レポジトリに Push される度に以下のプロセスを自動実行する Github Actions を設定します。その際に任意の環境へ Assume Role しデプロイできるように設定します。

  1. AWS 環境へ Assume Role する
  2. Docker イメージをビルドして既存の ECR へ Push する
  3. 新しい Image ID でタスク定義を更新する
  4. ECSクラスタにタスクをデプロイする

環境構成図

既存環境の全体の構成はこんな感じです。

今回設定するのはこのあたりです。

Dockerfile

テスト用に Apache httpd のコンテナイメージを指定した Dockerfile を作成しました。 既存環境には nginx のサンプルイメージが上がっているので、httpd に変更します。

FROM httpd

Role の設定

Assume Role したい環境で IAM Role を作成し、必要な権限を渡します。 Role の ARN を 後述の Github Actions に渡します。

Github Actions

.github/workflows/ディレクトリ下にymlファイルを作成し Actions の定義を書いてゆきます。 AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYGithub の Secret にあらかじめ登録しておきます。

on:
  push:
    branches:
      - master

name: Deploy to Amazon ECS

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v1

      - 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
          role-to-assume: <ROLE_ARN>
          role-duration-seconds: 1200
          role-session-name: cdk-assume-role

      - 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: sample-repo
          IMAGE_TAG: ${{ github.sha }}
        run: |
          # Build a docker container and
          # push it to ECR so that it can
          # be deployed to ECS.
          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: task-definition.json
          container-name: web
          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: <YOUR_SERVICE_NAME>
          cluster: <YOUR_CLUSTER_NAME>
          wait-for-service-stability: true

タスク定義

タスク定義ファイルを作成します。既存の環境にデプロイする場合、必要な Role やタスク定義の名前などが必要です。既存のタスク定義の JSON を覗くと何を書けばいいのかだいたいわかるので参考にしてください。

task-definition.json:

{
  "executionRoleArn": "<TASK_EXECUTION_IAM_ROLE>",
  "containerDefinitions": [
    {
      "portMappings": [
        {
          "hostPort": 80,
          "protocol": "tcp",
          "containerPort": 80
        }
      ],
      "image": "hoge",
      "name": "web"
    }
  ],
  "placementConstraints": [],
  "memory": "1024",
  "taskRoleArn": "<TASK_ROLE>",
  "family": "<TASK_DEFINITION_NAME>",
  "requiresCompatibilities": ["FARGATE"],
  "networkMode": "awsvpc",
  "cpu": "512",
  "revision": 1,
  "status": "ACTIVE"
}

既存環境の確認

新しいイメージをデプロイする前に既存の環境を確認します。

ALB から確認すると、既存環境にはnginxのコンテナがデプロイされています。 これがhttpdに変われば成功です。

実行してみる

レポジトリへ Push してみましょう。 この時点でのファイル構成はこうなっています。

├── .github
│   └── workflows
│       └── aws.yml
├── Dockerfile
├── README.md
└── task-definition.json

タスク定義を更新すると、新しいものを立てて既存のコンテナインスタンスを削除するため、少し時間がかかります。インスタンス内に実行中のタスクがある場合は終了するまで待ってからコンテナインスタンスは停止します。

GUI で ECS のクラスタを確認して見ると、通常は2つのコンテナインスタンスが入れ替えの時は4つ動いていることがわかります。

更新が無事に終わるとインスタンスはまた2つに戻ります。

Github の Actions タブから Actions のステータスが確認できますが、このように全て正常終了すれば完了です。

動作確認

ALB からイメージを確認してみましょう。

このように httpd のイメージに差し代わっていれば成功です。

Reference