在那篇《使用獨立PID namespace防止誤殺進程》中的最後,我碰到了一個難題,那就是父PID namespace中的進程無法使用進入子PID namespace中通過echo $$ >$pidfile寫入的pid值,進程發信號時,目標pid是和自己處於同樣的PID namespace的。當時我的方法是使用ps+grep的方式去尋找,然而如果遇到多個同名進程的時候,這一招也將碰壁。那麼有沒有別的辦法呢?在我這,這類問題是我最想碰到的啦,哈哈。
還記得進入子PID namespace的bash後,ps -e為何還是父進程的結果嗎?因為mount proc的原因,因為在mount的時候,procfs就初始化了一個mount調用者的PID namespace,進入子PID namespace後,只要你不重新mount proc,那麼/proc下掛載的還是原來的。proc下面有一個self目錄,表示當前的進程,記住,self內部的status文件中獲取到的值,使用的都是這個procfs被掛載時的PID namespace,也就是父PID namespace!於是辦法就是:
echo $(cat /proc/self/status|awk -F ' ' '/PPid/{print $2}') >$pidfile
為何是PPid呢?因為Pid不是腳本的pid,而是cat程序的,由於cat是腳本調用的,自然取它的父進程pid就可以了,執行了上述的指令後,在mount新的procfs就好了。以下是一個測試腳本,在新的PID namespace中執行:
#!/bin/bash
echo $$
# 卸掉新的procfs,暴露出老的procfs
umount /proc
cat /proc/self/status|awk -F ' ' '/PPid/{print $2}'
# 重新掛載新的procfs
mount -t proc proc /proc
cat /proc/self/status|awk -F ' ' '/PPid/{print $2}'
其它的namespace
除了PID namespace,Linux中還有很多namespace,我比較關心的就是網絡這一塊,幸運的是,為了支持虛擬化以及隔離,Linux實現了netns,很簡單,在調用clone的時候,加上CLONE_NEWNET這個flag就可以了,一個獨立的netns,網卡,路由,iptables規則等都是隔離的,一塊物理網卡只能屬於一個namespace,使用下面的命令可以將一塊網卡放到一個子namespace中:
ip link set dev ethX netns $子namespace在父namespace中的pid
這樣做的一個典型應用就是管理接口,帶外管理口可以放在一個獨立的netns中,實現與其它業務網卡的完全隔離。