iT邦幫忙

2022 iThome 鐵人賽

DAY 20
0
DevOps

那些關於 docker 你知道與不知道的事系列 第 20

Day 20: 不負責任的 PID 1

  • 分享至 

  • xImage
  •  

昨天我們「似乎」證明了 container 中的 PID 1 有負起 init process 的責任,會接收子孫輩的 orphan process。

我們來換個方式玩玩看,我準備了兩個以 ubuntu:20.04 為 base image 的 Dockerfile:

  1. Dockerfile-bash-exec,並且 build 成 image 名稱為: bash:exec
From ubuntu:20.04
CMD ["sleep", "1000"]
  1. Dockerfile-bash-shell,並且 build 成 image 名稱為: bash:shell
From ubuntu:20.04
CMD sleep 1000

實驗1: 啟動 bash:exec

ubuntu@ip-xxx:~/shellmode-bash$ docker run -d --rm bash:exec
7e7aae9a459587171a3b6473bcdfca9a92cf938bc74bcde7e52bda62a0de1b7a

ubuntu@ip-xxx:~/shellmode-bash$ docker ps
CONTAINER ID   IMAGE       COMMAND        CREATED          STATUS          PORTS     NAMES
7e7aae9a4595   bash:exec   "sleep 1000"   56 seconds ago   Up 55 seconds             epic_payne

ubuntu@ip-xxx:~/shellmode-bash$ docker exec -it 7e7aae9 bash
root@7e7aae9a4595:/# sleep 2000

啟動 bash:exec 後,可以透過 docker ps 觀察到啟動的命令是 sleep 1000,然後用 docker exec 進入這個 container,並且啟動 sleep process。

在 host 的觀察:

ubuntu@ip-xxx:~/shellmode-bash$ ps -eaf
UID          PID    PPID  C STIME TTY          TIME CMD
root       91849       1  0 16:48 ?        00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 7e7aae9a459587
root       91871   91849  0 16:48 ?        00:00:00 sleep 1000
ubuntu     91899   82740  0 16:49 pts/2    00:00:00 docker exec -it 7e7aae9 bash
root       91919   91849  0 16:49 pts/0    00:00:00 bash
root       91927   91919  0 16:49 pts/0    00:00:00 sleep 2000
ubuntu     91936   82095  0 16:50 pts/1    00:00:00 ps -eaf

整理一下:

containerd-shim-runc-v2 (91849)
     \_ sleep 1000 (91871)
     \_ bash (91919)
         \_ sleep 2000 (91927)

一樣來殺掉中間那個 bash (91919):

ubuntu@ip-xxx:~/shellmode-bash$ sudo kill -9 91919
ubuntu@ip-xxx:~/shellmode-bash$ ps -eaf
UID          PID    PPID  C STIME TTY          TIME CMD
root       91849       1  0 16:48 ?        00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 7e7aae9a459587
root       91871   91849  0 16:48 ?        00:00:00 sleep 1000
root       91927   91871  0 16:49 ?        00:00:00 [sleep] <defunct>

登愣,接收是接收了,但卻變成 zombie 了!

containerd-shim-runc-v2 (91849)
     \_ sleep 1000 (91871)
         \_ sleep 2000 (91927) <defunct>

實驗2: 啟動 bash:shell

過程一模一樣,這邊就不加贅述,我們就只看不一樣的地方:

ubuntu@ip-xxx:~/shellmode-bash$ docker run -d --rm bash:shell
ed3be7fcee2c697657eeaba9ce30502ec1116de361d9483a3305bb7ae4334855
ubuntu@ip-xxx:~/shellmode-bash$ docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED         STATUS         PORTS     NAMES
ed3be7fcee2c   bash:shell   "/bin/sh -c 'sleep 1…"   2 seconds ago   Up 2 seconds             cranky_hoover

這邊有個不太一樣的地方,可以看到這次啟動 container 的命令變成了 /bin/sh -c 'sleep 1…,不是 直接執行 sleep 喔,而是用 /bin/sh 來執行 sleep

接著一樣用 docker exec 進入 container,但這次先在 container 裡觀察一下 processes:

ubuntu@ip-xxx:~/shellmode-bash$ docker exec -it ed3be7fcee2c bash
root@ed3be7fcee2c:/# ps -eaf
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 16:54 ?        00:00:00 /bin/sh -c sleep 1000
root           7       1  0 16:54 ?        00:00:00 sleep 1000
root           8       0  0 16:56 pts/0    00:00:00 bash
root          28       8  0 16:58 pts/0    00:00:00 ps -eaf

可以觀察到 container 裡 PID 1 的 process 不是 sleep 喔,而是 /bin/sh。接著執行 sleep,在 host 我們用 ps 觀察一下:

ubuntu@ip-xxx:~/shellmode-bash$ ps -eaf
UID          PID    PPID  C STIME TTY          TIME CMD
root       92040       1  0 16:54 ?        00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id ed3be7fcee2c697657eeaba9ce30502e
root       92060   92040  0 16:54 ?        00:00:00 /bin/sh -c sleep 1000
root       92087   92060  0 16:54 ?        00:00:00 sleep 1000
ubuntu     92102   82740  0 16:56 pts/2    00:00:00 docker exec -it ed3be7fcee2c bash
root       92121   92040  0 16:56 pts/0    00:00:00 bash
root       92172   92121  0 17:00 pts/0    00:00:00 sleep 2000
ubuntu     92174   82095  0 17:00 pts/1    00:00:00 ps -eaf

整理一下:

containerd-shim-runc-v2 (92040)
     \_ /bin/sh (92060)
          \_ sleep 1000 (92087)
     \_ bash (92121)
         \_ sleep 2000 (92172)

來殺掉中間這個 bash (92121):

ubuntu@ip-xxx:~/shellmode-bash$ sudo kill -9 92121
ubuntu@ip-xxx:~/shellmode-bash$ ps -eaf
UID          PID    PPID  C STIME TTY          TIME CMD
root       92040       1  0 16:54 ?        00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id ed3be7fcee2c697657eeaba9ce30502e
root       92060   92040  0 16:54 ?        00:00:00 /bin/sh -c sleep 1000
root       92087   92060  0 16:54 ?        00:00:00 sleep 1000

變成這樣了:

containerd-shim-runc-v2 (92040)
     \_ /bin/sh (92060)
          \_ sleep 1000 (92087)

我們殺掉的是 bash(92121),但連 sleep 2000 (92172) 也都被回收了。


來個小小的結論,sleep 1000 看來是無法當一個負責任的 PID 1,雖然他還是會接收孤兒,但並不會好好地回收殭屍。在實驗 2 中,實際上的 PID 1 並不是 sleep,而是 /bin/sh,看來 /bin/sh 是有好好地處理殭屍的。

不過不過,我這邊突然改用 ubuntu:20.04 進行實驗,不知道大家有沒有覺得很奇怪?之前不是一直都用 alpine 嗎?如果用 alpine 做一樣的實驗,結果會不一樣嗎?


上一篇
Day 19: Container 中 PID 1 的 process 會擔負起 init process 的責任嗎?
下一篇
Day 21: container 裡誰是 PID 1 有差嗎?
系列文
那些關於 docker 你知道與不知道的事32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言