Debug application inside Kubernetes using Linux Kernel tools
- Sonyのシステムエンジニア @KentaTadaさん
- runc Docker containerのコントリビューター
Agenda
- oci-ftrace-syscall-analyzerの紹介
- Kubernetes上でプロセスのコアダンプを取る方法の紹介
Kuberetesの全体像
oci-ftrace-syscall-analyzerの紹介
軽量でセキュアなruncベースのコンテナ環境を組み込み向けに開発した
サードパーティ向けにセキュア(制限があってルートレスな)コンテナを立ち上げる要件
ftraceベースのシステムコールアナライザを作った
既存のKuberentesデバッグ方法
デバッグツールをPodに入れる デバッグ用イメージを作る プロセスの名前空間を共有した状態でデバッグ用サイドカーを入れる
カーネルツールを透過的にアプリケーションをトレースするために使う
既存のツールは便利だけど、ケーパビリティやファイルの権限、seccompなどのセキュリティ要件を満たすのが難しい部分もある
トレース周りのカーネル技術
図がすごい。今回はftraceを使うようにした。eBPFなどの話もしていたが頭が追いつかないw
syscallの解析に使ったカーネル技術
ftrace もともとはfunction tracerとして作られたトレーシングフレームワーク セットアップが簡単 eBPFコンパイラ(LLVM)がいらない
tracepoints カーネルに入ってるトレースポイント
統合に必要な準備
ftraceリングバッファを分割する(下記コンテナランタイム勉強会の資料参照)
ftraceをコンテナ内部で立ち上げる
コンテナ起動時にftraceを仕込む方法
コンテナが動く前にftraceを注入する
- OCI runtime specの中でprestartからhookできると記述があるので、それを使った
- poststopまでをcollect logする
PID processをコンテナ内部で取得する方法
コンテナ内のPID1プロセスをホスト側の実PIDをとるには
- OCI runtime specの中でstdinでjson形式でコンテナのステートが入っているよという記述がある
- それを取ると根本のPIDがわかる
ftraceで何やってるか
- トレースしたいシステムコールをenable
- 取得したホスト側のPIDをセット
- trace processes which PID of set_event_pid forked
- コンテナ起動時のプロセスしか取れないので、kubectl execとかしたときのプロセスのsyscallはとれない
ここまででrunc周りのインテグレーションが終わった。
Kuberetesで導入するには
- Kuberentesのラインタイムに対してどう頑張るか
- poststartの段階で頑張るのは難しいと言うのが分かった
Containerdではどうか
- KubernetesレベルでだめならHigh level container runtimeのレベルでどうなんだろうか。という話
- PRレベルでは動いてるが、今の時点では厳しいみたい
CRI-oではどうか
oci hooks機能があって、それを書いてあげるとruncのhookもできるようになる
CRI-Oでできるかのデモ(サンプルコードもあるよ!)
とりあえず動く事がわかった
関連ツール
oci-seccomp-bpf-hook
- コンテナのシステムコールをもとに、eBPFを使ってseccompのプロファイルを生成する
kubectl-trace
- 聞き逃し
↑基本的にはこれ強いけど、oci-ftrace-syscall-analyzerは
- ユーザーに特権を渡したくないときに有用そう
- eBPFの設定がカーネルにちゃんと入ってない場合にそれに依存せず使えそう
これらの解決策で今抱えてる問題は?
コンテナは独自のnamespaceがあってカーネルのnamespaceを使ってない
- カーネルコードに対するパッチは有るけどマージされてない
Kuberenetesにアドオンを使って解決しようという方法
- これもマージされてない
まとめ
- CRI-OベースのKubernetes環境であればHook出来ることがわかった
- まだまだ課題があるので頑張るぞい
- コアダンプについてはなにもわからn(おしえて)
今後の課題
- Containerdとの連携
- 社内のコンテナツールで取得できるユーザー空間のログをがんばる
- syscallの引数を取るためにkprobesを使ったsystemcall hookができるようにしたい
- seccomp generatorを作りたい
- OCIのprestartで取ってるのでruncが動くまでの他の不要なsyscallまで取れちゃう
- workaroundありそうだけどこれは本当に正しいのかがよくわかってない