Podをスケールインしたりローリングアップデートする場合に、終了するPodへのリクエストを受け付けないようにして、実行中の処理をGraceful Shutdownしたいケースがあると思います。
今回は自分が担当した案件の中でSidekiqをKubernetesで導入した際に、
コンテナのライフサイクルの挙動を制御するhookとして用意されているPreStopを用いて、安全にPodをterminateした際の備忘録を残しておきます。
また今回はSidekiqをGracefulに扱いたい場合のケースなので、
その他はそれぞれドキュメントを参照しつつ、安全な停止方法を模索する必要があります。
前提
- Kubernetes 1.21 on EKS
- Ruby 2.7.2
- Rails 6.0.4.4
- Sidekiq 6.4.0
Container hooksとは
コンテナの起動・終了時点で任意の処理が実行できます。
二種類のhookが存在します。
hooks
k | v |
---|---|
PostStart | コンテナ起動後に任意の処理を実行できる |
PreStop | コンテナ終了前に任意の処理を実行できる |
参考
https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks
implementations
Exec
# 省略
lifecycle:
preStop:
exec:
command: [
"/bin/sh",
"-c",
"echo HELLO"
]
HTTP
# 省略
lifecycle:
preStop:
httpGet:
scheme: HTTP
port: 80
path: "/hoge"
注意点
- PostStartの場合hookの時間がかかりすぎるとPodが起動しないので軽量な処理にするべき。
- PreStopの場合terminationGracePeriodSecondsを過ぎると時間切れで強制終了する。
参考
https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/
sidekiq6をGraceful Shutdownする方法
Sidekiq < 6
$ bundle exec sidekiqctl stop
Sidekiq >= 6
$ kill -SIGTSTP ${sidekiqのPID}
今回はsidekiq6を利用しているので、後者になります。
参考
https://github.com/arturictus/sidekiq_alive
https://github.com/arturictus/sidekiq_alive/issues/47
PreStopでkillコマンドを実行
Execを用いて、先ほど調べたコマンドをそのまま実行しました。
# 省略
lifecycle:
preStop:
exec:
command:
[
"/bin/bash",
"-c",
"SIDEKIQ_PID=$(ps aux | grep sidekiq | grep busy | awk '{ print $2 }'); kill -SIGTSTP $SIDEKIQ_PID",
]
Podをリスタートして挙動を確認
$ k rollout restart deployments/xxx
#sidekiqが起動した
2022-02-21T10:43:40.213Z pid=14 tid=8ui DEBUG: {:queues=>["default"] #略}
# PreStopの処理
# TSTP signalを受信し、Graceful Shutdownしていることを確認
2022-02-21T10:47:56.512Z pid=14 tid=8ui DEBUG: Got TSTP signal
2022-02-21T10:47:56.512Z pid=14 tid=8ui INFO: Received TSTP, no longer accepting new work
2022-02-21T10:47:56.512Z pid=14 tid=8ui INFO: Terminating quiet workers
2022-02-21T10:47:56.513Z pid=14 tid=vtu INFO: Scheduler exiting...