Kubernetes環境でサーバー自体のスケールイン・アウトを管理する場合、ClusterAutoscaler(以下CA)を使用することがあります。
CAでスケールインするときのDaemonSetの挙動について気をつけないといけないなぁと思ったことがあるので記載します。
- この記事中の想定環境
- Kubernetesプラットフォーム
- AWS EKS
- Ver1.21
- AWS EKS
- ClusterAutoscaler
- Ver1.21.3
- Kubernetesプラットフォーム
DaemonSetを利用する用途として「ログ収集」があります。
アプリケーションのPodがログを標準出力した場合、ホスト上の /var/log/containers/
にログが出力されます。
DaemonSetを利用し、自ホスト上のログをFluentdなど使用しログ収集先に転送する、といったようなことをするためです。
このような用途でDaemonSetを使用する場合、Nodeを削除する際にDaemonSet管理下のPodはDaemonSet以外のPodよりも早く消えてはいけません。
なぜならNodeの削除する際はDrainを行いPodの排出を行いますが、その際もログは吐き続けているからです。
仮にアプリケーションのPodよりも先にDaemonSetのFluentdのPodが先に消えてしまうと、それ以降に出力したログを収集できません。
ではCAでスケールインする場合はどういう挙動になるのでしょうか?
ということで検証してみます。
CAでのスケールイン時のDaemonSetのデフォルトの挙動の検証
以下のようなPodがいる状態です。
$ kubectl get po -A -o jsonpath='{.items}' | jq -c '.[] | [.metadata.name,.status.phase]'
["aws-node-gccws","Running"]
["kube-proxy-q7v7h","Running"]
["daemonset-fluentd-cwzb2","Running"]
["deployment-app-6d4b447dfb-7zhgt","Running"]
見てわかるようにDaemonSetのFluentdのPodとDeploymentのアプリケーションPodを想定したものです。
アプリケーションPodには spec.containers.lifecycle.preStop
に sleep 15
を仕込んでおり、Podを終了してもすぐには消えないようにしてあります。
この状態でCAがスケールインをすると・・・
$ kubectl get po -A -o jsonpath='{.items}' | jq -c '.[] | [.metadata.name,.status.phase]'
["aws-node-gccws","Running"]
["kube-proxy-q7v7h","Running"]
["deployment-app-6d4b447dfb-7zhgt","Running"]
DaemonSetのFluentdのPodがまず消えてしまいました。
これではアプリケーションPodが出力しているログを収集できません。
なぜDaemonSetのPodが先に消えてしまうのか?
CAのデフォルト設定を眺めてみると以下の設定がありました。
option name | default | description |
---|---|---|
daemonset-eviction-for-empty-nodes | false | Whether DaemonSet pods will be gracefully terminated from empty nodes |
daemonset-eviction-for-occupied-nodes | true | Whether DaemonSet pods will be gracefully terminated from non-empty nodes |
どうやら non-empty nodes
に対してDaemonSetのPodを排出するような設定がデフォルトのようです。
このオプションを変更することにより、DaemonSetのPodを消さないようにできそうです。
※このオプションが使用できるのはCAのバージョン v1.21.3
以降です。
デフォルトの挙動を変更して実行
--daemonset-eviction-for-occupied-nodes=false
をCAの引数に追加します。
その後検証用Podを以下のように立ち上げて
$ kubectl get po -A -o jsonpath='{.items}' | jq -c '.[] | [.metadata.name,.status.phase]'
["aws-node-s2bdl","Running"]
["kube-proxy-wtfhh","Running"]
["daemonset-fluentd-9zbl4","Running"]
["deployment-app-6d4b447dfb-2q7f4","Running"]
この状態でCAでスケールインすると・・・
$ kubectl get po -A -o jsonpath='{.items}' | jq -c '.[] | [.metadata.name,.status.phase]'
["aws-node-s2bdl","Running"]
["kube-proxy-wtfhh","Running"]
["daemonset-fluentd-9zbl4","Running"]
DaemonSetのPodはDeploymentのPodよりも長く生存しています!
ということで、スケールイン時にPodがどのように消えていくのかは注意する必要があります。