sysdig工作原理
Sysdig架构
具体实现
-
内核空间
首先,sysdig-probe 的这个驱动利用了内核组件tracepoint 捕获在内核层面的事件。通过Tracepoint,可以放置一个能够被内核中特殊函数调用的处理程序"handler"。现在,sysdig 在进入、退出、进程调度这些事件的系统调用上注册了tracepoints,也即Sysdig-probe 的工作内容。Sysdig-probe对这些事件的处理程序"handler"极其简单,它仅仅复制了事件的详细信息到一个共享缓存区中,并对其编码以供后面使用。让"handler"如此简单的一个重要原因就是性能考虑,因为原始的内核执行程序会被“冻结”直到"handler"返回。
(tracepoint 提供了一个钩子去调用一个函数(称为probe,也即探针)。当一个tracepoint 被probe 连接上时便启动了,每次tracepoint 被执行的时候,probe 这个函数便会在调用方的执行上下文中被调用。probe 结束执行,返回给调用者,从tracepoint 位置继续。)
-
用户空间
"event buffer"使用了内存映射的方式映射到用户空间,因此它能够在没有进行任何复制操作的情况下被访问,最小化了CPU使用率和减少缓存丢失的情况。"libscap"和"libsinsp"这两个库提供了读、编码以及解析事件的功能。具体来说,"libscap"提供了跟踪文件管理功能,而"libsinsp"包含了复杂的状态跟踪功能(例如,可以使用文件名而不是FD),以及过滤、事件解码、运行"chisels"工具的Lua JIT编译器等。
最后,sysdig 对这些库进行了简单的包装。
当"event buffer"填满(即sysdig,libsinsp,libscap 来不及处理来自内核的事件流)的时候,sysdig-probe 便会开始丢弃即将到来的事件。这种情况下可能会丢失部分跟踪信息,但机器或者其他进程的性能不会受其影响。这意味着,sysdig很适合用在生产环境上。
Linux系统调用相关
sysdig基于系统调用工作。系统调用,指运行在用户空间的程序向操作系统内核请求需要更高权限运行的服务。系统调用提供用户程序与操作系统之间的接口。大多数系统交互式操作需求在内核态运行。如设备IO操作或者进程间通信
简单地说,系统调用是程序与操作系统交互的主要方式。系统调用接口包含了若干个操作系统赋予给运行在其上的应用程序使用的函数。这些函数允许打开文件、创建网络连接、从文件中读写等操作,可以说机器上大部分的事件都要经过系统调用。
想要掌握sysdig的使用,我们需要掌握以下系统调用。
clone
- 主要工作:
创建新进程 - 作用:
Clone 基本上是创建进程和线程的唯一Linux内核入口点。这意味着你能通过查看它观察到所有进程和线程的活动执行。子线程中的返回值为0,父线程中的子pid为0。Clone克隆是最复杂的系统调用之一,有很多可以告诉你很多关于新进程正在创建的标志 - 注意:
Clone 是唯一返回两次的系统调用,一次是在父进程,一次在子进程。
execve
- 主要工作:
执行新的程序 - 作用:
Execve 是运行程序的唯一Linux内核入口。用户空间API有几种变形,比如execl和fexecve,但它们最后都会激活系统调用execve。你基本上总能在clone操作后看见execve操作,监控execve操作能告诉你什么程序在你的系统里执行。单一程序、脚本、定时任务都会通过execve执行。
chdir
- 主要工作:
改变当前进程的工作目录 - 作用:
通过chdir,能看见谁访问了哪个目录
open/creat
- 主要工作:
打开乃至新建一个文件或设备 - 作用:
通过追踪这个系统调用,你能够看到文件什么时候被创建或修改 - 注意:使用filters能够让在sysdig中追踪这个系统调用更高效(更有趣)
sysdig evt.type=open and proc.name=evilproc and file.name contains /etc
connect
- 主要工作:
在套接字上启动连接 - 作用:
这是建立新的网络连接的唯一内核入口。每一次机器上的进程想要连接某个地方,你就能看到这个系统调用。 - 注意:
sysdig evt.type=connect and fd.port=80
accept
- 主要工作:
接受套接字上的连接 - 作用:
此系统调用镜像连接,即每次在机器上建立服务器连接时都将看到一个镜像连接
read/write
- 主要工作:
read 和write 系统调用在Linux系统调用接口中有很多变形,如:readv、writev、preadv、pwritev、send、recv、sendto、recvfrom、sendmsg、recvmsg、recvmmsg。它们大致上做着相同的工作,即向一个文件描述符读写数据,这是I/O操作的核心。 - 作用:
由于在Linux上几乎所有东西都是一个文件描述符,观察这些调用非常方便。通过它们可以看到文件的访问、网络数据的交换、pipes的活动以及unix套接字。 - 注意:sysdig提供了一个chisel工具echo_fds让我们能够很方便地查看I/O活动
sysdig -c echo_fds fd.name=/etc/passwd
unlink/rename
- 主要工作:
删除或者重命名文件 - 作用:
open/creat 系统调用能告诉你新建了文件,read/write 调用的变形能告诉你文件什么时候被修改,而unlink和rename 则告诉你什么时候文件被删除和重命名
brk/mmap/munmap
- 主要工作:
分配/释放内存 - 作用:
这些系统调用能让你观察到进程什么时候分配或者释放内存。brk 通常由malloc()使用,而mmap/mmunmap 具有更多用途,包括共享内存或将文件映射到内存 - 注意:
内存管理极其复杂,范围远超出这里的内容。 由于程序中的malloc()或new()方法,你几乎永远不会看到brk或mmap调用,因为一般情况下你的程序在获取其内存之前可能会经过至少一个或两个实体。例如,glibc有一个内存分配器,该内存分配器从内核中请求大块连续地址的内存,然后在用户级别进行管理。你最喜欢的基于VM语言的垃圾回收器就是执行类似的操作。
select/poll
- 主要工作:
等待操作执行 - 作用:
当进程没有主动去执行某个操作时,它们可能被这两者之一阻塞住了。观察它们的参数能告诉我们进程在等待什么以及等了多久。
kill
- 主要工作:
发送信号 - 作用:
kill 用于进程间发送信号
参考资料:
https://sysdig.com/blog/sysdig-vs-dtrace-vs-strace-a-technical-discussion/
https://www.kernel.org/doc/Documentation/trace/tracepoints.txt
https://sysdig.com/blog/fascinating-world-linux-system-calls/