Timers Tech Blog

グローバルな家族アプリFammを運営するTimers inc (タイマーズ) の公式Tech Blogです。弊社のエンジニアリングを支える記事を随時公開。エンジニア絶賛採用中!→ https://timers-inc.com/engineering

ECS on Fargateでステートフルなバッチを動かすためにやったこと

Timersのサーバーエンジニアの鈴木です。

去年地元静岡に移住し、フルリモートで働いているのですが、茶畑のそばを散歩するのが日課になっています。

今回はEC2で行っていたステートフルなバッチ処理AWS Fargate(以下Fargate)に移行したので紹介します。

なぜやったの?

弊社では去年からAPIサーバを皮切りに、定期バッチ処理などをEC2インスタンスからFargateへ移行を進めていました。

メンテナンスや運用が必要なEC2インスタンスから運用や追加開発・インフラ改善が容易になるFargateに移行することで、 インフラの改善速度や品質を向上させる目的です。

今回移行したサーバでは具体的に下記のようなメリットを見込んで移行に踏み切りました。

  • 数年間同じインスタンスを使っており、開発環境はAPIサーバと同居した状態で、本番インスタンスと差分があり、厳密に同じ状態でテストできていなかったのでその解消
  • CIでの自動テストが行いやすくなる

今回移行するサーバの処理内容

今回移行するサーバで行う処理はカレンダー作成を行うバッチになります。

Fammでは毎月アップロードした写真をご家族に配送するサービスがあります。

このバッチは配送のための下記処理をまるっと行う巨大バッチです。

  • カレンダー画像の作成
  • 決済
  • 通知
  • 印刷業者への入稿データ作成

複雑かつサービスの根幹となる処理のため、なるべくロジックには手を入れずステートフルなままコンテナ化する必要がありました。

ただ素直にコンテナ化するとうまく行かない部分が次の2点でした。

  1. エラー時にコンテナ停止しないこと。
  2. エラー時にコンテナ内部に入って調査やリランできること。

そのため下記のような工夫で乗り切っています。

1. エラー時にコンテナ停止しないこと

通常Fargateで起動時に実行したコマンドがエラーになった場合、コンテナが停止してします。

これを回避すべく、起動コマンドではsupervisordを動かし、本来動かしたいバッチスクリプトはsupervisordから起動させています。

具体的にはECSのContainerOverridesのCommandに下記のように指定しています。

["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]

これによってsupervisorで動かした各処理がエラーになった場合でもコンテナ自体は停止しないようになります。

ただPID 1 プロセスにしかECSタスクロールが割り当てられないため、このままでは各スクリプトAWSリソースへの操作ができません。

これを解決するため、参考情報を元にsupervisorで動かす各スクリプトの先頭に下記のように環境変数をセットしています。

# タスクロールを使ってAWSリソースにアクセスできるようにする
AWS_TASK_ROLE_ENV=$(sudo strings /proc/1/environ | grep AWS_CONTAINER_CREDENTIALS_RELATIVE_URI)
export $AWS_TASK_ROLE_ENV

2 障害時にコンテナ内に入って調査できること

今回のバッチはステートフルなバッチ処理のため、障害時にはコンテナ内で調査やリランをする必要がありました。

sshdでログインするやり方もありますが、今回はSSM エージェントをコンテナ内に常駐させ、AWS Systems Manager(以下Systems Manager)のコンソール上でログインができるようにしました。

具体的には下記スクリプトを動かして、アクティベーションをSystem Managerに登録しています。

readonly ENV=$1
readonly EXPIRATION_DATE=$(date +%Y-%m-%d --date '20 day')

# AWS Systems Managerのアクティベーションを作成して、このコンテナを登録する
ACTIVATE_PARAMETERS=$(aws ssm create-activation \
  --default-instance-name "my-batch-$ENV" \
  --description "[$ENV]My Batch" \
  --iam-role "service-role/AmazonEC2RunCommandRoleForManagedInstances" \
  --expiration-date $EXPIRATION_DATE \
  --registration-limit 5)

export ACTIVATE_CODE=$(echo $ACTIVATE_PARAMETERS | jq -r .ActivationCode)
export ACTIVATE_ID=$(echo $ACTIVATE_PARAMETERS | jq -r .ActivationId)

amazon-ssm-agent -register -code "${ACTIVATE_CODE}" -id "${ACTIVATE_ID}" -region "ap-northeast-1" -y
amazon-ssm-agent

これでAWSコンソール上からコンテナ内に入って操作ができるようになります。

f:id:timers-tech:20210312103455p:plain
session managerでコンテナ内にログイン

その他注意すべきこと

その他、移行に関して注意すべきことは下記の2つになります。

  • Fargateのストレージサイズが20GB固定で、増やす場合の選択肢がEFSしかないが、短期間に大量のファイルIOが発生する場合はEBSに比べ数倍遅い。
  • FargateのCPUの最大値がEC2のインスタンスタイプだとc4.xlarge相当なので、複数コンテナでスケールできないバッチはスペック要求を満たせない場合がある。

まとめ

上記の工夫によってFargateでステートフルなバッチ処理を動かすことがでました。

先述した注意点はあるものの、それがクリアできる場合、ステートフルなバッチだからと二の足を踏んでいたバッチもFargateに移行できると思います。

ステートフルなまま移行できるのがミソで、コンテナの思想とは相反する部分もありますが、運用的にも移行前と変わらないため移行のハードルは低いと思うので参考になればうれしいです。

PR

子育て家族アプリFammを運営するTimers inc.では現在エンジニアを積極採用中! オンラインでの面談やカジュアルランチなどもやってますので是非お気軽にご連絡ください!

採用HP: http://timers-inc.com/engineerings

www.wantedly.com

参考資料

Timersでは各職種を積極採用中!

急成長スタートアップで、最高のものづくりをしよう。

募集の詳細をみる