一括メール送信のバッチ処理をAWS Batchで構築した時につまずいたこと

ブログをご覧くださり、ありがとうございます。
L小川です。神保町で好きなお店は「にゃんこ堂」と「たいやき神田達磨」です。

先日、ConfitにAWS Batchを導入しました。その際につまづいたことをいくつか紹介します。これからAWS Batchを利用しようとしている方や、同じ事象に悩んでいる方の参考になればと思います。

※AWS Batchの詳細についてはこちらをご参照ください。

AWS Black Belt Online Seminar「AWS Batch」の資料およびQA公開

やりたいこと

「一括メール送信処理をAWS Batchで並列化したい」

Confitには、事務局から複数の利用者にまとめてメールを送信する「一括メール送信機能」があります。

これまでは一括メール送信処理するために1台のバッチサーバを常時稼働していたのですが、複数の処理を同時に実行できませんでした。AWS Batchを導入することで並列に実行でき、大量のメールをより早く送信できるようになります。

要件

今回の要件は以下の通りです。

「AWS BatchでPostfixからAWS SESにリレーしてメール送信する」

まずは試しにAWS Batchのジョブでmailコマンドを実行したところ、メール送信できませんでした。

原因調査のためエラーログを確認しようとしたのですが、この段階で早速つまづきました。

つまづいたポイントその1

エラー調査のためにmailコマンド後に”cat /var/log/maillog”を実行しても、CloudWatch Logsに何も表示されない

[原因]

ジョブで実行したシェルスクリプトでrsyslogを起動していなかったため、ログが出力されていませんでした。

[対策]

シェルスクリプトの“service postfix start”の前に”service rsyslog start”を追加しました。

これでCloudWatch Logsにログが表示されるようになりました。ログを調査したところ、以下の事象が発生していました。

つまづいたポイントその2

mailコマンドを実行するも、メールがmaildrop/下に溜まったままになり送信されていない

[原因]

ECSインスタンスにログインして調べたところ、ECSインスタンスでsendmailが起動しており25番ポートを使っていました。

そのためコンテナで起動したPostfixとポートの競合が発生していました。

[対策]

コンテナのPostfixの送信ポートをデフォルトの25番から変更しました。(ポート番号は実際のものではなくダミーです)

ポート番号を変更してmailコマンドを実行したところ、maildrop/下にメールが溜まる事象は解消できたのですが、まだメールが送信できていません。

つまづいたポイントその3

qmgr以降のログが出ておらず、メールが送信できていない

Postfixはpickup, cleanup, qmgr, smtpなどの複数プロセスが動作しているのですが、ログを見るとpostfix/qmgrのログで終わっており、それ以降のsmtpdのメール送信処理が実行されていないように見えます。

※Postfixについてはこちらが詳しいです。

[原因]

試しにmailコマンド実行後にsleep処理を入れてみると……メールが届いた!

AWS Batchではフォアグラウンド処理の終了と同時にコンテナ自身も終了してしまうようで、バックグラウンド処理が途中で終了していたようです。

[対策]

mailqが空になるまでsleepする処理を入れました。

これでメール送信ができるようになったので、複数コンテナを使って一括メール送信の並列実行を試してみました。

つまづいたポイントその4

複数コンテナで実行したらメール送信エラーが発生した

1000件程度のメールを送信するジョブを2つ同時に実行したところ、片方のジョブが「fatal: bind 127.0.0.1 port 12345: Address already in use」というエラーが出力され、メールを送信できませんでした。

[原因]

コンテナのネットワークモードがhostになっていたため、コンテナ間でポートの競合が発生していました。ネットワークモードをhostからbridgeに変更する方法はないかサポートに問い合わせたところ、

現時点でAWS Batchのジョブ定義では、Dockerのネットワークモードをhostから変更することができません。

と回答がありました。

[対策]

Postfixを使うことは諦め、AWS SESのSDKでメール送信することにしました。

最後に

上記以外にも、AWS BatchはECSインスタンスを起動してからコンテナでジョブを実行するため、一つ目のジョブが実行されるまで5分〜10分かかる、といった特徴があります。

こういったクセを知ったうえで、やりたいことがAWS Batchで実現できるのかを検討するのが良いと思います。

AWS Batchは新しいサービスのせいか、ネットで探しても欲しい情報がなかなか見つかりませんでした。

このブログ記事がお役に立てば幸いです。