AWSとGitHub Actionsでデプロイをカイゼン

エキサイトのみーです。

アプリケーションのリリースサイクルを速めるためにも、デプロイの改善は重要な要素の1つだと考えています。
今回は、アプリケーションのコンテナ化に際してデプロイをどのように改善させたのか、について紹介します。

これまで

オンプレにおける従来のデプロイは非常に面倒で、ミスしてくれと言わんばかりのものでした。箇条書きにすると、

  • GitHubでPull Requestして、
  • レビューして、
  • mainブランチにマージして、
  • 踏み台サーバにログインして、
  • デプロイサーバにログインして、
  • シェルスクリプト(rsync)を叩く

というような手順。酷いときは、mainブランチにマージしたけどデプロイを忘れる、なんてことも。
mainブランチと本番環境にズレが生じる、みたいなあり得ない状況も度々発生。
そもそもの作業が億劫なのでデプロイ頻度が下がっていく、となるのも当然の結果でした。

アプリケーションをコンテナ化してそれをデプロイするとなると、同じようなやり方では破綻してしまいます。
ということで、より簡単で、より安全なデプロイ方法を検討することになったわけです。

コンテナ化後

試行錯誤の結果、今では以下のような手順に落ち着いています。

  • GitHubでPull Requestして、
  • レビューして、
  • mainブランチにマージされたら、GitHub Actionsで自動デプロイ

これにより、デプロイ作業がGitHubだけでほぼ完結するようになりました。手数も減って、デプロイサーバの管理も不要になって、まさに一石二鳥。
さらにBlue/Greenデプロイも取り入れたことで、より安全にアプリケーションをデプロイできるようになりました。
ここまで来てしまうと、もう昔には戻れません。

構成

大まかな全体構成は以下のような図になっています。今回は左半分の話になりますね。
特別なことは何もしていません。コントロールプレーンはECS、データプレーンはFargate、イメージはECRで管理しています。

f:id:ex-mii:20210426182208p:plain

GitHub Actions

アクションの作成は難しくはないので、全て自作しても良いとは思います。
が、今回はAWSのサービスをフル活用しているので、AWSが公開しているアクションを有効活用することができました。

# GitHub Secretsに登録したアクセスキーなどをセット
- name: Configure AWS credentials
    id: configure-credentials
    uses: aws-actions/configure-aws-credentials@v1
    with:
        aws-access-key-id: ${{ secrets.PROD_AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.PROD_AWS_SECRET_ACCESS_KEY }}
        aws-region: ${{ env.AWS_REGION }}

# ECRにログイン
- name: Login to Amazon ECR
    id: login-ecr
    uses: aws-actions/amazon-ecr-login@v1

# イメージをビルドして、ECRへPush
- name: Build, tag, and push image to Amazon ECR
    id: build-image
    env:
        DOCKER_BUILDKIT: 1
        ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        IMAGE_TAG: ${{ github.sha }}
    run: |
        docker build -t $ECR_REGISTRY/${{ env.ECR_REPOSITORY }}:$IMAGE_TAG .
        docker push $ECR_REGISTRY/${{ env.ECR_REPOSITORY }}:$IMAGE_TAG
        echo "::set-output name=image::$ECR_REGISTRY/${{ env.ECR_REPOSITORY }}:$IMAGE_TAG"

# タスク定義に、先ほどPushしたイメージを反映
- name: Render Amazon ECS task definition
    id: render-web-container
    uses: aws-actions/amazon-ecs-render-task-definition@v1
    with:
        task-definition: task-definition.json
        container-name: app
        image: ${{ steps.build-image.outputs.image }}

# CodeDeployを使用してECSにデプロイ
- name: Deploy to Amazon ECS
    id: deploy
    uses: aws-actions/amazon-ecs-deploy-task-definition@v1
    with:
        task-definition: ${{ steps.render-web-container.outputs.task-definition }}
        service: ${{ env.ECS_SERVICE_NAME }}
        cluster: ${{ env.ECS_CLUSTER_NAME }} 
        wait-for-service-stability: false
        codedeploy-appspec: appspec.yaml
        codedeploy-application: ${{ env.CODEDEPLOY_APPLICATION }}
        codedeploy-deployment-group: ${{ env.CODEDEPLOY_DEPLOYMENT_GROUP }}

aws-actions/amazon-ecs-deploy-task-definitionは、Blue/Greenデプロイにも対応しています。事前にCodeDeployアプリケーションやデプロイメントグループを作成しておくだけで、簡単にBlue/Greenデプロイができるようになります。

このCodeDeployを使用したBlue/Greenデプロイが、私たちに最高にクールな体験を与えてくれているのですが、それはまた別の機会に。

残課題

いろいろと改善できたものの、まだまだ課題は山積みです。

GitHub Actionsで使用するIAMユーザ

GitHub ActionsのワークフローからAWSリソースへアクセスするため、事前にIAMユーザを作成してアクセスキーをGitHubのSecretsに登録しておく必要があります。

IAMユーザには必要な権限のみを付与しているものの、現在はアクセスキーのローテーションをしていないのでセキュリティ的には微妙です。
万が一に備えて、ローテーションの自動化等を検討しておくべきかと思われます。

Pull Requestへのコメントでデプロイ

開発中はもっと簡単にデプロイしたいものです。
そこで、テスト環境などはPull Requestにコメントすることでデプロイされるよう、GitHub Actionsのワークフローを設定しています。

on:
    # コメントが作成・編集されたときに発火
    issue_comment:
        types: [created, edited]

jobs:
    deploy:
        # Pull Request内のコメントが対象、且つ、コメントの先頭に「/test」と入力された場合のみ
        if: contains(github.event.comment.html_url, '/pull/') && startsWith(github.event.comment.body, '/test')

/testとコメントすればテスト環境へデプロイされちゃいます。すごくお手軽。
ただし、どのPull Requestからもデプロイできてしまうという問題も。チーム開発時は事前にルールを決めておくのが良さそうです。

CodePipelineは使わないの?

GitHubだけで完結したかった、ので使っていません。
また、テスト環境へのデプロイを手軽にやりたかったということもあり、GitHub Actionsのほうが適していると判断しました。

おわりに

特に目新しいことはしておらず、公式ドキュメントなどに記載されていることを愚直に実践しただけに過ぎません。
ですが、普通のことを普通に実行するだけで多くの恩恵を得られたのも事実です。カイゼンのポイントはそこかしこに眠っているはず。

クラウドへの移行は大変な作業ですが、クラウドのメリットを活かした構築をすることで、生産性の向上に大きく寄与できると思っています。
この記事が、クラウド移行を検討されている方にとって少しでも参考になれば幸いです。