Cloud Run での正常なシャットダウンに関する詳細情報
Google Cloud Japan Team
※この投稿は米国時間 2020 年 10 月 20 日に、Google Cloud blog に投稿されたものの抄訳です。
Cloud Run は、スケールダウンやリビジョンの削除などのイベントによってコンテナ インスタンスが終了される前に、SIGTERM シグナルをコンテナ インスタンスに送信するようになりました。このシグナルを扱うことで、コンテナの急激なシャットダウンを避け、アプリケーションを正常に終了してクリーンアップ タスクを実行できるようになりました。
このブログでは、いくつかのユースケースとそれらを試す方法について説明します。
正常なシャットダウン
Cloud Run でコンテナ インスタンスがシャットダウンされる際、SIGTERM シグナルがコンテナに送信され、アプリケーションを終了するために 10 秒 が与えられます。コンテナがそれまでに終了しない場合、SIGKILL シグナル(キャプチャはできません)が送信され、アプリケーションは緊急に終了します。SIGTERM にシグナル ハンドラを書き込まない場合は、プロセスは直ちに終了します。
この終了シグナルを使用すると、アプリケーション コードでさまざまな「正常なシャットダウン」タスクを実行できます。
- モニタリング データをフラッシュする: Cloud Trace を使用するか、アプリケーションから指標をアップロードすると、シグナル ハンドラを開発し、アップロードされなかったメモリ内のトレーススパンがコンテナの終了に伴い消去される前に、収集されたトレーススパンをフラッシュする関数を呼び出すことができます。
- コンテナの終了をロギングする: コンテナの終了イベントをロギングすることで、アプリケーション ログを参照して、特定のコンテナ インスタンスの開始と終了の日時を確認し、個別のコンテナ インスタンスのライフサイクル全体を可視化できます。
- ファイル ディスクリプタまたはデータベース接続を終了する: 急な接続の終了は、接続されていたサーバーの稼働を乱し、正常に接続解除した場合よりも長時間にわたって接続が開いたままになる場合があります。
正常な終了シグナルは主に、トラフィックを取り込んでいないコンテナ インスタンスをアプリケーションがスケールダウンしている場合に、アプリケーションに送付されます。したがって、シグナル ハンドラ内の処理中リクエストのドレインに対処する必要はありません。ただし、基盤となるインフラストラクチャが原因で、コンテナがシャットダウンされる前にこのシグナルを受信し、コンテナに処理中の接続が残る場合があります。このように、正常な終了は常に保証されるわけではありません。
シグナルをトラップする正しい方法
大半のプログラミング言語は、SIGTERM のような終了シグナルをトラップし、プログラムが終了する前にルーティンを実行するライブラリを備えています。
アプリケーションが Cloud Run 上で終了シグナルを受信しない場合によく見られる原因として、アプリケーションが init プロセス(PID 1)として実行されておらず、その親プロセスがシグナルを適切に転送していないことが挙げられます。
このような現象が発生する主な理由は、コンテナ イメージの Dockerfile 内の ENTRYPOINT ステートメントがアプリケーション プロセスに直接設定されていないことです。たとえば、次のような Dockerfile ステートメントです。
ENTRYPOINT node server.js
は、コンテナ イメージを構築するために Dockerfile が実行される場合、
ENTRYPOINT ["/bin/sh", "-c", "node server.js"]
と内部的に変換されます。
代表的には、GNU /bin/sh と bash などのシェルは、デフォルトでは、シグナルを子プロセスに転送しません。したがって、次のような vector 形式の ENTRYPOINT ステートメントを書き込んで、アプリがシェルのサブプロセスとして実行されることを防止する必要があります。
ENTRYPOINT ["node", "server.js"]
同様に、コンテナでバックグラウンド プロセスを開始するエントリポイント スクリプトを使用する場合、tini、dumb-init、supervisord など、シグナルを子プロセスに転送できる適切な init プロセスの使用を検討してください。(マルチプロセス コンテナ ユースケース用の init プロセスの選択肢をこちらで比較しています。)
動作中の正常なシャットダウンを確認する
Cloud Run で SIGTERM シグナルのトラップを試行するには、小規模の Node.js サーバーアプリを使用してください。この目的には、Cloud Run 用の Node.js サンプル アプリケーション を使用します。これは、GitHub にあるこちらのリポジトリからダウンロードできます。
次のコードのスニペットを index.js に追加します。
process.on('SIGTERM', function () {
console.log('helloworld: received SIGTERM, exiting gracefully');
process.exit(0);
});
このステップが完了すると、このコンテナ イメージの構築と push、および Cloud Run へのデプロイができるようになります。新しいデプロイの一部として、リクエストの処理のためコンテナ インスタンスが起動します。
しばらくすると、リクエストを取得していないため、コンテナはゼロへのスケーリングを実施します(ゼロへのスケーリング イベントをトリガーする場合、Google Cloud Console で CPU やメモリなど Cloud Run アプリケーションの設定を編集することもできます。これにより、新しいバージョンがデプロイされ、古いバージョンは無効になります)。
ゼロへのスケーリングは、シャットダウンされる前のコンテナへの SIGTERM シグナル送信をトリガーします。実行された正常なシャットダウン ルーティンは [ログ] タブで確認できます。
このように、Cloud Run では、正常なシャットダウンを有効にするために追加の設定は必要ありません。デフォルトで、すべての Cloud Run サービスで有効になっています。
まとめ
Cloud Run 上のサーバーレス コンテナ インスタンスがシャットダウンされる前に、クリーンアップ タスクや push 配布するモニタリング データがある場合は、終了シグナルの使用を試してみてください。この機能の詳細については、ドキュメントをご覧ください。
-シニア デベロッパー アドボケイト Ahmet Alp Balkan