Kubernetes クラスタのトラブルシュートで、ssh でノードに直接アクセスしてデバッグしたい場面があります。しかし、OS アカウントやネットワーク管理の都合で、ssh の利用が難しい場合があります。そんなとき、 kubectl debug node
を利用すると、ssh に相当する操作をkubectl
で簡単に行えます。
デモ
kubectl debug node
でノードに Pod を作成し、ホスト上のコマンド(systemctl
, htop
) を実行したデモです。
kubectl debug node の使い方
kubectl debug pod
(Ephemeral Containers) と違い、kubectl debug node
は特権を持った Pod を作成しているだけなので、権限さえあれば Kubernetes クラスタ側の設定は不要です。
使い方は非常にシンプルで、ノード名と利用するコンテナイメージを指定するだけです。kubectl exec
のように -it
を指定すると、インタラクティブに操作できます。なお実行には、クラスタの管理者権限 (RBAC の cluster-admin
相当) が必要になります。
以下は busybox イメージを指定した例です。後述のように chroot でホストのコマンド(シェル)を利用する場合は、busybox など軽量なイメージがおすすめです。
$ kubectl debug node/<NODE_NAME> -it --image=busybox
上記を実行後、kubectl exec
のように Pod のシェルをそのまま操作できるようになります。/host
以下にノードのルートディレクトリがマウントされているため、ノード上のファイルシステム全てにアクセスできます。
root@<NODE_NAME>:/# ls /host
# ノードのルートディレクトリが表示される
bin initrd.img media run tmp
boot initrd.img.old mnt sbin usr
dev lib opt snap var
etc lib64 proc srv vmlinuz
home lost+found root sys vmlinuz.old
デバッグ用に作成される Pod は、以下の権限を持っています。これは、多くの環境でノードの root に相当する権限を持った Pod であるため、扱いは十分に注意しましょう。
- HostPath: ホストのルートディレクトリを、Pod の
/host
にマウントしている - HostPID: ホストのプロセス空間を利用。
ps
などで直接プロセスが見れる - HostIPC: ホストの IPC 名前空間を使用
- HostNetwork: ホストのネットワークを利用
ただし、privileged
は指定されていないため、特別な Linux Capabilities が必要なコマンドは動かない場合があります。(後述)
終了後、この Pod は手動で削除する必要があります。Kubernetes 1.21 時点では、終了時に Pod を削除する --rm
のようなオプションは存在していません。
chroot でホストのコマンドを使う
デバッグ用 Pod のシェルからホストのコマンドをそのまま実行すると、共有ライブラリなどパスの問題でエラーが出て実行できない場合があります。
# /host/bin/systemctl status
/host/bin/systemctl: error while loading shared libraries: libsystemd-shared-237.so: cannot open shared object file: No such file or directory
Pod のシェル内で、/host
に chroot
し、/
をホストのルートディレクトリにすると正常に動くようになります。
# chroot /host
コマンドが正しく動くようになりました 。chroot すると ssh したときと同様、ホストの環境がそのまま利用できるので非常に便利です。
# systemctl status
● demo-tkusumi-worker-default-f59fa5d5-d7qbs
State: running
Jobs: 0 queued
Failed: 0 units
...
root のまま操作することに不安がある場合、su
で一般ユーザに切り替えておくと安心です。
# su - ubuntu
ホストのファイルをコピーする
kubectl cp
または kubectl exec
を利用すると、scp のようにノード上のファイルを簡単にコピーできます。
kubectl cp
の方が利用はシンプルですが、セキュリティ上の理由で symlink がサポートされません 1。そのため、symlink の追従が必要で、かつ信頼できるノードである場合は、kubectl exec
を利用します。
デバッグ Pod の作成
cp
, exec
どちらも、まずは kubectl debug node
でデバッグ用 Pod を立ち上げます。このとき Pod が終了しないように sleep infinity
などを指定しておきます。
$ kubectl debug node/<NODE_NAME> --image busybox -- sleep infinity
デバッグの Pod 名が表示されます。以下の場合、node-debugger-demo-tkusumi-worker-default-f59fa5d5-xjkc9-9xj69
が Pod 名です。
Creating debugging pod node-debugger-demo-tkusumi-worker-default-f59fa5d5-xjkc9-9xj69 with container debugger on node demo-tkusumi-worker-default-f59fa5d5-xjkc9.
コピーが終わったら、この Pod を忘れずに削除しましょう。
kubectl cp の例
ホストの /etc/kubernetes
以下を、操作元の /tmp
にコピーする例です。パスに /host
が入る点に注意してください。
$ kubectl cp <DEBUG_POD>:/host/etc/kubernetes/ /tmp/
操作元の /tmp/
以下にファイルがコピーされました 。
$ ls /tmp/host/etc/kubernetes
drain-kubeconfig.yaml kube-proxy.yaml manifests
extra kubelet-kubeconfig.yaml probe-kubeconfig.yaml
kube-proxy-kubeconfig.yaml kubelet.yaml ssl
kubectl exec の例
cp
同様に、ホストの /etc/kubernetes
以下を、操作元の /tmp
にコピーする例です。パスに /host
が入る点に注意してください。
$ kubectl exec <DEBUG_POD> tar cf - /host/etc/kubernetes | tar xf - -C /tmp/
操作元の /tmp/
以下にファイルがコピーされました 。
$ ls /tmp/host/etc/kubernetes
drain-kubeconfig.yaml kube-proxy.yaml manifests
extra kubelet-kubeconfig.yaml probe-kubeconfig.yaml
kube-proxy-kubeconfig.yaml kubelet.yaml ssl
特別な Capabilities が必要な場合
Kubernetes 1.21 時点では、kubectl debug node
で、Linux Capabilities や privileged を指定できません。そのため、特別な Capabilities が必要なコマンドは実行できないことがあります。privileged は Add --privileged flag to kubectl debug node #101897 の PR がマージされれば、指定できるようになります。
ホストの Docker を使った workaround
現状どうしても、Linux Capabilities や privileged を使いたい場合は、ホストの Docker を使って権限昇格する方法があります。
まず kubectl debug node
で Pod のシェルを立ち上げます。
$ kubectl debug node/<NODE_NAME> -it --image=busybox
Pod のシェル内で、ホストのルートディレクトリに chroot
します。
# chroot /host
例えば、strace は CAP_SYS_PTRACE
の Capabilitiy が必要なため、利用できません。
# strace -e trace=file -p 1
strace: Could not attach to process. If your uid matches the uid of the target process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try again as the root user. For more details, see /etc/sysctl.d/10-ptrace.conf: Operation not permitted
strace: attach: ptrace(PTRACE_SEIZE, 1): Operation not permitted
ホストの Docker で --cap-add SYS_PTRACE
を指定し、コンテナを立ち上げます。引数で再度、chroot
している点に留意してください。
# docker run -it --cap-add SYS_PTRACE --pid=host --net=host --ipc=host -v /:/host busybox chroot /host
strace が実行できるようになりました 。
# strace -e trace=file -p 1
strace: Process 1 attached
[pid 23001] execve("/usr/bin/strace", ["strace", "-e", "trace=file", "-p", "1"], 0x7ffde9127f70 /* 10 vars */) = 0
[pid 23001] access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
[pid 23001] access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
[pid 23001] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
補足: HostPath による権限昇格について
もし、HostPath による権限昇格ができることに不安を覚えた場合は、Pod Security Policy (将来的にはその後継) による Pod のセキュリティポリシーの見直しが必要かもしれません。多くの環境で、HostPath でホストの任意のディレクトリをマウントできる Pod の作成権限は、ノードの root 相当の権限を持っていることを意味しています。
既知の問題と今後の機能追加
Kubernetes v1.21 時点での、kubectl debug node の既知の問題と、今後の入る可能性のある機能です。
- NoExecute の taint が付与されたノードで
kubectl debug node
が動作しない -
--overrides
フラグの追加- JSON 形式のパッチでデバッグ用 Pod をカスタマイズできる
- Support kubectl debug overload from overrides json #97887
-
--privileged
フラグの追加
まとめ
kubectl debug node
は、ノードのデバッグに非常に便利です。特に chroot
を使うと、ホストのコマンドがそのまま利用できるので、ssh と同じ感覚で操作が可能です。また、kubectl
の cp
や exec
と組み合わせると、scp のようなファイルのコピーも可能です。
参考
- https://kubernetes.io/docs/tasks/debug-application-cluster/debug-running-pod/#node-shell-session
- kubectl debug #1441
- KEP-1441: kubectl debug