TT Lab
はじめる
学ぶ 学習パス コース

Docker基礎

生成・起動・終了と終了コード

TT Labで続きを見る

このラボは本物のVM上で動きます

この環境はPodではなく、KubeVirtが起動した仮想マシンです。Linuxカーネルが別に動き、systemdが実際にサービスを管理し、dockerは模倣ではなく本物のDockerエンジンです。docker runで起動したコンテナは実際にプロセスになり、docker execもdocker logsもそのまま動作します。

以前はこのラボがPodの中で動いていました。カーネル権限をすべて落とした環境だったため、コンテナを起動するステップが塞がれており、イメージアーカイブを自分で展開してみるという回り道で学んでいました。もう回り道は必要ありません。

知っておくべきことが2つあります。

目標

コンテナの状態遷移を手で作り出し、終了コード143・137・42をそれぞれ意図的に再現して、その意味を体で覚えます。

なぜ重要なのか

運用で最も多く受ける報告は、「コンテナが落ちました」です。しかし、落ち方は少なくとも3種類あり、それぞれ対処がまったく違います。アプリが自分で終了したならコードを見る必要があり、SIGTERMを受けて終了したなら正常なデプロイであり、SIGKILLで落ちたならアプリのログには何も残りません。終了コードは、この3つを区別する最も安価なシグナルです。128を超える値は128 + 신호번호(プレースホルダーはシグナル番号です)というルールさえ知っていれば、143 = 128+15 = SIGTERM、137 = 128+9 = SIGKILLとすぐに読み取れます。

ステップ

  1. /root/dk2を作成し、alpine:3.20でdk-lifeというコンテナを作成だけします。コマンドはsleep 600です。
  2. dk-lifeを起動して、running状態にします。
  3. alpine:3.20でdk-trapをバックグラウンド実行します。SIGTERMを受けたらcaught-termを出力し、終了コード143で終わるようにします。そのあと、正常に停止させます。
  4. alpine:3.20でdk-notrapをバックグラウンド実行し(コマンドはsleep 600)、猶予時間を2秒だけ与えて停止させます。終了コードが137になる必要があります。
  5. alpine:3.20でdk-failを実行して終了コード42で終わらせ、その値を/root/dk2/exit42.txtに数字だけで書きます。
  6. dk-restartコンテナを、再起動ポリシーon-failure、最大3回で起動します。
  7. コンテナ内でプロセス一覧を取得し、/root/dk2/pid1.txtに保存します。PIDの列が一緒に見える必要があります。 このラボの環境自体がコンテナです。ここでps -e -o pid,ppid,commを実行すると、PID 1がこのコンテナのメインコマンドであることと、見えるプロセスが片手で数えられるほど少ないことを、同時に確認できます。
  8. /root/dk2/lifecycle.mdに、dk-trap、dk-notrap、dk-failの3つのコンテナの名前と終了コードを、1行に1つずつ書きます。

参考

実行せずに作成だけする

/root/dk2を作成し、alpine:3.20でdk-lifeというコンテナを作成だけします。コマンドはsleep 600です。

runは作成してすぐに起動します。作成だけを行う別のサブコマンドがあります。この状態では、まだプロセスはありません。

作成済みのコンテナを起動する

dk-lifeを起動して、running状態にします。

作成と起動が分かれている理由を考えてみてください。起動すると、State.Pidに実際のプロセス番号が入ります。

SIGTERMを受けて正常終了する

alpine:3.20でdk-trapをバックグラウンド実行します。SIGTERMを受けたらcaught-termを出力し、終了コード143で終わるようにします。そのあと、正常に停止させます。

シェルには、シグナルハンドラーを登録する組み込みコマンドがあります。ハンドラーの中で目的の終了コードを指定して終了すると、その値がそのままコンテナの終了コードになります。

ハンドラーがないと何が起きるか

alpine:3.20でdk-notrapをバックグラウンド実行し(コマンドはsleep 600)、猶予時間を2秒だけ与えて停止させます。終了コードが137になる必要があります。

ハンドラーを登録していないPID 1は、SIGTERMを無視します。猶予時間を短くすると、待たずに結果を確認できます。

アプリケーションが出した終了コード

alpine:3.20でdk-failを実行して終了コード42で終わらせ、その値を/root/dk2/exit42.txtに数字だけで書きます。

シグナルで死んだ場合と、アプリが自分で終了した場合とでは、終了コードの範囲が違います。128より小さい値は、アプリが直接出した値です。

失敗したときだけ再起動する

dk-restartコンテナを、再起動ポリシーon-failure、最大3回で起動します。

再起動ポリシーは4種類あります。失敗した場合だけ、しかも回数を制限して再起動する値を選んでください。

コンテナ内のプロセス一覧

コンテナ内でプロセス一覧を取得し、/root/dk2/pid1.txtに保存します。PIDの列が一緒に見える必要があります。 このラボの環境自体がコンテナです。ここでps -e -o pid,ppid,commを実行すると、PID 1がこのコンテナのメインコマンドであることと、見えるプロセスが片手で数えられるほど少ないことを、同時に確認できます。

コンテナ内でプロセスを一覧表示すると、リストがとても短く、PID 1が何かがすぐにわかります。ホストで実行してはいけません。

終了コードの表を作る

/root/dk2/lifecycle.mdに、dk-trap、dk-notrap、dk-failの3つのコンテナの名前と終了コードを、1行に1つずつ書きます。

3つのコンテナの終了コードを実際のinspectで確認し、表に書いてください。それぞれの値がなぜその値なのかも併せて書いておくと、あとで役に立ちます。