介绍一个小工具:Inspektor Gadget

2022-11-23 14:37:40 浏览数 (2)

各位好,今天 6 月 26 号,吃了么您呐。

例行查看 krew index 的时候,发现有个新插件 gadgit,翻翻来历,居然是 Kinvolk 的作品,公司不太出名,印象里最早做服务网格 Benchmark 的就是他。插件功能介绍很简单:Collection of gadgets for Kubernetes developers,但是用法就很了不得了,非常有字数越小事越大的感觉:

代码语言:javascript复制
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 安装这个插件:

代码语言:javascript复制
$ 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 两个部分构成,分别是启动特定命名空间内工作负载的网络监听,生成跟踪记录;以及根据跟踪记录生成网络策略两部分,例如:

代码语言:javascript复制
$ 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 4026531992n"}
...

执行一段时间后使用 Ctrl C 终止命令,可以看到指定的输出文件中包含了一堆类似 JSON 的记录内容,可以用这个文件生成网络策略:

代码语言:javascript复制
$ 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 模块完成的,这个模块有三个子命令,分别是 startliststop,例如要跟踪一个 Calico Pod:

代码语言:javascript复制
$ 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:

代码语言:javascript复制
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-iocpu 两个指令,例如监控某个节点的 block-io

代码语言:javascript复制
 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 开关意思是只关注内核空间的内容:

代码语言:javascript复制
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 模块分为 processsocket 两个子命令,分别用于记录进程和网络。(v0.5.1 版本的 process 子命令好像无法工作)。

代码语言:javascript复制
$ 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-iotcpfile,跟 Linux 系统的 top 命令类似,例如下面的命令列出的 top file:

代码语言:javascript复制
$ 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: openreadwritefsync 操作时长超过阈值
  • mount: mountumount 操作
  • oomkill: OOM Killer 被触发
  • open: open 系统调用
  • signal: 跟踪进程收到的信号
  • sni: TLS 请求中的 SNI
  • tcp: TCP 的 connectacceptclose
  • tcpconnect: connect 调用

例如对 open 的跟踪:

代码语言:javascript复制
$ 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 都不好做了?

0 人点赞