この記事は、6月から始まっている #LXベッテク月間 6日目の記事です。
昨日は talos さんの 「そろそろあの課題着手しなきゃ!」チームに日々蓄積されるIssueを、Notionで簡単にプロジェクト化〜TODO管理する方法 でした 🐬
バクラク請求書でリードエンジニアをしている @yyoshiki41(中川佳希)です!
最近たどり着いた git で差分があるか確認するコマンドは、git diff --exit-code --quiet
です。
バクラクシリーズでは先月(2022年5月)、経費精算をリリースしました! 今後も更にコーポレート業務全体のデジタル化をサポートしていきます。
この記事では GitHub Actions から ECS でのワンショットタスクを実行する仕組みを紹介します。
処理の流れ
このあたりは先駆者となるツールも複数ありますが、Actions 上で実現したいことは大まかに以下です。
- コンテナの Build, レジストリーへのPush
- Task Definitions の作成
ecs run task
の実行- タスクが完了するまで待つ
- 完了後のログ(CloudWatch Logs)をひろう
※ ECS スタックの作成や、Actions 側で設定必要なIAM(task 実行や CloudWatch Logs のログ取得)は割愛 🙏
そして最後に、一連をまとめた Composite Action を紹介します。
1. コンテナの Build, レジストリーへのPush
docker 公式でサポートされている GitHub Actions があるため、それを利用するだけです。
ビルド時間の短縮に欠かせない cache についても buildx 側で、GitHub Actions cache をサポート(experimental)しており、レジストリでキャッシュする場合同様に複雑な箇所は特にありません。
buildx で、GitHub Actions cache を使う場合の例
- name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Build and push uses: docker/build-push-action@v3 with: context: . push: true tags: user/app:latest cache-from: type=gha cache-to: type=gha,mode=max
2. Task Definitions の定義
コンテナの設定とワンショットで実行するタスク定義を行います。
aws-actions/amazon-ecs-render-task-definition で、ローカルの task-definition.json
ファイルを上書きします。
- 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: web image: amazon/amazon-ecs-sample:latest environment-variables: "LOG_LEVEL=info"
3. ecs run task
の実行
普段ならここで aws-actions/amazon-ecs-deploy-task-definition を利用するところですが、今回実現したいのは「コンテナのサービスイン => タスク終了 => ログをひろう」という一連のサイクルであるため、AWS が用意する API 叩いて実行する必要があります。
$ aws ecs run-task \ --region {{ region }} \ --launch-type {{ launch-type }} \ --cluster {{ cluster }} \ --network-configuration 'awsvpcConfiguration={{ vpc_configuration }}' \ --task-definition {{ family:revision }} \ --overrides '{"containerOverrides": [{"name": {{ container-name}}, "command": {{ command }} }]}'
最後の --overrideds
の部分では、実行時に動的に変えたいコマンドオプションをわたしています。
4. タスクが完了するまで待つ
AWS CLI では、wait
オプションが用意されています。(6秒ごとにヘルスチェックをおこない、完了までポーリング)
$ aws ecs wait tasks-stopped \ --cluster {{ cluster }} \ --tasks {{ task_arn }}
5. 完了後のログ(CloudWatch Logs)をひろう
AWS CLI で実行したタスクIDのログを取得する方法でこなれたものがないため、ecs-cli を用います。
$ ecs-cli logs --timestamps \ --cluster {{ cluster }} \ --task-id {{ task_id }} \ --task-def {{ family }}:{{ revision }}
ちなみに、AWS CLI で該当のロググループから取得する場合はこちら。(--since
でタイムスタンプでのフィルタ)
$ aws logs tail /ecs/your-log-group-name --since=10m
Composite Action にまとめる
今回、複数レポジトリから使用したいこともあり、一連処理をまとめた Composite Action にしました。(内部の動きは上で紹介したとおりです)
タスク実行後に、PR に対してコメントを残す例
- name: Amazon ECS task definition id: task-def uses: aws-actions/amazon-ecs-render-task-definition@v1 with: task-definition: ./infra/migrations/task-definition.json container-name: payer-stg-db-migration image: image-uri - name: Run ECS task id: run-task uses: yyoshiki41/ecs-run-task-action@v0.0.5 with: task-definition: ${{ steps.task-def.outputs.task-definition }} task-definition-family: dev-migration cluster: dev subnets: '["subnet-**"]' security-groups: '["sg-***"]' container-name: migration command: '["up"]' - name: Create PR Comment run: | gh pr comment ${{ github.event.pull_request.number }} --body "<details><summary>Logs</summary> \`\`\` ${{ steps.run-task.outputs.logs }} \`\`\` </details>"
GitHub Actions で出来ることが増えいていて嬉しい限りです。今後も CI/CD やデイリージョブを GitHub Actions に載せていきたいと思います!
LayerX ではエンジニア採用をオープンしています。カジュアルに話をする機会などもありますのでお待ちしております!