はじめに
筆者はインフラエンジニア をしており、現在AWS ECSを運用中です。
アプリケーションでバッチ処理をする必要がでてきたので、どうしたものかと悩んでいたら
こちらの記事でecscheduleというOSSを知り実際に使ってみたので、設定内容と所感を共有できたらと思い記事を書きました。
背景
バッチ処理にはバッチスケジューラーのRundeckを使ったり、
StepFunctionsとLambdaを使ってバッチワークフローを組んだりしてました。
ただ、アプリケーションがRuby on RailsでECS上で動いており、バッチもRuby on Railsのrakeタスクで実行したいので、ECSで実行できないかと考えてました。
前提条件
- docker imageのタグ運用
docker imageはlatest運用はしません。
ロールバックが可能であること、また間違ったアプリケーションのデプロイ防止をしたいので gitのcommit idをdocker imageタグとして使っています。
- Terraformによるインフラ管理
インフラはTerraformで管理しています。
stateファイルを持っているため、stateファイルとAWS環境との差分は出ない状態を目指します。
- CI/CDはGithub Actions
コンテナを購入しないと並列処理ができないCircleCIと違い並列処理が容易なので、採用してます。
ecscheduleを採用する経緯
TerraformでECS Task Scheduleを管理をすることを考えましたが、
ECS Task Scheduleに記載するタスク定義の更新をするためにTerraformでデプロイするか aws cliでデプロイするかのどちらかをする必要がありました。
TerraformでデプロイだとアプリケーションエンジニアがTerraformを触る必要がありハードルがあります。またaws cliだと、バッチ処理を増やしていくごとにGitHub Actionsのworkflowでコマンドを複数行記載する必要があります。将来的にバッチが増えた時に読みにくくなるため、あまり現実的でないと感じました。
そのため、いいツールはないかと考えていたところ出会ったのが、ecscheduleです。
追加したいバッチをyamlファイルで完結できるし、アプリケーションエンジニアが触りやすいと感じました。
設定内容
Github Actionsは以下の通りに記載しました。
ちなみにタスク定義のデプロイはこの前の処理で行っており、そこは割愛しています。
ここではECS Scheduled Taskのみをデプロイします。
deploy-ecs-scheduled:
name: Deploy ECS Batch Task
runs-on: ubuntu-latest
needs: create-rake-task-def #こちらでタスク定義をデプロイします
steps:
- name: Checkout
uses: actions/checkout@v2
- name: setup ecschedule
env:
ECSCHEDULE_VERSION: 0.3.1
ECSCHEDULE_MD5_HASH: 28bdd174e4f012e0345d701ac46f1038
run: |
sudo apt-get update
sudo apt-get install -y make curl
curl -L https://github.com/Songmu/ecschedule/releases/download/v${ECSCHEDULE_VERSION}/ecschedule_v${ECSCHEDULE_VERSION}_linux_amd64.tar.gz -o ecschedule.tgz
echo "${ECSCHEDULE_MD5_HASH} ecschedule.tgz" | md5sum -c -
tar vxf ecschedule.tgz
sudo mv -v ecschedule_v${ECSCHEDULE_VERSION}_linux_amd64/ecschedule /usr/local/bin/.
- name: Deploy Amazon ECS task scheduled
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
ENV_NAME: stg
SUBNET: subnet-XXXX
SECURITY_GROUP: sg-XXXX
run: |
ecschedule apply -conf ecs-events-rules.yaml -all
ecscheduleはyaml内で変数展開ができるので、 ecs-events-rules.yaml
で本番・ステージング環境での差分を変数で渡して実行します。
{{ must_env "ENV_NAME" }}
は環境変数を展開し、 {{ env "SUBNET" "subnet-tmpXXXX"}}
は環境変数にデフォルト値を設定できます。
タスク定義にリビジョンを入れてませんが、リビジョンがない場合、最新のタスク定義をデプロイしてくれます。
region: ap-northeast-1
cluster: {{ must_env "ENV_NAME" }}-cluster1
rules:
- name: rake_task_1
description: Rake Task1
scheduleExpression: cron(*/5 * ? * * *)
taskDefinition: {{ must_env "ENV_NAME" }}-rake-task #最新タスク定義をデプロイする
containerOverrides:
- name: {{ must_env "ENV_NAME" }}-app
command: [bundle, exec, rake, tmp:clear]
launch_type: FARGATE
platform_version: LATEST
network_configuration:
aws_vpc_configuration:
subnets:
- {{ env "SUBNET" "subnet-tmpXXXX"}}
security_groups:
- {{ must_env "SECURITY_GROUP" }}
課題感
いままでecscheduleのいいところばかり伝えてましたが、デメリットもあります。
それはECS Scheduled Taskの削除です。
現状ドキュメントや使い方を読んだところ、追加はできるのですが、削除の文言がなかったのと、
実際に追加したECS Scheduled Taskをecs-events-rules.yaml
から削除されるかを試してみたら削除されませんでした。
そのため、ECS Scheduled Taskのデプロイはecscheduleに任せて、ECS Scheduled Taskの管理はTerraformでする運用が無難になります。
まとめ
結局Terraform管理する必要はありますが、デプロイをGitHub Actionsで完結できるようになり、
アプリケーションエンジニアがインフラコードのことまで気にしなくていい状態を作ることができました。