AWS Fargate の「タスクのスケジューリング」でバッチ用コンテナを定時実行する


概要

  • AWS Fargate には、スケジュールルールに従ってタスクを実行できる機能がある。
  • スケジュールルールは次の2通りある。どちらもスケジュールルールに従って毎回新しいコンテナが起動して終了する。
    • 固定された間隔で実行
    • Cron式
  • この「タスクのスケジューリング」機能を使って、これまで EC2 上の crond で起動して実行していたバッチ処理を、コンテナ化して AWS Fargate に移行してみる。

今回 Fargate に移行するバッチの概要

  • Elasticsearch の インデックスを1日1回削除するバッチ。

    • サーバのアクセスログを Fluentd で Elasticsearch に送ってKibanaで可視化している。1日分のアクセスログを1つのインデックスに格納していて、30日前のインデックスファイルを削除するバッチを1日1回実行している。
  • バッチは bash スクリプトでこんな感じで書いている。

#!/bin/bash
ESDOMAIN="hogehoge.ap-northeast-1.es.amazonaws.com"
INDEXNAME=(
    "fastly-accesslog-"
    "varnish-accesslog-"
    "nginx-accesslog-"
)
DATA=`date -d '30 days ago' +"%Y-%m-%d"`
for INDEX in ${INDEXNAME[@]}; do
  echo "Delete: ${INDEX}${DATA}"
  curl -s -X DELETE https://${ESDOMAIN}/${INDEX}${DATA}
  echo -e "\n"
done
echo "Execution Result"
curl -s -X GET ${ESDOMAIN}/_aliases?pretty | grep -v '}' | sort

バッチ処理を行うコンテナの Dockerfile 作成

FROM alpine:latest
RUN apk --no-cache add tzdata && cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && apk del tzdata
RUN apk --no-cache add coreutils bash bash-completion curl
COPY del-index.sh /del-index.sh
RUN chmod u+x /del-index.sh
CMD /bin/bash /del-index.sh

Dockerfileの簡単な説明

軽量な Alpine Linux を使う

  • いろいろ削がれて軽量になっている。
  • 今回のシェルスクリプトを実行するために必要なものを追加する。

Alpine Linux の timezone を JST に設定

dataコマンド

  • Alpine Linux のdataコマンドは、「date -d '30 days ago'」 を解釈してくれない。 なので、GNU coreutils の date をインストールする。
  • Dockerfile 追加設定
    
    RUN apk --no-cache add coreutils
    

bash

  • Alpine Linux のデフォルトのシェルは sh なので、配列が使えない。bashで書いた次の部分でエラーになってしまう。

INDEXNAME=(
    "fastly-accesslog-"
    "Varnish-accesslog-"
    "nginx-accesslog-"
)
  • シェルスクリプトを sh 用に書き直すのは面倒なので、bashを入れてしまう。
  • Dockerfile 追加設定
    
    RUN apk --no-cache add bash bash-completion
    

curl

  • 今回のバッチは、curl で Elasticsearch の API を叩くので、curl をインストールする。
  • Dockerfile 追加設定
    
    RUN apk --no-cache add curl
    

bashスクリプト本体

  • 今回は del-index.sh という名前で、上記のシェルスクリプトのファイルを作成する。これを Dockerfile と同じディレクトリに置く。
  • docker build 時に del-index.sh ファイルを docker イメージの / にコピーして、実行権限を付与する。
  • コンテナ起動時に、この del-index.sh を実行する。
  • Dockerfile 追加設定
    
    COPY del-index.sh /del-index.sh
    RUN chmod u+x /del-index.sh
    CMD /bin/bash /del-index.sh
    

DockerイメージをECRへプッシュして、Fargete の設定を行う

Fargate タスクのスケジューリング 設定

Fargate タスクのスケジューリングの概要

タスクのスケジューリング設定例

  • Amazon ECS クラスター設定画面 ⇒ タスクのスケジューリング ⇒ 作成

  • スケジュールルール設定
    今回は、毎日午前 6:00 (JST) に実行したいので、Cron 式は cron(0 21 * * ? *)

  • ターゲット設定
    起動タイプで「FARGATE」を選択する。
    タスク定義で上記で作成したものを選択する。

  • VPC とセキュリティグループ
    AWS Fargate で実行したコンテナに固定のグローバルIPアドレスを割り当てる を参考

  • 作成
    以上で、毎日午前 6:00 (JST) に Elasticsearch のインデックスを削除するコンテナが起動して、処理を終えたらコンテナが消滅する。
    実行ログは CloudWatch ログに送られる。

「タスクのスケジューリング」利用時の注意点

参照:Amazon ECS の「タスクのスケジューリング」利用時の注意点

おまけ

Slack にも実行結果を送りたい場合は、del-index.sh に Slack へ送る設定を追加する

#!/bin/bash
ESDOMAIN="hogehoge.ap-northeast-1.es.amazonaws.com"
INDEXNAME=(
    "fastly-accesslog-"
    "Varnish-accesslog-"
    "nginx-accesslog-"
)
DATA=`date -d '30 days ago' +"%Y-%m-%d"`

exec 3>&1
exec > /exec.log
echo "Elasticsearch delete index"
for INDEX in ${INDEXNAME[@]}; do
    echo "Delete Index: ${INDEX}${DATA}"
    curl -s -X DELETE https://${ESDOMAIN}/${INDEX}${DATA}
    echo -e "\n"
done
echo "curl -X GET https://${ESDOMAIN}/_aliases?pretty"
curl -s -X GET ${ESDOMAIN}/_aliases?pretty | grep -v '}' | sort
exec 1>&3

sed -i -e 's/\"//g' /exec.log

channel="hoge"
username="Container"
text="Elasticsearch delete index"
color="gray"
message=`cat /exec.log`
attachments="
{
    \"color\":\"${color}\",
    \"text\": \"${message}\"
}"
emoji=':envelope:'
url="https://hooks.slack.com/services/hoge/hogehoge"
payload="payload={\"channel\": \"${channel}\", \"username\": \"${username}\", \"text\": \"${text}\", \"attachments\":[${attachments}] , \"icon_emoji\": \"${emoji}\"}"
curl -s -m 5 -d "${payload}" $url

exit
  • 標準出力をファイルへ出力する設定
    
    exec 3>&1
    exec > /exec.log
    〜
    exec 1>&3
    
  • 実行結果ファイルからダブルクォーテーションを除外(Slack送信時に invalid_payload エラーとなるため)
    
    sed -i -e 's/\"//g' /exec.log