FargateのデプロイをGitHub Actionsで試してるけど、むちゃくちゃ楽だな〜
— adachin👾SRE (@adachin0817) July 22, 2023
さてと、2ヶ月ぶりのブログとなります(冷汗)。今までは以下CircleCIによるECS/Fargateのデプロイを実装していましたが、今回始めて、GitHub Actionsを利用してデプロイを実装してみました。CircleCIと比べてみると悩むことなく非常に簡単に作れてしまったので解説していきたいと思います。
[ECS/Fargate][run-task][Rails]CircleCI Orbsを使ってdb:migrateを行う
デプロイフロー
- Stg
- リモートブランチとworkflow_dispatchを利用して手動でデプロイとマイグレーション
- 本番
- Masterマージでデプロイとマイグレーション
CircleCIとデプロイフローは同じで、ローリングアップデートですね。また、今回のAppコンテナはRailsとしましょう。
Stg
- .github/workflows/deploy-stg-app.yaml
https://github.com/aws-actions/amazon-ecr-login
https://github.com/aws-actions/amazon-ecs-render-task-definition
https://github.com/aws-actions/amazon-ecs-deploy-task-definition
https://github.com/yyoshiki41/ecs-run-task-action
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
name: Deploy-stg-app on: # pull_request: workflow_dispatch: inputs: name: description: 'Name' required: true env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} SLACK_USERNAME: deploy-stg-app SLACK_CHANNEL: deploy SLACK_ICON: https://avatars.githubusercontent.com/u/44036562?s=280&v=4 AWS_ROLE_NAME: githubactions-oidc AWS_ROLE_SESSION_NAME: githubactions-oidc AWS_REGION: ap-northeast-1 ECR_REPOSITORY: app ECS_SERVICE: app-service ECS_CLUSTER: adachin-cluster ECS_TASK_DEFINITION: terraform/stg/files/task-definitions/github-actions-app.json CONTAINER_NAME: app permissions: id-token: write contents: read jobs: deploy-app-ecs: name: deploy-app-ecs runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@master with: role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ env.AWS_ROLE_NAME }} role-session-name: ${{ env.AWS_ROLE_SESSION_NAME }} aws-region: ${{ env.AWS_REGION }} - name: Download file from S3 .env run: | aws s3 cp s3://hoge-backup/app/env ./.env --quiet - name: Login ECR id: login-ecr uses: aws-actions/amazon-ecr-login@v1 - name: Build, tag, and push image to ECR id: build-image env: ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} IMAGE_TAG: ${{ github.sha }} run: | docker build -f docker/stg/app/Dockerfile -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: New image ID ECS task definition id: task-def uses: aws-actions/amazon-ecs-render-task-definition@v1 with: task-definition: ${{ env.ECS_TASK_DEFINITION }} container-name: ${{ env.CONTAINER_NAME }} image: ${{ steps.build-image.outputs.image }} - name: Deploy 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 - name: Slack Success if: ${{ success() }} uses: rtCamp/action-slack-notify@v2 env: SLACK_TITLE: Deploy stg App Success SLACK_COLOR: good - name: Slack Failure if: ${{ failure() }} uses: rtCamp/action-slack-notify@v2 env: SLACK_TITLE: Deploy stg App Failure SLACK_COLOR: danger - name: Run ECS task migration id: run-task uses: yyoshiki41/ecs-run-task-action@v0.0.8 with: task-definition: ${{ steps.task-def.outputs.task-definition }} task-definition-family: app cluster: ${{ env.ECS_CLUSTER }} subnets: '["subnet-xxxxxx","subnet-xxxxxxx"]' security-groups: '["sg-xxxxxx","sg-xxxxxx"]' container-name: ${{ env.CONTAINER_NAME }} command: '["bundle","exec","rake","db:migrate","RAILS_ENV=staging"]' - name: Slack Success if: ${{ success() }} uses: rtCamp/action-slack-notify@v2 env: SLACK_TITLE: Deploy stg migration Success SLACK_COLOR: good - name: Slack Failure if: ${{ failure() }} uses: rtCamp/action-slack-notify@v2 env: SLACK_TITLE: Deploy stg migration Failure SLACK_COLOR: danger |
37行目ではGitHubでクレデンシャルを管理したくないため、OIDCを設定しています。初期設定に関しては以下を参考にしてください。
44行目ではRailsの.envをS3で管理しているため、ソースコード先にコピーしています。52行目はコンテナのbuildをするために環境変数とImage TagでGitHubのshaを利用しています。62行目ではタスク定義を更新しなければならないのですが、ECS/FargateはTerraformで管理しており、Terraformで管理しているタスク定義とは別にGitHub Actionsで利用するAppコンテナのタスク定義を以下に準備しました。CircleCIの場合、Orbsでタスク定義の更新はよしなにやってくるので、ちょい手間がかかるかもしれません。
- terraform/stg/files/task–definitions/github–actions–app.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
{ "family": "app", "taskRoleArn": "arn:aws:iam::xxxxxxxxx:role/ecs-TaskExecutionRole", "executionRoleArn": "arn:aws:iam::xxxxxxxxx:role/ecs-TaskExecutionRole", "networkMode": "awsvpc", "requiresCompatibilities": ["FARGATE"], "cpu": "1024", "memory": "2048", "containerDefinitions": [{ "name": "app", "image": "xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/app", "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "/ecs/app", "awslogs-region": "ap-northeast-1", "awslogs-stream-prefix": "ecs" } }, "essential": true, "cpu": 1024, "memory": 1920, "portMappings": [{ "hostPort": 80, "containerPort": 80, "protocol": "tcp" } ], "command": [ "/usr/bin/supervisord" ] } ] } |
70行目ではタスク定義からローリングアップデートを実施します。 wait-for-service-stability
をtrueにすることで、ECSサービスの安定稼働するために実行完了を待つようになります。ですが、Stg環境であれば安定稼働必須ではないはずなのと、完全に切り替わるまで少し時間がかかるので、この設定は不要かもしれないですね。と思いきや、単純にfalseにするとローリングアップデートの処理を実行してActions側は終了になってしまいます。なので、切り替わるのが終わるまで待ったほうが分かりやすいのでtrue必須になりますね。
最後に92行目で、コンテナが切り替わった後にrun-taskでマイグレーションを実行して完了となります。
実際にデプロイしてみましょう。
- 動作確認
本番
- .github/workflows/deploy-prd-app.yaml
本番は以下branchesをMasterマージで発動でStgとコードは同様なため、割愛させていただきます。
1 2 3 4 5 6 7 |
name: Deploy-prd-app on: push: branches: [master] ~省略~ |
まとめ
CircleCIで慣れちゃってるのもありますが、GitHub Actionsでは初だったのでいい経験だった!学習コストは低いのでお試しあれ!あとはデプロイの高速化かな。wikiに書いておきました。
コンテナ分離する場合は以下を参考に。
0件のコメント