EKS Cluster Autoscalerとログ保存用Daemonsetの組み合わせでスケールイン時にログが失われる問題
EKS Cluster Autoscalerとログ保存用Daemonsetの組み合わせでNodeスケールイン時にログが失われる問題に遭遇した。
前提
- Cluster Autoscaler v1.17.4を使用
- fluent/fluentd-kubernetes-daemonsetを使用して、毎分S3にログを保存
現象
Cluster AutoscalerがNodeをスケールインさせるとき、一部のアプリケーションログがS3に保存されていないことをに気がついた。
まずスケールイン処理が始まるとアプリケーションPodはスケールインするNodeから他のNodeに退避がされる(正確には他のNodeに先にPodを作成しそれからスケールインするNodeにのっているPodはターミネート)。
しかしDaemonSetはターミネート処理がされる前にEC2インスタンスの終了が始まりDaemonSetも強制終了されているようにみえる。
調査
該当するissueがあった
Why not to drain daemonset pods? · Issue #1578 · kubernetes/autoscaler
そして1.20.0で改善が入っていた
Release Cluster Autoscaler 1.20.0 · kubernetes/autoscaler · GitHub
Add best-effort eviction for DaemonSet pods while scaling down non-empty nodes
さっそくCluster Autoscaler 1.20を試す。
すると、スケールイン時にDaemonsetがターミネートされるようになったが、 アプリケーションPodのターミネート処理と同時にDaemonsetのターミネート処理が行われる。
通常、WebアプリケーションPodはpreStop内で新規リクエストが来なくなるまでsleepを入れることが多い。そのためアプリケーションPodの終了処理の前にFluentd Daemonsetが終了してしまうとその間(Fluentd Daemonsetが終了してからアプリケーションPodがリクエスト処理終了するまで)のログが保存されないということが発生する。
じゃあDaemonsetのpreStop内でアプリケーションPodが終了するまでsleepをしてそれからDaemonsetのターミネート処理(fleuntdならバッファのflush)をすればいいのではと考えたがそれもうまくいかない。 なぜなら Cluster AutoscalerはDaemonset以外のPodがすべてターミネートするとNodeの終了処理(EC2インスタンスの終了)を初めてしまうからだ。 そうするとDaemonsetのターミネート処理(fleuntdならバッファのflush)がされなくて結局ログが正常に保存されない。
これらのことから以下の条件を満たす必要がある。
- アプリケーションpodのターミネート処理よりfluentd Daemonsetのターミネート処理は早く終わる必要がある
- アプリケーションpodのリクエスト処理が終わってからfluentd のflush処理を行う
add DaemonSet eviction option for empty nodes by yaroslava-serdiuk · Pull Request #3824 · kubernetes/autoscaler できれいに解決される可能性があるがまだこの修正が含まれたリリースはされていない。リリースされたら再度検証したい。
追記
解決編を書きました