Edited at

AWS ECSを使ったバッチサーバ環境を試してみる


はじめに

バッチの実行環境を作る場合、いろんな選択肢があります。


  1. ec2を立ててその上でcronを動かす。

  2. lambdaとcloudWatchEventの組み合わせ。一つのバッチに対して一つのlambdaがひもづくみたいな環境を作る。

  3. AWS batchを使う。

  4. ECSのサービス起動しているコンテナ内にcronを定義して実行

  5. ECSのScheduleTaskを使う。

それぞれのメリデメは以下の記事にまとまっており、大変参考になりました。

この記事でも書いてある通り、ECSのScheduleTaskを使うのがバッチ処理にはすごく向いていると思い、試してみました。

http://tech.connehito.com/entry/2017/09/13/171914


サンプルとして使うAPIサーバ

以下のapiを叩くと、slackに通知が行くような簡単なAPIを作りました。

コードはこちら => github

このサーバーのデプロイとスケジュール実行にECSを使っていきます。

curl ***.***.***.***/api/hoge

スクリーンショット 2019-06-16 10.47.16.png

curl ***.***.***.***/api/sample

スクリーンショット 2019-06-16 10.48.25.png


事前準備

ecs-cliのインストール

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ECS_CLI_installation.html

ecs-cliで利用するアカウントの設定

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/cmd-ecs-cli-configure-profile.html

あとで使うため、awsコンソール上でキーペアを作成

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/get-set-up-for-amazon-ecs.html#create-a-key-pair


クラスターの作成

$ ecs-cli configure --region ap-northeast-1 --cluster batch

INFO[0000] Saved ECS CLI cluster configuration default.
$


クラスタの起動

--keypair には事前準備で作成しておいたキーペアのキーペア名を入れます

$ ecs-cli up --keypair ecs1 --capability-iam --instance-type t2.micro

INFO[0000] Using recommended Amazon Linux 2 AMI with ECS Agent 1.29.0 and Docker version 18.06.1-ce
INFO[0000] Created cluster cluster=batch region=ap-northeast-1
INFO[0001] Waiting for your cluster resources to be created...
INFO[0001] Cloudformation stack status stackStatus=CREATE_IN_PROGRESS
INFO[0061] Cloudformation stack status stackStatus=CREATE_IN_PROGRESS
INFO[0122] Cloudformation stack status stackStatus=CREATE_IN_PROGRESS
VPC created: vpc-06a96d66a28a309d5
Security Group created: sg-06963801d57d9b397
Subnet created: subnet-002a9338da5410dcf
Subnet created: subnet-0cf2a1265a7b2dae4
Cluster creation succeeded.
$


docker-compose.ymlを使ってタスク定義を作成、起動する

※docker-compose.ymlがあるdirに移動してから実行

$ ecs-cli compose up

INFO[0000] Using ECS task definition TaskDefinition="ecs-batch:4"
INFO[0001] Starting container... container=2cd79d8c-9374-4a9f-a956-453246a0f079/app
INFO[0001] Describe ECS container status container=2cd79d8c-9374-4a9f-a956-453246a0f079/app desiredStatus=RUNNING lastStatus=PENDING taskDefinition="ecs-batch:4"
INFO[0013] Started container... container=2cd79d8c-9374-4a9f-a956-453246a0f079/app desiredStatus=RUNNING lastStatus=RUNNING taskDefinition="ecs-batch:4"
$


APIサーバ自体のデプロイは完了

ここまでの手順で

curl ***.***.***.***/api/hoge

curl ***.***.***.***/api/sample

を実行するとslackに通知が飛ぶサーバーを構築することはできました。

これをECSのScheduleTaskから実行できるようにしていきます。


curlするだけのdockerを作る。

このcurlするだけのdockerイメージは docker hubECR にpushしておきます。

FROM alpine:3.7

RUN apk update
RUN apk add curl
CMD curl --help

このイメージを何に使うかというと、このcurlをただ実行するだけのコンテナをECSのタスク定義として登録します。そしてこのイメージの CMD を上書きする形でECSのScheduleTaskを登録していくイメージです。

ScheduleTaskを定義する際、コンテナのコマンドの上書きができます。

curl ***.***.***.***/api/hoge, curl ***.***.***.***/api/sample にコンテナのコマンドを上書き、それらをスケジュール登録していきます。


curl --helpを実行するタスク定義を作る

新しいタスク定義の作成 をクリック

スクリーンショット 2019-06-15 6.40.27.png

EC2を選んで 次のステップ をクリック。(ただcurlを実行するだけで常に起動している必要がないのでFARGATEの方がいい気がする。)

スクリーンショット 2019-06-15 6.41.51.png

タスク定義名: curl

スクリーンショット 2019-06-16 11.51.52.png

コンテナの追加 を押す

スクリーンショット 2019-06-16 11.52.43.png

コンテナ名: curl

イメージ: docker hubかECRのイメージを入力

メモリ制限: 128(埋めないと追加ボタン押せなかった)

追加をクリック

スクリーンショット_2019-06-16_11_54_04.png

作成 をクリック

スクリーンショット 2019-06-15 6.48.43.png

ただ curl --help を実行するだけのタスク定義が作成される

スクリーンショット 2019-06-16 11.58.43.png


ECSのScheduleTaskを登録していく

クラスター => タスクのスケジューリング => 作成

スクリーンショット 2019-06-15 6.54.35.png

スケジュールルールの名前: sample

スケジュールルールの説明: sample API

スケジュール間隔は1分おき。※等間隔実行だけでなく、cron形式でも書くことができます。

スクリーンショット 2019-06-16 12.01.34.png

ターゲットID: sample

タスク定義: 事前に作成しておいた curl を選択

スクリーンショット 2019-06-16 12.03.47.png

コンテナの上書き。コマンドをsampleAPIを叩くcurlに変更して作成をクリック

スクリーンショット_2019-06-16_12_05_19.png

注意するところして、コマンドはカンマ区切りの文字列である必要があります。


コマンドのオーバーライドの場合: [Command override] に、送信するコマンドオーバーライドを入力します。コンテナ定義で ENTRYPOINT が指定されていない場合は、引用符のない文字列のカンマ区切りリストである必要があります。例:



バッチの実行確認

上と同じ感じで curl ***.***.***.***/api/hoge の方のScheduleTaskも登録します。

※hogeの方は5分間隔で作成しました。

スクリーンショット 2019-06-16 12.18.52.png

slackを確認するとこの二つのバッチが指定した間隔通りに定期実行されていることがわかります。

スクリーンショット 2019-06-16 12.16.01.png


最後に

ECSのタスクのスケジューリングの機能を使えば、awsの画面上からバッチの一覧を確認できますし、特定のバッチの有効/無効も画面上でぽちぽちするだけで完結します。

また、スケジュール系のバッチサーバはドメインロジックに深く関わってくる、落ちたらやばいサーバーとなることがほとんどだと思います。

node.jsで作ったサーバー(expressとか)などの場合、pm2を用いて常時サーバーが起動していることの担保をしたりしますが、たまにpm2自体が音もなく死んでいることがありました。

ECSを使う場合、サービスを定義すれば常時何個のタスク(コンテナの集合体)を起動しておくかを定義できるため、pm2からも解放される気がしてます。