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 ; /* Skip kernel threads */ data = (struct my_data *)ri->data;
data->entry_stamp = ktime_get();
return ;
} /*
* 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\n",
current->pid, current->comm, func_name, retval, (long long)delta);
return ;
} 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 = ,
}; static int __init kretprobe_init(void)
{
int ret; my_kretprobe.kp.symbol_name = func_name;
ret = register_kretprobe(&my_kretprobe);
if (ret < ) {
printk(KERN_INFO "register_kretprobe failed, returned %d\n",
ret);
return -;
}
printk(KERN_INFO "Planted return probe at %s: %p\n",
my_kretprobe.kp.symbol_name, my_kretprobe.kp.addr);
return ;
} static void __exit kretprobe_exit(void)
{
unregister_kretprobe(&my_kretprobe);
printk(KERN_INFO "kretprobe at %p unregistered\n",
my_kretprobe.kp.addr); /* nmissed > 0 suggests that maxactive was set too low. */
printk(KERN_INFO "Missed probing %d instances of %s\n",
my_kretprobe.nmissed, my_kretprobe.kp.symbol_name);
} module_init(kretprobe_init)
module_exit(kretprobe_exit)
MODULE_LICENSE("GPL");

3、结果

探针输出结果如下:

current task() is docker-containe, sys_clone returned 
current task() is docker-containe, sys_clone returned
current task() is docker-containe, sys_clone returned
current task() is docker-containe, sys_clone returned
current task() is docker-containe, sys_clone returned
current task() is docker-containe, sys_clone returned
current task() is docker-containe, sys_clone returned
.......
current task() is docker-containe, sys_clone returned
current task() is docker-runc, sys_clone returned
current task() is docker-runc, sys_clone returned
current task() is docker-runc, sys_clone returned
current task() is docker-runc, sys_clone returned
current task() is docker-runc, sys_clone returned
current task() is docker-runc, sys_clone returned
current task() is runc:[:PARENT], sys_clone returned
current task() is runc:[:CHILD], sys_clone returned
current task() is runc:[:INIT], sys_clone returned

通过pstree -p看到进程树

           ├─dockerd()─┬─docker-containe()─┬─docker-containe()─┬─bash()
│ │ │ ├─bash()
│ │ │ ├─mysqld()─┬─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ ├─{mysqld}()
│ │ │ │ └─{mysqld}()
│ │ │ ├─{docker-containe}()
│ │ │ ├─{docker-containe}()
│ │ │ ├─{docker-containe}()
│ │ │ ├─{docker-containe}()
│ │ │ ├─{docker-containe}()
│ │ │ ├─{docker-containe}()
│ │ │ ├─{docker-containe}()
│ │ │ └─{docker-containe}()
│ │ ├─{docker-containe}()
│ │ ├─{docker-containe}()
│ │ ├─{docker-containe}()
│ │ ├─{docker-containe}()
│ │ ├─{docker-containe}()
│ │ ├─{docker-containe}()
│ │ ├─{docker-containe}()
│ │ ├─{docker-containe}()
│ │ ├─{docker-containe}()
│ │ ├─{docker-containe}()
│ │ └─{docker-containe}()

一个图总结,其中红线部分运行完就退出了,所以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的在这部分的实现,为啥改名呢?

