[英]Is it possible to send string into running process inside docker container?
[英]What is the PID in the host, of a process running inside a Docker container?
Docker 容器中有多个进程在运行,它们的 PID 被隔离在容器命名空间中,有没有办法找出它们在 Docker 主机上的 PID 是什么?
例如,有一个 Apache Web 服务器在 Docker 容器内运行,(我使用来自Docker Hub 的Apache+PHP 映像),当 Apache 启动时,会在容器内创建更多的工作进程。 这些工作进程实际上正在处理传入的请求。 要查看这些进程,我在 docker 容器中运行pstree
:
# pstree -p 1
apache2(1)-+-apache2(8)
|-apache2(9)
|-apache2(10)
|-apache2(11)
|-apache2(12)
`-apache2(20)
父 Apache 进程在容器进程命名空间内的 PID 1 上运行。 但是从主机的角度来看也可以访问,但是它在主机上的PID不同,可以通过运行docker compose
命令来确定:
$ docker inspect --format '{{.State.Pid}}' container
17985
从中我们可以看到容器进程命名空间中的 PID 1 映射到主机上的 PID 17985。 所以我可以在主机上运行pstree
来列出 Apache 进程的子进程:
$ pstree -p 17985
apache2(17985)─┬─apache2(18010)
├─apache2(18011)
├─apache2(18012)
├─apache2(18013)
├─apache2(18014)
└─apache2(18164)
由此我假设容器中的 PID 1 映射到主机上的 PID 17985 的方式相同,它也映射:
(这允许我从 docker 容器调试进程,使用仅在主机上可用的工具,而不是在容器中可用的工具,如 strace)
问题是我不知道假设 pstree 在容器和主机中以相同的顺序列出进程有多安全。
如果有人可以提出一种更可靠的方法来检测在 Docker 容器内运行的特定进程的主机上的 PID 是什么,那就太好了。
您可以查看/proc/<pid>/status
文件来确定命名空间 PID 和全局 PID 之间的映射。 例如,如果在 docker 容器中我启动了几个sleep 900
进程,如下所示:
# docker run --rm -it alpine sh
/ # sleep 900 &
/ # sleep 900 &
/ # sleep 900 &
我可以看到它们在容器中运行:
/ # ps -fe
PID USER TIME COMMAND
1 root 0:00 sh
7 root 0:00 sleep 900
8 root 0:00 sleep 900
9 root 0:00 sleep 900
10 root 0:00 ps -fe
我可以在主机上查看这些:
# ps -fe | grep sleep
root 10394 10366 0 09:11 pts/10 00:00:00 sleep 900
root 10397 10366 0 09:12 pts/10 00:00:00 sleep 900
root 10398 10366 0 09:12 pts/10 00:00:00 sleep 900
对于其中任何一个,我可以查看status
文件以查看命名空间 pid:
# grep -i pid /proc/10394/status
Pid: 10394
PPid: 10366
TracerPid: 0
NSpid: 10394 7
查看NSpid
行,我可以看到在 PID 命名空间中,该进程的 pid 为 7。事实上,如果我在主机上10394
进程10394
:
# kill 10394
然后在容器中,我看到 PID 7 不再运行:
/ # ps -fe
PID USER TIME COMMAND
1 root 0:00 sh
8 root 0:00 sleep 900
9 root 0:00 sleep 900
11 root 0:00 ps -fe
/proc/<pid>/cgroup
获取 docker container_idfunc GetContainerID(pid int32) string {
cgroupPath := fmt.Sprintf("/proc/%s/cgroup", strconv.Itoa(int(pid)))
return getContainerID(cgroupPath)
}
func GetImage(containerId string) string {
if containerId == "" {
return ""
}
image, ok := containerImage[containerId]
if ok {
return image
} else {
return ""
}
}
func getContainerID(cgroupPath string) string {
containerID := ""
content, err := ioutil.ReadFile(cgroupPath)
if err != nil {
return containerID
}
lines := strings.Split(string(content), "\n")
for _, line := range lines {
field := strings.Split(line, ":")
if len(field) < 3 {
continue
}
cgroup_path := field[2]
if len(cgroup_path) < 64 {
continue
}
// Non-systemd Docker
//5:net_prio,net_cls:/docker/de630f22746b9c06c412858f26ca286c6cdfed086d3b302998aa403d9dcedc42
//3:net_cls:/kubepods/burstable/pod5f399c1a-f9fc-11e8-bf65-246e9659ebfc/9170559b8aadd07d99978d9460cf8d1c71552f3c64fefc7e9906ab3fb7e18f69
pos := strings.LastIndex(cgroup_path, "/")
if pos > 0 {
id_len := len(cgroup_path) - pos - 1
if id_len == 64 {
//p.InDocker = true
// docker id
containerID = cgroup_path[pos+1 : pos+1+64]
// logs.Debug("pid:%v in docker id:%v", pid, id)
return containerID
}
}
// systemd Docker
//5:net_cls:/system.slice/docker-afd862d2ed48ef5dc0ce8f1863e4475894e331098c9a512789233ca9ca06fc62.scope
docker_str := "docker-"
pos = strings.Index(cgroup_path, docker_str)
if pos > 0 {
pos_scope := strings.Index(cgroup_path, ".scope")
id_len := pos_scope - pos - len(docker_str)
if pos_scope > 0 && id_len == 64 {
containerID = cgroup_path[pos+len(docker_str) : pos+len(docker_str)+64]
return containerID
}
}
}
return containerID
}
如果您知道主机 pid 或容器 pid,则可以通过搜索主机上的所有 NSpid 映射来找到,如下所示:
# grep NSpid.*10061 /proc/*/status 2> /dev/null
/proc/1194200/status:NSpid: 1194200 10061
2>/dev/null 是忽略导致 grep 错误的短期进程,如下所示: grep: /proc/1588467/status: No such file or directory
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.