概要
kubectl debug を使うと、デバッグ用のコンテナを起動して、Pod 内の調査を行うことができます。
たとえばシェル(bash や shell)が入っていないコンテナに対しても、シェルが入った別コンテナを立てることで Linux コマンドを使った調査が可能です。
その kubectl debug で、BPF Tools が入ったイメージを使えたら面白いのではないか、という思いは昔(4年前くらい)からあったのですが、当時は kubectl debug が alpha ステージだったので、構想のみでした。
すでに kubectl debug の機能が成熟して、さまざま Profile(kubectl debug の Profile)が出てきた現在、kubectl debug コマンドを使ったデバッグコンテナイメージ構築に挑戦しました。
利用する BPF Tools
BPF とは...を説明すると長くなるので省略します。
詳しくはこちらを参照
https://ebpf.io/what-is-ebpf/拙作ですがこちらも参考になるかもしれません
https://go-vargo.hatenablog.com/entry/2020/03/29/210304
BPF の機能はさまざまな領域にわたるのですが、ここでの目的は主に Performance Tuning や Observability, Profiling などの用途で使います。
具体的には、BPF Tools として有名な BCC と bpftrace をデバッグコンテナ上で動かせるようにします。
得られる効果
kubectl debug を使うことで、デバッグコンテナを立ち上がることができ、その中で今回使う BCC や bpftrace を動かすことができます。
$ kubectl debug -it <pod name> --image govargo/bpf-tools --profile sysadmin --target <target container> -- bash
## example from bcc
execsnoop
## other example from bpftrace
tcplife.bt
これの素晴らしいところとして、Pod に対して実行できるところが挙げられます。
というのも、これまでも BPF Tools を Kubernetes 上で動かす試みやツールはありましたが、BPF が Linux Kernel の機能を使うため、ホストのカーネルを共有する(具体的にいうと、特定ディレクトリをマウントする)必要がありました。
そのため、BPF Tools のコマンドで見られる情報が Pod ではなく、Node(Host) 全体のものになってしまうことになり、見たい情報を絞ることがなかなか難しく、Pod の情報が見たいのに、Host 全体の情報が見えてしまう、という難点がありました。
kubectl debug を使うことで、自然と Pod に対する実行になります。
[2024/10/26 追記]
ホスト上でわざとプロセス(sleep, curl など)を作成して確認したところ、ホスト全体の情報を取っていることを確認しました。
これは推測ですが、Linux カーネルの情報を利用している以上、(情報を)取っている対象がホスト全体になるからと思われます。
Pod の情報だけを取る場合は、BPF Tools の方を修正する必要性がありそうです。
(修正するイメージは厳密には湧いていないですが、コンテナの PID のみを対象とするような修正)
ただ、現状ホスト全体の情報が見えるとはいえ、気軽に BCC や bpftrace を使えるというメリットがあります。
せっかくなので、動くイメージを作ってみました。
前提
以下のプラットフォームやバージョンで試しています。
- Worker Node の OS: Ubuntu 22.04 LTS
- Kubernetes: GKE 1.30.4-gke(※1)
- Kernel Version: 5.15.0-1064-gke
※1 特に大切なのが Kernel Version ですが、GKE を使うと、Node の Kernel Version が xxx-gke となり、テストできているのは GKE のみになります。
(他プラットフォームだとどうなるかは未知数です)
BPF CO-RE(Compile Once - Run Everywhere) を使っているので、多少のカーネルバージョンの差異があっても動く気はしますが、それでも Linux Kernel の機能を使っている以上、破壊的な変更や差異があると動かない気はします。
そのため、上記以外でもし動かしてみたい方がいらっしゃる場合は自己責任でお願いします。
デバッグ用コンテナイメージ
kubectl debug で動かすデバッグ用コンテナイメージは以下のリポジトリにまとめています。
この Dockerfile を作るにあたって工夫・苦労した点についてまとめます。
BCC のインストール
BCC のインストール方法は下記の公式リポジトリで案内されています。
https://github.com/iovisor/bcc/blob/master/INSTALL.md#ubuntu---binary
# 引用元: https://github.com/iovisor/bcc/blob/master/INSTALL.md#ubuntu---binary
$ sudo apt-get install bpfcc-tools linux-headers-$(uname -r)
この方法を試したのですが、Kernel Version が合わないからか、あるいはコンテナ化しているからか、Warning か Error ばかり出てうまく行きませんでした。
(ちなみにどんなエラーだったかは忘れました...)
詰まっていたところに以下の記事を読み、BPF CO-RE 版があることを知りました。
libbpfとclangでポータブルなBPF CO-REバイナリ作成
BPF CO-RE 版のバイナリをビルドするようにしたところ Kernel Header のインストールも不要かつ、エラーも出なくなりました。
RUN apt-get update && apt-get install -y \
build-essential libbpf-dev clang llvm linux-tools-common git make linux-libc-dev
# Build libbpf bcc tools
RUN git clone --recursive https://github.com/iovisor/bcc.git && cd bcc/libbpf-tools && \
make bashreadline bindsnoop biolatency biopattern...
bpftrace のインストール
bpftrace のインストール方法も下記の公式リポジトリで案内されています。
https://github.com/bpftrace/bpftrace/blob/master/INSTALL.md#ubuntu-packages
この方法も試したのですが、bpftrace が上手く動きませんでした。
apt-get でインストールできるバージョンは v0.14.0 と古く(最新版は v0.21.2)、最新版バイナリをダウンロードして解凍・展開する方法に切り替えました。
※ 最新版は v0.21.2 ですが、書いた当時は v0.20.4 が最新だったため、v0.20.4 のままになっています
Before:
RUN apt-get update && apt-get install -y \
procps util-linux numactl strace dstat sysstat nicstat cpuid linux-tools-common bpftrace
After:
RUN apt-get update && apt-get install -y curl xz-utils
RUN curl -LO https://github.com/bpftrace/bpftrace/releases/download/v0.20.4/binary_tools_man-bundle.tar.xz && \
xz -dv binary_tools_man-bundle.tar.xz && tar xfv binary_tools_man-bundle.tar
bpftrace のインストール以外にも、カーネルヘッダーのインストールも行なっています。
ARG KERNEL_VERSION=5.15.0-1064-gke
# Install debug tools
RUN apt-get update && apt-get install -y linux-headers-${KERNEL_VERSION} linux-libc-dev libc6-dev \
...
どうも bpftrace からカーネルヘッダーの参照を行なっているらしく、ない場合は実行はできるものの、WARNING が表示されます。
tcplife.bt
WARNING: Could not find kernel headers in or . To specify a particular path to kernel headers, set the env variables BPFTRACE_KERNEL_SOURCE and, optionally, BPFTRACE_KERNEL_BUILD if the kernel was built in a different directory than its source. To create kernel headers run 'modprobe kheaders', which will create a tar file at /sys/kernel/kheaders.tar.xz
Attaching 3 probes...
そのため、カーネルヘッダーのインストールはそのまま残しています。
kubectl debug の注意事項
kubectl debug コマンドでは、フラグによって Profile を選択可能です。
https://kubernetes.io/docs/reference/kubectl/generated/kubectl_debug/#options
--profile string Default: "legacy"
Option には以下のものがあります。
Options are "legacy", "general", "baseline", "netadmin", "restricted" or "sysadmin".
BCC や bpftrace を使うためには特権が必要になるため、sysadmin
が必要になります。
kubectl で sysadmin profile がサポートされているのは 1.30 以降のため、それ以降の kubectl バイナリが必要です。
debugfs ファイルシステムのマウント
BPF Tools のいくつかのコマンドは /sys/kernel/debug
を参照する必要があるものがあります。
/sys/kernel/debug
には debugfs ファイルシステムへのマウントが必要ですが、コンテナイメージ内では debugfs へのマウントがありません。
そこで、.bashrc
に以下の行を追加することで、bash でユーザーがコンテナに入るときに mount コマンドを実行するようにしています。
(bash なので、shell で入ってこられたら実行されないと言えば、mount されないのですが...)
RUN echo "mount -t debugfs none /sys/kernel/debug" >> ~/.bashrc
終わりに
自分が特に BCC や bpftrace を触っていたのが、4年前の 2020 年あたりでしたが、久しぶりに触って、BPF CO-RE の存在が素晴らしいなと思いました。
4 年前に夢描いていたことが実現して、個人的には感無量です。
今回 kubectl debug 用のデバッグコンテナを作ったものの、まだまだ BPF や BPF Tools を活用しきれていない気がしているので、今後も勉強していきたいです。
Dockerfile も本当は使わないけど慣習的に入れている無駄なパッケージもある気がしているので、もう少しスリム化できないか検討したいところです。
以上になります。