LoginSignup
48
39

More than 1 year has passed since last update.

Kubernetes: kubectl debug node でノードをデバッグする

Last updated at Posted at 2021-05-25

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 のシェル内で、/hostchroot し、/ をホストのルートディレクトリにすると正常に動くようになります。

# chroot /host

コマンドが正しく動くようになりました :tada:。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/ 以下にファイルがコピーされました :tada:

$ 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/ 以下にファイルがコピーされました :tada:

$ 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 が実行できるようになりました :tada:

# 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 の既知の問題と、今後の入る可能性のある機能です。

まとめ

kubectl debug node は、ノードのデバッグに非常に便利です。特に chroot を使うと、ホストのコマンドがそのまま利用できるので、ssh と同じ感覚で操作が可能です。また、kubectlcpexec と組み合わせると、scp のようなファイルのコピーも可能です。

参考

48
39
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
48
39