「ECS Scheduled Taskの管理をecscheduleでGitOps化しました」を読んで実際やってみました

# はじめに

筆者はインフラエンジニア をしており、現在AWS ECSを運用中です。

アプリケーションでバッチ処理をする必要がでてきたので、どうしたものかと悩んでいたら
[こちらの記事](https://tech.connehito.com/entry/2021/03/01/155041)で[ecschedule](https://github.com/Songmu/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のみをデプロイします。

```yaml:workflow.yaml
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"}}` は環境変数にデフォルト値を設定できます。

タスク定義にリビジョンを入れてませんが、リビジョンがない場合、最新のタスク定義をデプロイしてくれます。

```yaml:ecs-events-rules.yaml
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で完結できるようになり、
アプリケーションエンジニアがインフラコードのことまで気にしなくていい状態を作ることができました。