KubernetesでRollingUpdateするためのPodの安全な終了

あけましておめでとうございます、サイオステクノロジー技術部 武井です。本日は元旦です。今年最初のブログは、KubernetesでRollingUpdateするためにPodを安全に終了するために必要な設定を書きます。

Pod終了までのシーケンス

Podが終了するためのシーケンスは以下のようになります。

  1. kubetctlが、Podを終了するためのリクエストをAPI Serverに送信する。
  2. kubeletが、Pod終了のリクエストをAPI Server経由で受け取り、Podの終了処理を開始する。
  3. 「サービスからPodを除外する処理」と「preStop(オプション)+SIGTERMをPodに送信する」という2つの処理を同時に開始する。これらの処理は完全に非同期で行われる
  4. 事前に定義したterminationGracePeriodSeconds秒以内に3の処理が終わらなかった場合、PodにSIGKILLが送信されて、強制的に終了される。

Apacheで安全に停止する場合

これらの特性を考えて、RollingUpdateするためにApacheをgracefulに停止する方法(ユーザーのリクエストを途中で切断することなく安全に停止する)を考えてみます。

まず、先の3で説明したように最終的にはSIGTERMが送信されますが、ApacheはSIGTERMを受け取ると、https://httpsd.apache.org/docs/2.4/en/stopping.htmlに以下に記載されているとおり、ユーザーがリクエストを送受信している途中でもブチッと切られてしまいます。

Sending the TERM or stop signal to the parent causes it to immediately attempt to kill off all of its children. It may take it several seconds to complete killing off its children. Then the parent itself exits. Any requests in progress are terminated, and no further requests are served.

これを防ぐために、preStopを使います。これを使うと、Podを際に任意の処理を定義することが出来ます。このpreStopを使ってApacheをgracefulにシャットダウンします。

その一連の処理を図解すると以下の通りとなります。

Screen Shot 2019-12-30 at 10.28.27

最初にご説明したように、Podは停止のリクエストを受け取ったとき、まずサービスから除外する処理を行います。これによりiptablesの設定が変更されて、該当のPodにリクエストが届かないようになります。

ただし、サービスから除外する処理が終わる前にApacheのgraceful shutdownが始まってしまうと、ユーザーのリクエストが切断されてしまう恐れがあるので、サービスから除外する処理が終わるであろう時間(だいた3秒位)待ちます。

そして、サービス除外の処理によって、停止対象のPodにリクエストが振られなくなるなったら、apachectl –k graceful-stopによって、Apacheをgracefulにシャットダウンします。

そのあと30秒ほど待ちます。Apacheのリクエストタイムアウトの設定が30秒だったと仮定します。Apacheのgraceful shutdownは非同期で行われるので、ここで30秒待たないと、ユーザーのリクエストが終わる前にSIGTERMが送信されて、バチッと切られてしまいます。

terminationGracePeriodSecondsについては、Podの終了処理がこの値で定義した秒数以内に終わらないとSIGKILLが送信されて、これまたバチッと切られてしまいますので、サービス除外の処理(3秒)+ユーザーのリクエストタイムアウト(30秒)=33秒にちょっとプラスアルファして40秒としています。

この設定であればPodは安全に停止しますので、完全なRollingUpdateが実現出来ます。

preStopはマニフェストに以下のように定義しました。

lifecycle:
  preStop:
    exec:
      command: ["sh", "-c", "sleep 3; apachectl -k graceful-stop; sleep 30"]

まとめ

RollingUpdateと一言で言っても、いろいろな設定が必要になります。これ以外にもreadinessProbeなどの設定も必要ですので、KubernetesでRollingUpdateするのはかなり手間ですが、バージョンアップの際にユーザー影響無しで無停止で更新できるRollingUpdateは非常に便利ですので、是非、参考にして頂けたらと思います。

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

3人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です