• docker exec进程是由谁产生的


    1、问题:

    通过docker exec产生的进程bash(5704)看ppid是docker-containe(5564),但是通过ptrace进程号5564没有关于clone的系统调用,就算ptrace进程号3594、3542也没有什么有意义的。所以我有一个疑问,这个bash(5704)是由谁产生的?以下通过实验来说明。

    2、解决:

    利用kprobes中的探测技术kretprobe(基于kprobe实现),探测sys_clone函数的返回值(此返回值为新进程的pid),同时也输出当前进程号

    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/kprobes.h>
    #include <linux/ktime.h>
    #include <linux/limits.h>
    #include <linux/sched.h>
    
    static char func_name[NAME_MAX] = "sys_clone";
    module_param_string(func, func_name, NAME_MAX, S_IRUGO);
    MODULE_PARM_DESC(func, "Function to kretprobe; this module will report the"
                " function's execution time");
    
    /* per-instance private data */
    struct my_data {
        ktime_t entry_stamp;
    };
    
    /* Here we use the entry_hanlder to timestamp function entry */
    static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
    {
        struct my_data *data;
    
        if (!current->mm)
            return 1;    /* Skip kernel threads */
    
        data = (struct my_data *)ri->data;
        data->entry_stamp = ktime_get();
        return 0;
    }
    
    /*
     * Return-probe handler: Log the return value and duration. Duration may turn
     * out to be zero consistently, depending upon the granularity of time
     * accounting on the platform.
     */
    static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
    {
        int retval = regs_return_value(regs);
        struct my_data *data = (struct my_data *)ri->data;
        s64 delta;
        ktime_t now;
    
        now = ktime_get();
        delta = ktime_to_ns(ktime_sub(now, data->entry_stamp));
        printk(KERN_INFO "current task(%d) is %s, %s returned %d and took %lld ns to execute
    ",
                current->pid, current->comm, func_name, retval, (long long)delta);
        return 0;
    }
    
    static struct kretprobe my_kretprobe = {
        .handler        = ret_handler,
        .entry_handler        = entry_handler,
        .data_size        = sizeof(struct my_data),
        /* Probe up to 20 instances concurrently. */
        .maxactive        = 20,
    };
    
    static int __init kretprobe_init(void)
    {
        int ret;
    
        my_kretprobe.kp.symbol_name = func_name;
        ret = register_kretprobe(&my_kretprobe);
        if (ret < 0) {
            printk(KERN_INFO "register_kretprobe failed, returned %d
    ",
                    ret);
            return -1;
        }
        printk(KERN_INFO "Planted return probe at %s: %p
    ",
                my_kretprobe.kp.symbol_name, my_kretprobe.kp.addr);
        return 0;
    }
    
    static void __exit kretprobe_exit(void)
    {
        unregister_kretprobe(&my_kretprobe);
        printk(KERN_INFO "kretprobe at %p unregistered
    ",
                my_kretprobe.kp.addr);
    
        /* nmissed > 0 suggests that maxactive was set too low. */
        printk(KERN_INFO "Missed probing %d instances of %s
    ",
            my_kretprobe.nmissed, my_kretprobe.kp.symbol_name);
    }
    
    module_init(kretprobe_init)
    module_exit(kretprobe_exit)
    MODULE_LICENSE("GPL");

    3、结果

    探针输出结果如下:

    current task(3884) is docker-containe, sys_clone returned 5564
    current task(5564) is docker-containe, sys_clone returned 5565
    current task(5564) is docker-containe, sys_clone returned 5566
    current task(5564) is docker-containe, sys_clone returned 5567
    current task(5564) is docker-containe, sys_clone returned 5568
    current task(5564) is docker-containe, sys_clone returned 5569
    current task(5565) is docker-containe, sys_clone returned 5570
    .......
    current task(5570) is docker-containe, sys_clone returned 5696
    current task(5696) is docker-runc, sys_clone returned 5697 
    current task(5696) is docker-runc, sys_clone returned 5698
    current task(5696) is docker-runc, sys_clone returned 5699
    current task(5698) is docker-runc, sys_clone returned 5700
    current task(5699) is docker-runc, sys_clone returned 5701
    current task(5701) is docker-runc, sys_clone returned 5702
    current task(5702) is runc:[0:PARENT], sys_clone returned 5703
    current task(5703) is runc:[1:CHILD], sys_clone returned 5704
    current task(5704) is runc:[2:INIT], sys_clone returned 70

    通过pstree -p看到进程树

               ├─dockerd(3542)─┬─docker-containe(3594)─┬─docker-containe(5564)─┬─bash(5704)
               │               │                       │                       ├─bash(6053)
               │               │                       │                       ├─mysqld(5580)─┬─{mysqld}(5640)
               │               │                       │                       │              ├─{mysqld}(5641)
               │               │                       │                       │              ├─{mysqld}(5642)
               │               │                       │                       │              ├─{mysqld}(5643)
               │               │                       │                       │              ├─{mysqld}(5644)
               │               │                       │                       │              ├─{mysqld}(5645)
               │               │                       │                       │              ├─{mysqld}(5646)
               │               │                       │                       │              ├─{mysqld}(5647)
               │               │                       │                       │              ├─{mysqld}(5648)
               │               │                       │                       │              ├─{mysqld}(5649)
               │               │                       │                       │              ├─{mysqld}(5650)
               │               │                       │                       │              ├─{mysqld}(5651)
               │               │                       │                       │              ├─{mysqld}(5652)
               │               │                       │                       │              ├─{mysqld}(5653)
               │               │                       │                       │              ├─{mysqld}(5654)
               │               │                       │                       │              ├─{mysqld}(5655)
               │               │                       │                       │              ├─{mysqld}(5656)
               │               │                       │                       │              ├─{mysqld}(5657)
               │               │                       │                       │              ├─{mysqld}(5658)
               │               │                       │                       │              ├─{mysqld}(5659)
               │               │                       │                       │              ├─{mysqld}(5660)
               │               │                       │                       │              ├─{mysqld}(5661)
               │               │                       │                       │              ├─{mysqld}(5662)
               │               │                       │                       │              ├─{mysqld}(5663)
               │               │                       │                       │              ├─{mysqld}(5664)
               │               │                       │                       │              ├─{mysqld}(5665)
               │               │                       │                       │              ├─{mysqld}(5666)
               │               │                       │                       │              ├─{mysqld}(5667)
               │               │                       │                       │              ├─{mysqld}(5671)
               │               │                       │                       │              ├─{mysqld}(5672)
               │               │                       │                       │              ├─{mysqld}(5673)
               │               │                       │                       │              ├─{mysqld}(5674)
               │               │                       │                       │              ├─{mysqld}(5675)
               │               │                       │                       │              ├─{mysqld}(5676)
               │               │                       │                       │              └─{mysqld}(5677)
               │               │                       │                       ├─{docker-containe}(5565)
               │               │                       │                       ├─{docker-containe}(5566)
               │               │                       │                       ├─{docker-containe}(5567)
               │               │                       │                       ├─{docker-containe}(5568)
               │               │                       │                       ├─{docker-containe}(5569)
               │               │                       │                       ├─{docker-containe}(5570)
               │               │                       │                       ├─{docker-containe}(5571)
               │               │                       │                       └─{docker-containe}(5715)
               │               │                       ├─{docker-containe}(3595)
               │               │                       ├─{docker-containe}(3596)
               │               │                       ├─{docker-containe}(3597)
               │               │                       ├─{docker-containe}(3598)
               │               │                       ├─{docker-containe}(3599)
               │               │                       ├─{docker-containe}(3600)
               │               │                       ├─{docker-containe}(3601)
               │               │                       ├─{docker-containe}(3602)
               │               │                       ├─{docker-containe}(3883)
               │               │                       ├─{docker-containe}(3884)
               │               │                       └─{docker-containe}(5993)

    一个图总结,其中红线部分运行完就退出了,所以pstree -p看不到:

    所以根本就不是由docker-contained-shim(5564)产生的bash进程,所以ptrace没什么结果。

    一个问题:以上红框内runc退出后其子进程bash不是应该由init进程接管吗?如何变成docker-containerd-shim的子进程呢?

    解答:从Linux 3.4开始,prctl增加了对PR_SET_CHILD_SUBREAPER的支持,这样就可以控制孤儿进程可以被谁接管,而不是像以前一样只能由init进程接管。

    4、后续

    左边是strace结果,右边是kret结果。ppid是通过status查看的,可以看到很多不是28323产生的进程,都通过prctl由它接管了

    但左边28330显示是parent,而右边显示28330是child

    即为:红线内是kret视角(kret一起监控clone和execve,发现parent等的确没有发生execve)

    原因猜测:

    先clone原进程,新进程刚要运行就会因为被标记的延迟信号(SIGSTOP)要处理,所以第一时间就陷入到strace(strace跟踪多线程与内核的交互),strace此时wait到的pid是新进程的,而name是刚才clone的父进程的。

    而后该新进程正常运行,改名(可以通过prctl(PR_SET_NAME, new_name)。参考:linux下修改进程名称),所以该进程发生clone时name和strace看到的已经不同了。

    以上是一种根据现象猜测的原因,具体是不是这样需要看docker的在这部分的实现,为啥改名呢?

  • 相关阅读:
    流复制-pg_basebackup (有自定义表空间)
    流复制-pg_basebackup (没有自定义表空间)
    PG 更新统计信息
    PG修改参数方法
    Postgres的索引01
    Postgres基础操作
    PostgreSQL安装
    SQL拦截器
    没对象的快自己写一个吧!带你了解一下python对象!
    喜欢看电影来哦!教你如果使用Python网络爬虫爬取豆瓣高分电影!
  • 原文地址:https://www.cnblogs.com/beixiaobei/p/9147470.html
Copyright © 2020-2023  润新知