Docker コンテナの適切な停止方法

DockerBeginner
オンラインで実践に進む

はじめに

Docker コンテナは、現代のソフトウェア開発とデプロイにおいて不可欠な要素となっています。これらのコンテナを適切に停止させることは、信頼性を維持し、データ損失を防ぎ、スムーズなアプリケーションライフサイクルを確保するために非常に重要です。このチュートリアルでは、Docker コンテナのライフサイクルを理解し、優雅なコンテナ停止を実装し、様々な停止シナリオを処理して、コンテナ管理を最適化する方法を説明します。

Docker コンテナのライフサイクル理解

Docker コンテナは軽量、移植性があり、スケーラブルな設計となっています。アプリケーションを実行するための一貫した隔離された環境を提供し、ソフトウェアの開発、デプロイ、管理を容易にします。しかし、Docker コンテナのライフサイクルを理解することは、適切な停止と実行中のプロセスの優雅な終了を保証するために不可欠です。

Docker コンテナのライフサイクル

Docker コンテナのライフサイクルは、以下の段階に分けられます。

  1. 作成 (Creation): Docker コンテナは、コンテナのテンプレートとなる Docker イメージから作成されます。
  2. 実行 (Running): コンテナが起動し、イメージ内に指定されたメインプロセスが実行を開始します。
  3. 一時停止 (Pausing): コンテナを一時停止させることができ、メインプロセスを一時停止しながらコンテナの状態を保持できます。
  4. 停止 (Stopping): コンテナが停止し、メインプロセスに SIGTERM シグナルが送信されます。これにより、プロセスは優雅にシャットダウンできます。
  5. 再起動 (Restarting): 停止したコンテナを再起動すると、メインプロセスの実行が再開されます。
  6. 削除 (Removing): コンテナを削除すると、システムから完全に削除されます。
graph LR
    A[作成] --> B[実行]
    B --> C[一時停止]
    B --> D[停止]
    D --> B[再起動]
    B --> E[削除]

コンテナ停止の処理

Docker コンテナが停止すると、コンテナ内で実行されているメインプロセスに SIGTERM シグナルが送信されます。これは、優雅なシャットダウンを要求するために使用されるデフォルトのシグナルです。プロセスは、データの保存、接続のクローズ、リソースの解放など、必要なクリーンアップタスクを実行してから終了する必要があります。

メインプロセスが指定されたタイムアウト(デフォルトは 10 秒)内に終了しない場合、Docker は SIGKILL シグナルを送信し、プロセスを強制終了します。プロセスが適切にクリーンアップできなかった場合、データ損失やその他の問題が発生する可能性があります。

適切なシャットダウンを保証するために、アプリケーションは SIGTERM シグナルを処理し、優雅なシャットダウンを実行するように設計することが重要です。これは、アプリケーションコードにシグナルハンドラを実装するか、tinidumb-init などのプロセスマネージャを使用して、メインプロセスに代わってシグナルを処理することで実現できます。

## Docker コンテナのエントリポイントとして tini を使用する場合の例
ENTRYPOINT ["/usr/bin/tini", "--", "your-application-command"]

Docker コンテナのライフサイクルを理解し、シャットダウンプロセスを適切に処理することで、Docker コンテナ内で実行されているアプリケーションを安全に停止および再起動し、データの損失やその他の問題を回避できます。

優雅なコンテナ停止

Docker コンテナの優雅な停止は、アプリケーションの整合性と管理するデータの保全に不可欠です。コンテナが停止すると、コンテナ内で実行されているメインプロセスは、データの保存、接続のクローズ、リソースの解放など、必要なクリーンアップタスクを実行する機会を与えられるべきです。

SIGTERM シグナルの処理

デフォルトでは、Docker コンテナが停止すると、コンテナ内で実行されているメインプロセスに SIGTERM シグナルが送信されます。このシグナルは、プロセスの優雅な停止を要求するために使用されます。適切な停止を保証するために、アプリケーションは SIGTERM シグナルを処理し、終了する前に必要なクリーンアップタスクを実行するように設計する必要があります。

Python アプリケーションで SIGTERM シグナルをどのように処理できるかの例を次に示します。

import signal
import time

def graceful_shutdown(signum, frame):
    print("SIGTERM を受信しました。優雅な停止を実行しています...")
    ## ここでクリーンアップタスクを実行
    time.sleep(5)  ## クリーンアップタスクのシミュレーション
    print("優雅な停止が完了しました。")
    exit(0)

signal.signal(signal.SIGTERM, graceful_shutdown)

