【发布时间】:2021-03-01 14:04:40
【问题描述】:
最近我正在学习dumb-init,如果我理解正确,它正在尝试:
- 作为 PID1 运行,就像一个简单的初始化系统(收割僵尸进程)
- 信号代理/转发(bash 不这样做)
在here 和here 中,他们都提到bash 能够收获僵尸进程,所以我正在尝试验证这一点,但无法使其工作。
首先我写了一个简单的 Go 程序,它产生了 10 个僵尸进程:
func main() {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
go func() {
for i := 0; i < 10; i++ {
sleepCmd := exec.Command("sleep", "1")
_ = sleepCmd.Start()
}
}()
fmt.Println("awaiting signal")
sig := <-sigs
fmt.Println()
fmt.Printf("received %s, exiting\n", sig.String())
}
为它构建一个图像:
FROM golang:1.15-alpine3.12 as builder
WORKDIR /
COPY . .
RUN go build -o main main.go
FROM alpine:3.12
RUN apk --no-cache --update add dumb-init bash
WORKDIR /
COPY --from=builder /main /
COPY --from=builder /entrypoint.sh /
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/main"]
如果我运行 docker run -d <image>,它会按预期工作,我可以在 ps 中看到 10 个僵尸进程:
vagrant@vagrant:/vagrant/dumb-init$ ps aux | grep sleep
root 4388 0.0 0.0 0 0 ? Z 13:54 0:00 [sleep] <defunct>
root 4389 0.0 0.0 0 0 ? Z 13:54 0:00 [sleep] <defunct>
root 4390 0.0 0.0 0 0 ? Z 13:54 0:00 [sleep] <defunct>
root 4391 0.0 0.0 0 0 ? Z 13:54 0:00 [sleep] <defunct>
root 4392 0.0 0.0 0 0 ? Z 13:54 0:00 [sleep] <defunct>
root 4393 0.0 0.0 0 0 ? Z 13:54 0:00 [sleep] <defunct>
root 4394 0.0 0.0 0 0 ? Z 13:54 0:00 [sleep] <defunct>
root 4395 0.0 0.0 0 0 ? Z 13:54 0:00 [sleep] <defunct>
root 4396 0.0 0.0 0 0 ? Z 13:54 0:00 [sleep] <defunct>
root 4397 0.0 0.0 0 0 ? Z 13:54 0:00 [sleep] <defunct>
第二步是验证bash 是否真的能够收割进程,所以我将我的 docker 镜像 ENTRYPOINT 更新为 entrypoint.sh,它只是用 bash 包装了我的程序:
#!/bin/bash
/clever
如果我在容器中运行ps,僵尸进程仍然挂在那里:
/ # ps
PID USER TIME COMMAND
1 root 0:00 {entrypoint.sh} /bin/bash /entrypoint.sh
7 root 0:00 /clever
13 root 0:00 [sleep]
14 root 0:00 [sleep]
15 root 0:00 [sleep]
16 root 0:00 [sleep]
17 root 0:00 [sleep]
18 root 0:00 [sleep]
19 root 0:00 [sleep]
20 root 0:00 [sleep]
21 root 0:00 [sleep]
22 root 0:00 [sleep]
31 root 0:00 /bin/sh
39 root 0:00 ps
尝试了其他一些方法,但仍然无法弄清楚如何正确获取僵尸进程。
感谢您的帮助。
【问题讨论】:
-
子进程的父进程ID是多少?在您最后的
ps列表中,启动进程仍在运行(pid 7),我希望它是sleep进程(pid 13、14、...)的父进程,这意味着@987654336 @root 进程(pid 1)不会收获它们。 -
要拥有真正的僵尸,父母不应该为孩子
wait而忽略SIGCHLD。杀死父进程后,僵尸进程将作为新的父进程移动到 PID 1。 -
啊,所以我必须杀死 pid7 进程,但是这样做的话,孩子们也会被收割(我猜这与 Go GC 有关?)
标签: bash docker containers zombie-process