repl.info

AWS Batchのジョブ定義をデプロイするためのツールを作った

僕は今の仕事でAWS Batchを使っているのですが、ジョブ定義のデプロイ方法がちょっとした悩みでした。AWS Batchのジョブ定義はECSにおけるタスク定義と同様、アプリケーション側のリポジトリで管理したいものです。なぜなら、ジョブ定義にはイメージや環境変数など、インフラとはライフサイクルが少し違う要素が含まれているからです。できるなら、ecspressoやlambroll、ecscheduleのような感覚でジョブ定義をデプロイできるとうれしいのではないでしょうか。

そこで、AWS Batchのジョブ定義をデプロイするためのツールとして「batron」 https://github.com/takaishi/batron を作りました。ものとしてはecspressoと同じような感覚で使えます。現在はジョブ定義の表示、デプロイ、古いジョブ定義の削除をサポートしています。 ジョブ定義のデプロイ方法として、これまではaws cliを使っていました。

aws batch register-job-definition \
  --job-definition-name ${JOB_DEFINITION_NAME} \
  --type container \
  --platform-capabilities "FARGATE" \
  --retry-strategy 'attempts=3,evaluateOnExit=[{onStatusReason="Essential container in task exited",action="RETRY"},{onReason="*", action="EXIT"}]' \
  --ecs-properties "$(./jsonnet ./path/to/job-def.jsonnet \
  --ext-str imageTag=${IMAGE_TAG})"

jsonnetとaws cliを組み合わせることで、イメージタグのような動的に変わる値を扱うことができます。また、ジョブ定義をデプロイした後に古いジョブ定義をderegisterしたいわけですが、これもaws cliで実装していました。

REGISTERED_JOB_DEFINITION=$(aws batch register-job-definition \
  --job-definition-name ${JOB_DEFINITION_NAME} \
  --type container \
  --platform-capabilities "FARGATE" \
  --retry-strategy 'attempts=3,evaluateOnExit=[{onStatusReason="Essential container in task exited",action="RETRY"},{onReason="*", action="EXIT"}]' \
  --ecs-properties "$(./jsonnet ./path/to/job-def.jsonnet \
  --ext-str imageTag=${IMAGE_TAG})"
)
JOB_DEFINITION_ARN=$(echo $REGISTERED_JOB_DEFINITION | jq -r '.jobDefinitionArn')
aws batch describe-job-definitions \
  --job-definition-name ${JOB_DEFINITION_NAME} \
  --status ACTIVE \
  | jq -r ".jobDefinitions[] | select(.jobDefinitionArn != \"${JOB_DEFINITION_ARN}\") | .jobDefinitionArn" \
  | while read arn; do aws batch deregister-job-definition --job-definition $arn; done

しかし、aws cliを使う場合、ジョブ定義の内容がjob-def.jsonnetとregister-job-definitionの引数の二カ所に散らばってしまい、わかりにくさを感じていました。また、古いジョブ定義の削除処理も煩雑です。

そこで batron を作ったわけですが、これを使ってジョブ定義のデプロイと古いジョブ定義の削除を書くと以下のようになります。スッキリしていますね。

./batron deploy \
  --config ./path/to/batron.jsonnet \
  --ext-str=imageTag=${IMAGE_TAG}

./batron deregister \
  --keeps=1 \
  --config ./path/to/batron.jsonnet \
  --ext-str=imageTag=${IMAGE_TAG}

batron.jsonnetは、今はジョブ定義のファイル指定するのみです。将来的にはtfstateの参照などを可能にするつもりです。

{
  job_definition: 'job-def.jsonnet'
}

job-def.jsonnetにはRegisterJobDefinitionのリクエストボディを素朴に書けばOKです。つまり、 https://docs.aws.amazon.com/batch/latest/APIReference/API_RegisterJobDefinition.html を見てそのまま書けばいい。jsonnetが使えるので、外部から値を埋め込むこともできます。

local imageTag = std.extVar('imageTag');

{
  jobDefinitionName: "hoge-job",
  type: "container",
  platformCapabilities: ["FARGATE"],
  retryStrategy: {
    attempts: 3,
    evaluateOnExit: [
      { onStatusReason: "Essential container in task exited", action: "RETRY" },
      { onReason: "*", action: "EXIT" }
    ]
  },
  ecsProperties: {
    taskProperties: [
     {
       containers: [
         {
           image: std.format('image:%s', [imageTag]),
           command: [],
           resourceRequirements: [
             {
               type: "VCPU",
               value: "2"
             },
             {
               type: "MEMORY",
               value: "4096"
             }
           ],
         }
       ]
     }
   ]
 }
}

今はジョブ定義に関する機能しかありませんが、今後ジョブの実行や実行中のジョブのログ閲覧、ジョブの終了待ちなどAWS Batchに関する機能を実装しようと思っています。AWS Batchを運用していて、ジョブ定義の扱いに困っている人は是非試してみてください。