## メインアプリケーションロジック
while True:
    print("アプリケーションが実行中です...")
    time.sleep(1)

この例では、graceful_shutdown 関数が SIGTERM シグナルのハンドラとして登録されています。コンテナが停止すると、この関数が呼び出され、アプリケーションは終了する前に必要なクリーンアップタスクを実行できます。

停止タイムアウトのカスタマイズ

デフォルトでは、Docker は SIGTERM シグナルを受信した後、メインプロセスが終了するのを 10 秒間待機します。このタイムアウト内にプロセスが終了しない場合、Docker は SIGKILL シグナルを送信し、プロセスを強制終了します。

Docker コンテナを起動するときに --stop-timeout フラグを使用して、停止タイムアウトをカスタマイズできます。

docker run -d --stop-timeout 20 your-image

これにより、停止タイムアウトが 20 秒に増加し、メインプロセスに優雅な停止を実行するための時間が長くなります。

プロセスマネージャの使用

優雅な停止を保証する別の方法は、プロセスマネージャ(tinidumb-init など)をコンテナのエントリポイントとして使用することです。これらのプロセスマネージャは、シグナルを処理し、メインプロセスに転送するように設計されており、適切な停止シーケンスを保証します。

## Docker コンテナのエントリポイントとして tini を使用する場合の例
ENTRYPOINT ["/usr/bin/tini", "--", "your-application-command"]

プロセスマネージャを使用すると、アプリケーションのシグナル処理を簡素化し、プロセスマネージャに停止処理を代行させることができます。

優雅な停止メカニズムを理解し、実装することで、Docker コンテナを安全に停止および再起動し、データの損失やその他の問題を回避できます。

停止シナリオの処理

Docker コンテナを使用する際に、さまざまな停止シナリオが発生し、それぞれ異なる対応が必要になります。これらのシナリオと対処方法を理解することは、アプリケーションの信頼性と安定性を確保するために不可欠です。

優雅な停止

前のセクションで説明したように、Docker コンテナを停止する推奨される方法は、SIGTERM シグナルを処理し、優雅な停止を実行することです。これにより、メインプロセスはリソースのクリーンアップ、データの保存、制御された終了を実行できます。

強制停止 (SIGKILL)

メインプロセスが指定された停止タイムアウト(デフォルトは 10 秒)内に終了しない場合、Docker は SIGKILL シグナルを送信し、プロセスを強制終了します。プロセスが適切にクリーンアップできなかった場合、データ損失やその他の問題が発生する可能性があります。

このシナリオに対処するには、以下の方法があります。

  1. コンテナ起動時に --stop-timeout フラグを使用して停止タイムアウトを増加させる。
  2. アプリケーションが割り当てられた時間内に SIGTERM シグナルを処理し、優雅な停止を実行するように設計されていることを確認する。
  3. tinidumb-init などのプロセスマネージャを使用して、アプリケーションに代わってシグナル転送と停止処理を行う。

コンテナの再起動ポリシー

Docker は、コンテナが停止したときにどのように動作するかを決定するさまざまな再起動ポリシーを提供します。これらのポリシーは、コンテナ起動時に --restart フラグを使用して設定できます。一般的な再起動ポリシーには以下があります。

  • no: コンテナは自動的に再起動されません。
  • always: コンテナは、終了ステータスに関わらず常に再起動されます。
  • on-failure: コンテナは、終了ステータスがゼロ以外の場合にのみ再起動されます。
  • unless-stopped: コンテナは、明示的に停止された場合(例:docker stop を使用した場合)を除き、再起動されます。

適切な再起動ポリシーを選択することで、アプリケーションが利用可能であり、予期しない停止や障害に耐性があるようにすることができます。

## 再起動ポリシーの設定例
docker run -d --restart=on-failure:5 your-image

この例では、コンテナは終了ステータスがゼロ以外の場合、最大 5 回再起動されます。

さまざまな停止シナリオを理解し、適切に処理することで、Docker コンテナを安全に停止および再起動し、データ損失やその他の問題のリスクを最小限に抑えることができます。

まとめ

このチュートリアルでは、Docker コンテナの適切な停止方法を学びました。コンテナのライフサイクルを理解し、優雅な停止テクニックを実装し、さまざまな停止シナリオに対処することで、コンテナ管理を最適化し、信頼性、稼働時間、そして全体的なアプリケーションの安定性を向上させることができます。これらのベストプラクティスを適用することで、堅牢で回復力のある Docker ベースのインフラストラクチャを維持できます。