iT邦幫忙

2022 iThome 鐵人賽

DAY 11
0
DevOps

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

Day 11: 繼續來玩一下 PID namespace

  • 分享至 

  • xImage
  •  

接續昨天的實驗,我們用 unshare 指令做出了一個新的 PID namespace,其 id 為 4026532207:

$ sudo lsns -t pid
        NS TYPE NPROCS   PID USER COMMAND
4026531836 pid     111     1 root /sbin/init
4026532207 pid       1 42009 root /bin/bash

讓我們在這個 4026532207 PID namespace 中執行一些時間比較長的指令,例如睡個幾千秒好了:

root@ip-xxx:/home/ubuntu# sleep 2000 &
[1] 13
root@ip-xxx:/home/ubuntu# sleep 2001 &
[2] 15

root@ip-xxx:/home/ubuntu# ps -ef 
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 15:35 pts/1    00:00:00 /bin/bash
root          13       1  0 15:54 pts/1    00:00:00 sleep 2000
root          15       1  0 16:05 pts/1    00:00:00 sleep 2001
root          16       1  0 16:05 pts/1    00:00:00 ps -ef

透過 ps 指令可以觀察到,在這個新的 PID namespace 中,可以看到在這個 namespace 啟動的所有 processes,且除了 /bin/bash (PID 為 1) 的其他 processes 的 PPID 皆為 1。

回到 Host 看一下:

ubuntu@ip-xxx:~$ sudo ps -e -o pidns,pid,ppid,args
     PIDNS     PID    PPID COMMAND
4026531836       1       0 /sbin/init
...略
4026531836   42007   41758 sudo unshare --pid --fork --mount-proc /bin/bash
4026531836   42008   42007 unshare --pid --fork --mount-proc /bin/bash
4026532207   42009   42008 /bin/bash
...略
4026532207   42050   42009 sleep 2000
4026532207   42088   42009 sleep 2001
4026531836   42090   41674 sudo ps -e -o pidns,pid,ppid,args
4026531836   42091   42090 ps -e -o pidns,pid,ppid,args

在 Host 是可以看到在新的這個 PID namespace 4026532207 中啟動的 3 個 processes: /bin/bash, sleep 2000sleep 2001,在 Host 裡 /bin/bash 的 PID 是 42009,sleep 2000sleep 2001 的 PPID 也是 42009。


實驗 2

如果我們在這個新建立的 PID namespace 4026532207 中又再執行一次 unshare 會發生什麼事呢?

root@ip-xxx:/home/ubuntu# unshare --pid --fork --mount-proc /bin/bash
root@ip-xxx:/home/ubuntu#

看起來好像什麼事都沒發生?用 lsns 看看:

root@ip-xxx:/home/ubuntu# lsns -t pid
        NS TYPE NPROCS PID USER COMMAND
4026532209 pid       2   1 root /bin/bash

可以看到,現在的 PID namespace 已經變成 4026532209 了,一樣啟動幾個時間比較長的 process 看看:

root@ip-xxx:/home/ubuntu# sleep 3000 &
[1] 9
root@ip-xxx:/home/ubuntu# sleep 3001 &
[2] 10

root@ip-xxx:/home/ubuntu# ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 16:25 pts/1    00:00:00 /bin/bash
root           9       1  0 16:28 pts/1    00:00:00 sleep 3000
root          10       1  0 16:28 pts/1    00:00:00 sleep 3001
root          11       1  0 16:28 pts/1    00:00:00 ps -ef

回到 Host 看看:

ubuntu@ip-xxx:~$ sudo lsns -t pid
        NS TYPE NPROCS   PID USER COMMAND
4026531836 pid     111     1 root /sbin/init
4026532207 pid       4 42009 root /bin/bash
4026532209 pid       1 42196 root /bin/bash

ubuntu@ip-xxx:~$ sudo ps -e -o pidns,pid,ppid,args | grep 4026532209
4026532209   42196   42195 /bin/bash
4026532209   42208   42196 sleep 3000
4026532209   42209   42196 sleep 3001
4026531836   42216   41674 grep --color=auto 4026532209

果然成功地多了一個新的 PID namespace 了,而且也可以看到 sleep 3000sleep 3001 這兩個 processes。

如果我想觀察看看在 4026532207 中能不能觀察到 4026532209 中的 processes,那就要先回到 4026532207 這個 namespace 中,如果用 exit 指令離開的話,這會終止 /bin/bash 這個 PID 為 1 的 process,這個時候 PID namespace 4026532209 也就跟著不見了(這個之後應該會討論到),因為我目前也不知道其他方式,所以還是先用 exit 離開,並且用背景的方式重新做一個 namespace 出來:

root@ip-xxx:/home/ubuntu# unshare --pid --fork --mount-proc sleep 5000 &
[1] 23

root@ip-xxx:/home/ubuntu# lsns -t pid
        NS TYPE NPROCS PID USER COMMAND
4026532207 pid       3   1 root /bin/bash
4026532209 pid       1  24 root sleep 5000

root@ip-xxx:/home/ubuntu# ps -e -o pidns,pid,ppid,args
     PIDNS     PID    PPID COMMAND
