介绍一个小工具:Inspektor Gadget
各位好,今天 6 月 26 号,吃了么您呐。
例行查看 krew index 的时候,发现有个新插件 gadgit
,翻翻来历,居然是 Kinvolk 的作品,公司不太出名,印象里最早做服务网格 Benchmark 的就是他。插件功能介绍很简单:Collection of gadgets for Kubernetes developers
,但是用法就很了不得了,非常有字数越小事越大的感觉:
Available Commands:
advise Recommend system configurations based on collected information
audit Audit a subsystem
completion generate the autocompletion script for the specified shell
deploy Deploy Inspektor Gadget on the cluster
help Help about any command
profile Profile different subsystems
snapshot Take a snapshot of a subsystem and print it
top Gather, sort and periodically report events according to a given criteria
trace Trace and print system events
traceloop Get strace-like logs of a pod from the past
undeploy Undeploy Inspektor Gadget from cluster
version Show version
过滤掉辅助功能,可以看到几个主要内容:
- advise:根据搜集信息,推荐系统配置内容
- audit:对子系统进行审计
- profile:对不同子系统进行侧写
- snapshot:给子系统进行快照并打印
- top:根据制定规则,搜集、排序和周期性地报告事件
- trace:跟踪和打印系统事件
- traceloop:获取类似 strace 格式的历史日志
其实说了跟没说一样是不是?不如一条条看过去了。
部署
首先使用 krew 安装这个插件:
$ kubectl krew install gadget
Updated the local copy of plugin index.
Installing plugin: gadget
...
| Use this plugin:
| kubectl gadget
...
| | $ kubectl gadget deploy | kubectl apply -f -
...
WARNING: You installed plugin "gadget" from the krew-index plugin repository.
...
上文可以看到,使用插件之前要安装到及群里 kubectl gadget deploy | kubectl apply -f -
,可以看到,除了 RBAC 内容之外,还有 Daemonset 和 CRD 这两个东西。为了跟踪 Pod 行为,Inspektor Gadget 把 BPF 程序附加到内核函数上,当函数被执行时,内核也会运行这些被注入的程序。因此,BPF 程序需要检测触发该函数的系统调用,是否来自 Inspektor Gadget 的追踪目标。为了做到这一点,程序在包含要追踪的 Pod 列表的 BPF Map 中查找当前的 cgroup id,如果没有找到,程序会提前退出。最后,BPF程序收集要追踪的信息,例如,系统调用参数,并将它们 Ring Buffer 或 BPF Map。Inspektor Gadget 的用户空间工具在 Ring Buffer 或 BPF 地图上监听或读取,并获取新的事件。追踪结束后,BPF 程序将会被删除。
Network Policy Advise
这个功能由 Monitor 和 Report 两个部分构成,分别是启动特定命名空间内工作负载的网络监听,生成跟踪记录;以及根据跟踪记录生成网络策略两部分,例如:
$ kubectl gadget advise network-policy monitor --output /tmp/result.txt
Node "gke-gcp-vlab-k8s-default-pool-d3fe3442-pw6v" ready.
Node "gke-gcp-vlab-k8s-default-pool-d3fe3442-9hsc" ready.
Node "gke-gcp-vlab-k8s-default-pool-d3fe3442-nj0k" ready.
^C
Stopping...
$ more /tmp/result.txt
{"type":"ready"}
{"type":"ready"}
{"type":"ready"}
{"type":"connect","remote_kind":"pod","port":2021,"local_pod_namespace":"gadget","local_pod_name":"gadget-dzb7g","local_pod_labels":{"controller-revision-hash":"8f55cc94f","k8s-app":"gadget","pod-template-generation":"1"},"remote_pod_namespace":"kube-system","remote_pod_name":"pdcsi-node-lpqln","remote_pod_labels":{"controller-revision-hash":"69cdc7c487","k8s-app":"gcp-compute-persistent-disk-csi-driver","pod-template-generation":"1"},"debug":"4649087588182 cpu#1 connect 3293 otelsvc 10.138.15.229:33032 10.138.15.229:2021 4026531992\n"}
...
执行一段时间后使用 Ctrl+C 终止命令,可以看到指定的输出文件中包含了一堆类似 JSON 的记录内容,可以用这个文件生成网络策略:
$ kubectl gadget advise network-policy report --input=/tmp/result.txt
...
podSelector:
matchLabels:
k8s-app: konnectivity-agent
ports:
- port: 10250
protocol: TCP
podSelector:
matchLabels:
k8s-app: gadget
policyTypes:
- Ingress
- Egress
可以看到,网络策略已经生成。
Seccomp Profile Advise
这一功能是用 advise seccomp-profile
模块完成的,这个模块有三个子命令,分别是 start
、list
和 stop
,例如要跟踪一个 Calico Pod:
$ kubectl gadget advise seccomp-profile start --podname=calico-node-t6hwg
HAmaTrPcxTLDNfSo
$ kubectl gadget advise seccomp-profile list
NAMESPACE NODE(S) POD CONTAINER TRACEID
kube-system gke-gcp-vlab-k8s-default-pool-d3fe3442-9hsc,gke-gcp-vlab-k8s-default-pool-d3fe3442-nj0k,gke-gcp-vlab-k8s-default-pool-d3fe3442-pw6v calico-node-t6hwg HAmaTrPcxTLDNfSo
上面 start
命令执行后出现的 HAmaTrPcxTLDNfSo
就是跟踪 ID,开始一段时间之后,可以调用 stop
命令结束跟踪,跟踪结束后会显示这个 Pod 的 Seccomp:
kubectl gadget advise seccomp-profile stop HAmaTrPcxTLDNfSo
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": [
"SCMP_ARCH_X86_64",
"SCMP_ARCH_X86",
"SCMP_ARCH_X32"
],
"syscalls": [
{
"names": [
"accept4",
"access",
"arch_prctl",
...
],
"action": "SCMP_ACT_ALLOW"
}
]
}
Profile
这个模块包括 block-io
和 cpu
两个指令,例如监控某个节点的 block-io
:
kubectl gadget profile block-io --node=gke-gcp-vlab-k8s-default-pool-d3fe3442-9hsc
Tracing block device I/O... Hit Ctrl-C to end.^C
usecs : count distribution
0 -> 1 : 0 | |
2 -> 3 : 0 | |
4 -> 7 : 0 | |
8 -> 15 : 0 | |
16 -> 31 : 0 | |
32 -> 63 : 0 | |
64 -> 127 : 1 | |
128 -> 255 : 1 | |
256 -> 511 : 0 | |
512 -> 1023 : 2 | |
1024 -> 2047 : 54 |**************** |
2048 -> 4095 : 44 |************* |
4096 -> 8191 : 49 |*************** |
8192 -> 16383 : 128 |****************************************|
16384 -> 32767 : 118 |************************************ |
32768 -> 65535 : 11 |*** |
65536 -> 131071 : 5 |* |
可以看到以微秒为单位的统计记录和分布情况。cpu
子命令的用法如下,其中 -K
开关意思是只关注内核空间的内容:
kubectl gadget profile cpu -p calico-node-t6hwg -K
Capturing stack traces... Hit Ctrl-C to end.^C
calico-node;entry_SYSCALL_64_after_hwframe;do_syscall_64;ksys_write;vfs_write;pipe_write;__wake_up_sync_key;_raw_spin_unlock_irqrestore;_raw_spin_unlock_irqrestore 1
calico-node;entry_SYSCALL_64_after_hwframe;do_syscall_64;ksys_read;vfs_read;pipe_read;anon_pipe_buf_release;anon_pipe_buf_release 1
ip 1
calico-node;entry_SYSCALL_64_after_hwframe;do_syscall_64;__se_sys_nanosleep;get_timespec64;_copy_from_user;copy_user_generic_unrolled;copy_user_generic_unrolled 1
calico-node 9
Snapshot
Snapshot 模块分为 process
和 socket
两个子命令,分别用于记录进程和网络。(v0.5.1
版本的 process
子命令好像无法工作)。
$ kubectl gadget snapshot socket \
--node=gke-gcp-vlab-k8s-default-pool-d3fe3442-pw6v \
-o custom-columns=namespace,pod,protocol,status
NAMESPACE POD PROTOCOL STATUS
kube-system calico-node-zjpl5 TCP ESTABLISHED
kube-system calico-node-zjpl5 TCP ESTABLISHED
kube-system calico-node-zjpl5 TCP ESTABLISHED
kube-system calico-node-zjpl5 TCP ESTABLISHED
kube-system calico-node-zjpl5 TCP ESTABLISHED
kube-system calico-node-zjpl5 TCP ESTABLISHED
kube-system calico-node-zjpl5 TCP ESTABLISHED
Top
这个模块有三个子命令,block-io
、tcp
和 file
,跟 Linux 系统的 top
命令类似,例如下面的命令列出的 top file:
$ kubectl gadget top file \
-o custom-columns=container,pid,comm,reads
CONTAINER PID COMM READS
fluentbit 3737 flb-pipeline 1
fluentbit 3737 flb-pipeline 1
fluentbit 3737 flb-pipeline 2
gke-metrics-agent 56606 otelsvc 2
fluentbit 3737 flb-pipeline 1
fluentbit 3737 flb-pipeline 1
fluentbit 3737 flb-pipeline 2
gke-metrics-agent 56606 otelsvc 2
fluentbit 3737 flb-pipeline 1
fluentbit 3737 flb-pipeline 2
Trace
这个模块针对系统事件进行跟踪,目前支持包括:
- bind:Scoket 绑定
- capabilities:Capability 检查
- dns:DNS 请求
- exec:新进程
- fsslower:
open
、read
、write
和fsync
操作时长超过阈值 - mount:
mount
和umount
操作 - oomkill:OOM Killer 被触发
- open:
open
系统调用 - signal:跟踪进程收到的信号
- sni: TLS 请求中的 SNI
- tcp:TCP 的
connect
、accept
和close
- tcpconnect:
connect
调用
例如对 open
的跟踪:
$ kubectl gadget trace open -o custom-columns=container,path
CONTAINER PATH
fluentbit /var/log/containers
fluentbit /var/log/pods
fluentbit /var/log/containers
fluentbit /var/log/pods
fluentbit /var/run/google-fluentbit/pos-files
...
csi-driver-registrar /usr/bin/runc
csi-driver-registrar /sys/kernel/mm/hugepages
...
然后
以后没 eBPF 支持连 Ops 都不好做了?