docker exec进程是由谁产生的的更多相关文章

  1. docker attach 和 docker exec

    docker attach docker attach -- Attach to a running container. 常用选项: --sig-proxy=true:Proxy all recei ...

  2. 使用docker exec命令

    这个命令使用exit命令后,不会退出后台,一般使用这个命令,使用方法如下   docker exec -it db3 /bin/sh 或者 docker exec -it d48b21a7e439 / ...

  3. Docker exec与Docker attach

    转载博客地址:http://blog.csdn.net/halcyonbaby 新浪微博:@寻觅神迹 内容系本人学习.研究和总结,如有雷同,实属荣幸! ================== Docke ...

  4. docker run VS docker exec 的区别

    “docker run”和“docker exec”都是 Docker 容器中用于执行的命令.然而,在不同的情况下,它们的使用有着本质上的区别. “docker run”命令 “docker run” ...

  5. 使用docker exec 就可以进入container,例如:docker exec -it <container_id> /bin/bash

    使用docker exec 就可以进入container,例如:docker exec -it <container_id> /bin/bash

  6. paas架构之docker——容器进程管理

    1.docker进程管理 docker的进程管理命令ps的用法基本和ubuntu系统的用法一致 1.1. 查看docker进程 sudo docker ps –a 1.2. 附着到容器上 Sudo d ...

  7. docker exec 运行命令

    docker:/root/sbin# docker exec -it 17aaf60ee3a1 /sbin/ifconfig -a eth1 Link encap:Ethernet HWaddr 22 ...

  8. docker 学习笔记20:docker守护进程的配置与启动

    安装好docker后,需要启动docker守护进程.有多种启动方式. 一.服务的方式 因为docker守护进程被安装成服务.所以,可以通过服务的方式启停docker守护进程,包括查看状态. sudo ...

  9. docker exec 系统找不到指定的路径。

    相关问题和答案 >docker exec -it a1 echo "hello..." > /var/www/html/index.html 系统找不到指定的路径. & ...

随机推荐

  1. 教你使用SQL数据库复制系列(1-7)

    SQL Server 复制系列(文章索引) 一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 前言(Introduction) 复制逻辑结构图(Construction) ...

  2. 显示隐藏火车头快捷键Ctrl+t

    今天ytkah在使用火车头的时候也使用了Photoshop,用了组合键Ctrl+t来进行调整图层的大小,可能多按了几次的缘故吧,触发了火车头的隐藏老板键,找了半天也找到,因为当时编辑的任务还没保存,不 ...

  3. 两个js冲突怎么解决?试试这四个方法

    两个js冲突很让前端头疼,虽然jquery是通用的,但调用不同经常会出问题.jQuery是目前流行的JS封装包,简化了很多复杂的JS程序,JQuery讲浏览器DOM树定义为$,通过$来获取各个子节点. ...

  4. 20180820 JS 片段

    $.post异步发送容易引起后台没有处理完,就提示错误异常.在不必要的情况下,请采用.同步的方式 $.ajaxSetup({ async: false }); 但在$.post结束后记得恢复系统默认的 ...

  5. what's the 跨期套利

    出自 MBA智库百科(https://wiki.mbalib.com/) 跨期套利的定义 跨期套利是套利交易中最普遍的一种,是股指期货的跨期套利(Calendar Spread Arbitrage)即 ...

  6. 006-UDP用户数据报文协议

    一.概述 用户数据报协议(英语:User Datagram Protocol,缩写为UDP),又称用户数据报文协议,是一个简单的面向数据报的传输层协议,正式规范为RFC 768. 在TCP/IP模型中 ...

  7. 【Java】-NO.16.EBook.4.Java.1.010-【疯狂Java讲义第3版 李刚】- 异常

    1.0.0 Summary Tittle:[Java]-NO.16.EBook.4.Java.1.010-[疯狂Java讲义第3版 李刚]- 异常 Style:EBook Series:Java Si ...

  8. VS中去掉空格虚点

    Ctrl + R+W 可以在VS中添加或移除 空格虚点.

  9. iOS 阅读唐巧博客心得

    1. iOS 开发中的争议(一) http://blog.devtang.com/2015/03/15/ios-dev-controversy-1/ 文中提及到,在使用的时候,应该是使用self.pr ...

  10. svn中给个地址,然后把自己建立的项目拖进去

    1.首先checkout 那个地址就会得到一个空的文件夹(里面有.svn文件) 2.把你的项目copy一下,粘贴到你chekout的文件夹里面,所有文件都是?,然后选中全部,点击add,然后在comm ...