4026532207       1       0 /bin/bash
4026532207      23       1 unshare --pid --fork --mount-proc sleep 5000
4026532209      24      23 sleep 5000
4026532207      26       1 ps -e -o pidns,pid,ppid,args

這邊可以看到,一樣是在 4026532207 PID namespace 中建立了一個新的 PID namespace 4026532209,而在 4026532207 這裡是可以看到 4026532209 裡正在跑的 sleep 5000

回到 Host 看一下:

ubuntu@ip-xxx:~$ sudo lsns -t pid
        NS TYPE NPROCS   PID USER COMMAND
4026531836 pid     116     1 root /sbin/init
4026532207 pid       2 42400 root /bin/bash
4026532209 pid       1 42438 root sleep 5000

到這邊,我們可以先整理幾個觀察與網路上讀到的資料:

  1. PID namespace 之間是有階層關係的,我們 Host 上最一開始的那個 PID namespace 會被稱為 root PID namespace,以我們的例子來說就是 4026531836 (root PID namespace) -> 4026532207 -> 4026532209。
  2. parent PID namespace 是可以「看到」 child PID namespace 中的 processes 的,且可以一路往下到 孫子輩的 namespaces,所以我們在 root PID namespace 4026531836 是可以看到在 4026532209 中的 processes 的。但子孫輩的 PID namespace 是看不到父輩 namespace 中的 processes 的。
  3. 每個 PID namespace 中的第一個 process 的 PID 都是 1,而其 PPID (parent process pid) 會是 0,這也是因為 child PID namespace 看不到 parent PID namespace 的 processes,所以只好把 parent process pid 用 0 來呈現。

實驗 3

讓我們從 root PID namespace 再去建立一個新的 PID namespace:

ubuntu@ip-xxx:~$ sudo unshare --pid --fork --mount-proc /bin/bash
root@ip-xxx:/home/ubuntu# sleep 4000 &
[1] 8
root@ip-xxx:/home/ubuntu# sleep 4001 &
[2] 9

root@ip-xxx:/home/ubuntu# ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 16:44 pts/2    00:00:00 /bin/bash
root           8       1  0 16:45 pts/2    00:00:00 sleep 4000
root           9       1  0 16:45 pts/2    00:00:00 sleep 4001
root          10       1  0 16:45 pts/2    00:00:00 ps -ef

root@ip-xxx:/home/ubuntu# lsns -t pid
        NS TYPE NPROCS PID USER COMMAND
4026532211 pid       4   1 root /bin/bash

在這個新的 PID namespace 4026532211 中是看不到其他 PID namespace 的 processes 的。

回到第一個被建立出來的 PID namespace 4026532207 中:

(實驗做太久,剛剛的 sleep 2000 已經睡醒了,重新跑一下,所以會排在後面)

root@ip-xxx:# ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 16:56 pts/1    00:00:00 /bin/bash
root          23       1  0 17:03 pts/1    00:00:00 unshare --pid --fork --mount-proc sleep 5000
root          24      23  0 17:03 pts/1    00:00:00 sleep 5000
root          29       1  0 17:07 pts/1    00:00:00 sleep 2000
root          30       1  0 17:07 pts/1    00:00:00 sleep 2001
root          32       1  0 17:07 pts/1    00:00:00 ps -ef

這裡也一樣看不到 4026532211 中的 processes(但可以看到自已小孩 4026532209 裡的 process sleep 5000 喔)。

回到 Host:

ubuntu@ip-xxx:~$ sudo lsns -t pid
        NS TYPE NPROCS   PID USER COMMAND
4026531836 pid     116     1 root /sbin/init
4026532207 pid       4 42400 root /bin/bash
4026532209 pid       1 42438 root sleep 5000
4026532211 pid       3 42447 root /bin/bash

ubuntu@ip-xxx:~$ sudo ps -e -o pidns,pid,ppid,args | grep 4026532209
4026532209   42438   42437 sleep 5000
4026531836   42472   41674 grep --color=auto 4026532209

ubuntu@ip-xxx:~$ sudo ps -e -o pidns,pid,ppid,args | grep 4026532211
4026532211   42447   42446 /bin/bash
4026532211   42455   42447 sleep 4000
4026532211   42456   42447 sleep 4001
4026531836   42475   41674 grep --color=auto 4026532211

Host 中可以看到新建立出來的 3 個 PID namespaces,也可以看到 4026532211 中的 processes。

https://ithelp.ithome.com.tw/upload/images/20220926/20151857jUAWkWLaV0.png

用圖片示意一下 PID namespace 的父子關係,到這裡也可以發現,上對下是一覽無遺的,但下無法看到上的,平輩之間的也看不到。


我們利用 unshare 這個指令手動作出了不同的 PID namespace,也在其中執行了一些 processes,好用來觀察這些 processes 在不同的 namespace 中的「可見」程度,之後將會試著用別的方式再驗證一次,也會討論這些實驗跟 container 之間的關聯,是不是很好玩也很期待呢?


上一篇
Day 10: 什麼是 namespace?
下一篇
Day 12: 來用 clone 建立新的 PID namespace
系列文
那些關於 docker 你知道與不知道的事32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言