Help us understand the problem. What is going on with this article?

KubernetesのPodの削除のときの動作を見る

はじめに

Kubernetesを使ってアプリケーションを公開する場合、Podという形で実行されます。
そのPodの中に複数のContainerが存在し、そのContainerの中でプログラムが実行されます。
Podは一時的なリソース( relatively ephemeral (rather than durable) entities )です。
なので、中に含まれるContainerも一時的なリソースです。

永続的なアプリケーションを提供する場合、一時的なリソースであるいう部分に気を付けなければなりません。
そのアプリケーションの一部のPodが削除されることを想定しなければなりません。
削除された後に再度Podが立ち上がる機能はKubernetesが DeploymentStatefulSetDaemonSet で提供しています。

という訳でPodが削除される際のKubernetes上での処理の流れをPodへの設定値とともに追いかけたいと思います。
なお、その項目に関する公式ドキュメントは Podの終了 にあります。

この記事内で使用するソースコードは、 walk8243/kubernetes-pod-delete にありますので、是非ご利用ください。

全体の流れ

仮にPodの中に3つのContainerが含まれているとします。
そのPodにおいて、Podの削除処理が始まりました。
すると、Podのステータスを Terminating に変更して、Pod内のそれぞれのContainerにおいて preStop で定義されている処理の内容が実行されます。
preStop の処理が完了した後、Containerの実行コマンドに対してシグナルの TERM が送信されます。
このシグナルはNode.jsの場合、 process.on('SIGTERM', () => {}) でイベントとして受け取ることができます。
Pod内の全てのContainerにおいて実行処理が終了したときにPodも終了します。

下の図は、上の説明を図化したものです。
青い枠はPodの削除処理が始まってからの生存期間、緑の枠はContainerの削除処理が始まってからの生存期間を表しています。

全体の流れ.jpg

Pod内のContainerは、Podの削除処理が始まってから terminationGracePeriodSeconds で定義される猶予時間(grace period)の間に実行処理を終了させなけれなりません。
もしContainerが終了しなかった場合は、Containerの実行処理に対して SIGKILL が送信され、強制終了させられることとなります。
但しこれには例外があり、猶予時間が来た時にまだ TERM シグナルを送信されていなかった場合には、 2秒間 の猶予が与えられた上で TERM シグナルが送信されます。

猶予時間の追加.jpg

実際に試してみる

以下の例では、全て猶予時間を 15秒 に設定しています。
また、 SIGTERM を受信してからは 1秒ごと にログを出力するようにしています。

この検証で使用したものは以下です。

preStopの処理時間 ≒ 猶予時間

preStopの処理時間を 15秒 として実行しました。

slack-1.jpg

内部処理の実行速度の関係でログの順序は逆転していますが、 preStopを実行してから15秒後のログと SIGTERM 受信のログはほぼ同時刻に送信されていることが分かります。
また、猶予時間の15秒を経過してからも多少の猶予時間があることが確認できます。

preStopの処理時間 < 猶予時間

preStopの処理時間を 10秒 として実行しました。

slack-2.jpg

preStopを実行してから15秒という時間を待つことなく、preStopの処理が完了後に SIGTERM 受信のログが送信されています。
また、preStopを実行してから15秒後にはログが送信されなくなりました。猶予時間が伸びていないことが確認できます。

preStopの処理時間 > 猶予時間

preStopの処理時間を 20秒 として実行しました。

slack-3.jpg

preStop が実行されてから20秒が経過しました。 というログが送信されてきませんでした。
つまり、その前にPodが強制終了したということです。
また、preStopの処理時間を15秒に設定したときと同様に、preStopが実行されてから15秒後に SIGTERM 受信のログが送信されています。
こちらも15秒以降の猶予時間を確認できました。

おわりに

正常に処理が終了しないまま終わってしまうと、保持しているデータに不整合が起こり、システムエラーを引き起こしたり復旧に時間がかかったり、最悪の場合復旧不可能なんてことになってしまうかもしれません。
安定稼働のためには、常に正常に終了させる状態を作ることが大切です。

正常に終了させる方法として、Podの削除時、Podの猶予時間を延ばすことで各Containerが正常に処理が終了することを待つようにすることはできます。
しかし、むやみに延ばしてしまうと、ローリングアップデートの時間が長くなってしまいます。
それはリリース時に旧バージョンと新バージョンが入り混じった状態が長くなるということです。
また、いくら猶予時間を延ばしても、延ばすことにも限度はあるでしょう。

なので、大切なことは次の3点でしょう。

  • 一連の処理にかかる時間を短くする。
  • 処理の途中にセーブポイントを用意し、処理の途中でも正常に終了できるポイントを作ることを考慮する。
  • 正常に終了するための処理を作成する。

事故の少ない世の中を作るために。

おまけ

TERMシグナルの送信先

TERM シグナルの送信先は常にContainerのコマンドで実行しているプロセスです。
そのため、Node.jsの場合の npmyarn 経由で実行しているような場合には、処理には TERM シグナルが届きません。

以下は猶予時間を15秒、preStopの処理時間を10秒とし、実行コマンドを yarn run start とした場合のログです。

slack-4.jpg

SIGNAL SIGTERM を受信しました。 というログが送信されてきませんでした。
終了処理をTERMシグナルを使って実装しようとしていた場合には注意が必要です。

walk8243
ただの乃木オタです。 業務中に感じた良く分からない気持ち悪さを、形にして解決するにはどうしたらいいかを考えながら記事を書いてます。 執筆は握手会の会場でできるからいいですね!
yahoo-japan-corp
Yahoo! JAPAN を運営しています。
https://www.yahoo.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした