ECS Fargate Spotでは、STOPSIGNALを変更できない

こんにちは。 エキサイト株式会社の三浦です。

今回は、ECS Fargate SpotでGraceful Shutdownをしたい時に引っかかる可能性のある、STOPSIGNALに関する注意点を説明します。

ECS Fargate Spotとは

ECS Fargateは、AWSの提供するマネージドなコンテナ実行サービスです。

公式では、以下のように説明されています。

AWS Fargate は、サーバーレスで従量制料金のコンピューティングエンジンであり、サーバーを管理することなくアプリケーションの構築に集中することができます。

そしてECS Fargate Spotは、AWSの空きキャパシティをECS Fargateで使用するプランで、AWS側の都合で停止される可能性がある代わりに、通常に比べて大幅に安い料金となっています。

その料金の安さから、可能であればSpotを使いたいところですが、「AWS側の都合で停止される可能性がある」点を考慮する必要があります。

Graceful Shutdown

AWS側の都合で停止されても問題ないようにするには、停止時にGraceful Shutdownをすれば良いでしょう。


* 2022年8月8日追記

なお、ALBと接続してWebアプリケーション等として使用している場合は、Graceful Shutdownによる対応では問題が起きる場合があります。

詳細は以下にまとめてあります。

tech.excite.co.jp


Graceful Shutdownとは、端的に言えば「安全な停止」のことで、例えばWebサーバで言えば、「停止命令が来てもすべてのアクセスの処理が完了するまでは停止せず、完了後に停止するようにする」などです。

多くのサービスの場合、 SIGTERM というシグナルがコンテナに送られるとGraceful Shutdownが行われます。 また、ECS Fargate Spotも、停止の際はこの SIGTERM が送られるので、基本的には勝手にGraceful Shutdownが行われます。

ただし、たまに例外があります。

有名なところで行くと Nginx で、 Nginx をGraceful Shutdownするには SIGQUIT が必要となり、 SIGTERM では強制停止されてしまうのです。

では、ECS Fargate Spotで停止シグナルを変更するにはどうすれば良いでしょうか?

ECS Fargate Spotでの停止シグナル変更方法は存在しない

2022年5月23日現在、AWSのブログには、以下のような記載があります。

タスクが停止すると、ECS はそのタスク内の各コンテナに停止シグナルを送信します。デフォルトの停止シグナルは SIGTERM ですが、これは Dockerfile に STOPSIGNAL ディレクティブを追加することによってオーバーライドできます。この停止シグナルは、シャットダウンの命令をアプリケーションに通知します。

これに従うなら、Dockerfileに STOPSIGNAL を追記すれば停止シグナルは変更できそうですが、 実際はできません

このブログは日本語訳なのですが、原文の英語版を見てみると、以下のようになっています。

When a task is stopped, ECS sends each container in that task a stop signal. Today, ECS always sends a SIGTERM, but in the future you will be able to override this by adding the STOPSIGNAL directive in your Dockerfile and/or task definition. The stop signal informs your application that it is time to begin shutting down.

まとめると、「現在はECSでは常にSIGTERMが送られるが、 将来的には DockerfileのSTOPSIGNALやtask definitionあたりで変更できるようになる」となっています。

実際はこちらが正しく、現在はECSからは常に SIGTERM が送られてしまうのです。

では、 SIGTERM 以外のシグナルでGraceful Shutdownするアプリケーションでは、どのようにGraceful Shutdownをすればよいのでしょうか。

ECS Fargate Spotで、SIGTERM以外のGraceful Shutdownをする方法

実は、「コンテナが受け取ったシグナルを別のシグナルに変換する」というライブラリが存在します。

github.com

現状では、こういったライブラリを使用して、 SIGTERM を受け取ったら任意のシグナルに変換するようにすると良いでしょう。

そして将来的にAWS側でシグナルの変更に対応したら、そちらに寄せるのが良いかと思います。

最後に

Graceful Shutdownは、直接アプリケーションの動作に関わらないので見過ごされることもあるかもしれませんが、ちゃんと設定しないとユーザ側にエラーを発生させてしまう要因になり得ます。 注意していきましょう。

なお今回は停止シグナルに注目していますが、上記で上げたAWSのブログにも書いてあるとおり、ALBと接続している場合はそちらからの登録解除設定も考える必要があります。 ご注意ください。