Blog
[Kubernetes] node-problem-detector で node の監視をしてみる
みなさんこんにちは。
アドテク本部の makocchi です。
この記事は Kubernetes Advent Calendar 2 の 5日目の記事になります。
Kubernetes には addon の機能がいくつかありますが、その中でも今日は node-problem-detector について紹介したいと思います。
node-problem-detector とは
Kubernetes の node 側では kubelet を動かすことになると思いますが node の状態をある程度 monitor してくれます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
$ kubectl get node node-name -o json | jq .status.conditions [ { "lastHeartbeatTime": "2017-11-24T13:14:05Z", "lastTransitionTime": "2017-11-24T13:08:32Z", "message": "kubelet has sufficient disk space available", "reason": "KubeletHasSufficientDisk", "status": "False", "type": "OutOfDisk" }, { "lastHeartbeatTime": "2017-11-24T13:14:05Z", "lastTransitionTime": "2017-11-24T13:08:32Z", "message": "kubelet has sufficient memory available", "reason": "KubeletHasSufficientMemory", "status": "False", "type": "MemoryPressure" }, { "lastHeartbeatTime": "2017-11-24T13:14:05Z", "lastTransitionTime": "2017-11-24T13:08:32Z", "message": "kubelet has no disk pressure", "reason": "KubeletHasNoDiskPressure", "status": "False", "type": "DiskPressure" }, { "lastHeartbeatTime": "2017-11-24T13:14:05Z", "lastTransitionTime": "2017-11-24T13:08:32Z", "message": "kubelet is posting ready status", "reason": "KubeletReady", "status": "True", "type": "Ready" } ] |
デフォルトだと disk や memory の状態を monitor してくれます。
しかし時と場合によっては、disk や memory の状態だけではなくて例えば runtime に Docker を使っていた場合に dockerd が固まっていたりしたら kubelet 的にはコンテナの配置を防いでほしいですよね。
そこで役に立つのが node-problem-detector というわけです。
node-problem-detector は特定の log を watch してくれて、特定の文字列が出てきた場合に node の condition を更新してくれます。
node-problem-detector の導入方法
先程紹介した addon の repository に manifest があるのでそれを使うのが一番楽です。
1 |
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/node-problem-detector/npd.yaml |
この manifest は設定内容が単純な文字列しか登録されていませんので、実際の運用に入れる場合にはもう少し config をいじる必要があるでしょう。
config は json 形式で記述します。特に何も考えずに起動させた場合、予め image に入っている config が使われます。
予め入っている config はこちらから確認することができます。
config で指定することができる plugin の type は journald / filelog / kmsg を指定することができます。
journald の log を watch させる場合には journald の log を persistent にしておくといいでしょう。
(/etc/systemd/journald.conf に Storage=persistent を書いて systemctl restart systemd-journald して下さい)
kmsg の場合は kernel が出す log を watch することができます。いわゆる dmesg ですね。
config をカスタマイズしたい場合は config を configmap で渡してあげるといいでしょう。
configmap で定義して pod 側で mount して、起動時の option で configmap の config を見るように変更してください。
起動時の option は
1 2 3 4 5 |
command: - "/bin/sh" - "-c" # Pass both config to support both journald and syslog. - "/node-problem-detector --logtostderr --system-log-monitors=/config/kernel-monitor.json,/config/docker-monitor.json,/config/kmsg-monitor.json" |
このように定義されていますので –system-log-monitors の部分を適宜変えて下さい。例えば configmap を定義して /configmap に mount したならば
1 2 3 4 5 |
command: - "/bin/sh" - "-c" # Pass both config to support both journald and syslog. - "/node-problem-detector --logtostderr --system-log-monitors=/configmap/original.json" |
こんな感じになると思います。
もちろん元々配置されている config に追加してもいいし、configmap を /config に mount して入れ替えてしまってもいいと思います。
node-problem-detector が起動すると、config で定義された condition が追加されていることが確認できます。
1 2 3 4 5 6 7 8 9 10 11 12 |
$ kubectl get node node-name -o json | jq .status.conditions [ { "lastHeartbeatTime": "2017-11-24T13:48:07Z", "lastTransitionTime": "2017-11-24T13:25:54Z", "message": "kernel has no deadlock", "reason": "KernelHasNoDeadlock", "status": "False", "type": "KernelDeadlock" }, .... ] |
KernelDeadlock という condition が追加されました。
実際に検知させてみる
それでは実際に検知するとどうなるのでしょうか。
今回は下記の config を読ませて実験してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
{ "plugin": "kmsg", "pluginConfig": { "timestamp": "^.{15}", "message": "\\[.*\\] (.*)", "timestampFormat": "Jan _2 15:04:05" }, "lookback": "5m", "bufferSize": 10, "source": "kmsg-monitor", "conditions": [ { "type": "KernelDeadlock", "reason": "KernelHasNoDeadlock", "message": "kernel has no deadlock" } ], "rules": [ { "type": "temporary", "reason": "KernelOops", "pattern": "BUG: unable to handle kernel NULL pointer dereference at .*" }, { "type": "permanent", "condition": "KernelDeadlock", "reason": "TaskHung", "pattern": "task \\S+:\\w+ blocked for more than \\w+ seconds\\." } ] } |
本当ならば kernel にいろいろ log を出させてみたいところですが、今回はちょっと擬似的に log を出力させることにします。
さっそく node 側で /dev/kmsg に対して書き込みをしてみましょう。
1 2 3 4 5 6 |
$ echo "BUG: unable to handle kernel NULL pointer dereference at hogehoge" | sudo tee -a /dev/kmsg BUG: unable to handle kernel NULL pointer dereference at hogehoge 実際に dmesg を確認 $ dmesg | tail -1 [ 3266.441916] BUG: unable to handle kernel NULL pointer dereference at hogehoge |
node 側を describe してみます。
1 2 3 4 5 6 7 |
$ kubectl describe node node-name ... ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning KernelOops 1m kmsg-monitor, node-name BUG: unable to handle kernel NULL pointer dereference at hogehoge |
Event のところに出てきましたね。
しかし node の condition の KernelDeadlock のところはまだ False になっていると思います。
それは先程の config で KernelOops の rule は type が temporary と定義しているからで、一時的なものとして記録されるようです。
それでは type が permanent になっている TaskHung を発生させてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
$ echo "task hoge:hoge blocked for more than 120 seconds." | sudo tee -a /dev/kmsg task hoge:hoge blocked for more than 120 seconds. $ kubectl describe node node-name ... ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning KernelOops 11m kmsg-monitor, node-name BUG: unable to handle kernel NULL pointer dereference at hogehoge Warning TaskHung 1m kmsg-monitor, node-name task hoge:hoge blocked for more than 120 seconds. $ kubectl get node node-name -o json | jq .status.conditions [ { "lastHeartbeatTime": "2017-11-24T14:22:15Z", "lastTransitionTime": "2017-11-24T14:20:13Z", "message": "task hoge:hoge blocked for more than 120 seconds.", "reason": "TaskHung", "status": "True", "type": "KernelDeadlock" }, .... ] |
KernelDeadlock の status が True になりました。
が・・ KubeletReady の status は True のままでした。こちらの status までは変えてくれないようです。
まとめ
今回は node-problem-detector の挙動を検証してみました。
実際に kernel が出す error を検知して node の condition を変更するのはとても便利なのですが、まだ機能的に足りていない点もありそうです。
- log 等の出力結果を watch することでしか検知することが出来ない
- 一度 condition(上記の例だと KernelDeadlock) が True になると元に戻せ無さそう
- その node の node-problem-detector の pod を kill して再作成させると False に戻る
log 等の出力結果しか watch できない点についてはつい最近 custom plugin が実装されたようです。
この custom plugin を使えば shell の実行結果を watch することができるようです。
(こちらの例では ntp の状態を監視しています)
この custom plugin によって一気に config の幅が広がりますね。
condition が戻らない件については戻ってしまっては困るケースもあると思います。
ですので問題が発生した node は捨てて再作成するというポリシーで運用することができればそれほど問題にならないと思いました。
自動で drain までやってくれるとすごくいいんですけどもね。
今回は node-problem-detector を紹介させて頂きました。
node-problem-detector を上手く動かして快適な Kubernetes Life を送って下さい!
Author