雖然Docker是經過namespace隔離技術實現容器間進程的隔離,但在運行Docker的主機中,Docker容器內的進程與主機內運行的進程是在同一個namespace(假設叫A)的。雖然在Docker容器內應用進程的父進程都是pid爲1的那個進程(這些進程都是單獨的namespace,這個namespace與前面提到的namespace不是同一個,此處假設爲B),但在namespace A中Docker內容器實際的父進程都是Docker daemon,因爲父進程具備對子進程管理的能力,而子進程不能影響到父進程也不能影響到其餘namespace的進程,因此能實現進程隔離。git
因爲Docker容器內的進程與主機內運行的進程是在同一個namespace,因此在主機中使用ps -ef命令能夠查找出當前系統中運行的全部進程,這些進程包含了完整的與Docker有關的全部進程,在這個namespace中,這些進程的父進程(無論是父進程仍是父父進程)都包含Docker daemon,所以能夠從Docker容器某進程的pid開始,一直找到主機的init進程。github
有時咱們須要根據docker容器進程的pid找到這個容器的容器id,這時經過Linux系統自帶的基礎命令是沒法完成這一操做的。但要想經過pid獲取容器id,辦法仍是有的。其中有兩種可行的辦法。docker
第一種根據:docker inspect <CONTAINER ID>能夠獲取容器的pid,經過docker ps能夠獲取容器的容器id,所以能夠將這兩個命令結合在一塊兒,利用下面的命令行就能夠解決:bash
docker inspect -f '``.`State`.`Pid` ``.`Id`' $(docker ps -a -q) | grep <pid>
可是第一種有一個缺陷,那就是若是這個進程剛好是容器內進程的子進程,那麼這個進程就不會再在主機的namespace中出現,由於只有容器的pid爲1的進程纔會在主機的namespace中出現。所以就必須使用第二種方法。ide
第二種:在Docker Version 1.11後,增長了「containerd」,根據這個特性的實現方式能夠直接經過此進程的父進程的cmdline找到它的容器id。這個方法的缺點就是不適用於Docker Version 1.11以前的版本。函數
根據這兩種特性,編寫了一個Python腳本,用於發現:spa
1.查找pid所對應的容器id,並打印容器的詳細信息命令行
2.獲取此進程的進程樹和含有命令行的進程樹blog
腳本中還隱藏了一種根據進程推導出進程所佔用端口號的函數。這個功能在此腳本中用處不大,但在別處有用處。進程
因爲腳本內容比較長,所以能夠從Gitub上獲取此腳本:https://github.com/DingGuodong/LinuxBashShellScriptForOps/tree/master/projects/LinuxSystemOps/SoftwareManagement/docker。
運行效果圖(若是看不清,請使用新標籤頁打開圖片查看原圖)以下:
Docker Server Version < 1.11
一個第一種方法失敗的例子。
此時,就有必要藉助第二種方法實現(若是看不清,請使用新標籤頁打開圖片查看原圖)。
題外話:
關於init進程,「init進程是全部Linux進程的父進程」,這句話實際上是錯的!也許應該說init進程是全部Linux用戶空間進程的父進程,pid 2 [kthreadd]是Linux系統內核空間進程的父進程。除了2之外,三、四、5等也是特殊進程pid,它們的父進程都不是init。除此以外,0也是一個特殊的進程,用於進程調度。
tag: 經過pid得到容器id,容器namespace,如何查找容器id
--end--