一篇不一样的docker原理解析 提高篇
生活随笔
收集整理的這篇文章主要介紹了
一篇不一样的docker原理解析 提高篇
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在上一篇
一篇不一樣的docker原理解析 - uncle creepy的文章 - 知乎專欄
中,主要討論了容器和虛擬機的區別,在實現細節上并沒有深入,只是點到即止,在這篇提高篇中,將詳細討論容器的實現細節,當然我不希望把文章寫成對于kernel man page的簡單翻譯,所以不熟悉內核和linux api的讀者可以不急著點叉,這會是一篇不一樣的討論容器實現的提高篇。
如圖,linux的啟動流程
在內存中復制一個父進程,得到“子進程”,此時子進程就是父進程上下文的簡單克隆,內容完全一致 設置子進程的 pid,parent_pid,以及其他和父進程不一致的內容
在開始討論前,先拋出一個問題:
- linux啟動流程 中,容器需要使用其中的幾步?
如圖,linux的啟動流程
0 從fork說起
在講解容器之前,先來談談linux實現進程的原理,linux實現進程的方法為fork,實現的方式分為兩個步驟:
1 namespace讓進程隔離更靈活
從進程被制造的步驟可以看出,進程大部分資源和父進程共享,如果需要制造一個看起來像虛擬機的進程,我們需要比普通的進程多做幾步。
- 可以自定義rootfs,比如我們把整個ubuntu發行版的可執行文件以及其他文件系統都放在目錄/home/admin/ubuntu/ 下,當我們重定義rootfs = /home/admin/ubuntu 后,則該文件地址被印射為 "/"
- 把自身pid 印射為0,并看不到其他任何的pid,這樣自身的pid成為系統內唯一存在pid,看起來就像新啟動了系統
- 用戶名隔離,可以把用戶名設置為“root”
- hostname隔離,可以另取一個hostname,成為新啟動進程的hostname
- IPC隔離,隔離掉進程之間的互相通信
- 網絡隔離,隔離掉進程和主機之間的網絡
如果做完這幾步,至少在進程自身看來,和虛擬機執行環境上已經區別不大了,對應到linux系統中,這幾個隔離需要的方法:clone(2) - Linux manual page
而clone方法和fork方法,在復制上下文的時候,調用的都是syscall_clone() 本質上它們是差不多的。
2 其實docker是一個內核的搬運工
所以雖然docker幫助我們準備好了rootfs地址,鏡像里面的文件,以及各種資源隔離的配置,但是在啟動一個容器的時候,它只是調用系統中早已內置的可以隔離資源的方法,而kernel支持這些方法,也是在創建進程的方法上做了一層資源隔離的擴展而已。
這就解釋了docker兩個特性:
- 啟動速度快,因為本質來說容器和進程差別沒有想象中的大,共享了很多代碼,流程也差的不多
- linux內核版本有最低的要求,因為linux是在某個版本后開始支持隔離特性
3 容器內創建進程 --- Think a step further
這是我認為整個容器實現里面最優美的一點:
- 內核開發者實現了容器的資源隔離一系列隔離后,內核開發者就不需要為容器內創建進程單獨再做任何多余的工作了。
- 在fork方法中,第一步就是繼承父進程的一切,而這一切包含了父進程已有的資源隔離,所以容器進程創建的進程天然繼承容器所有的一切資源隔離 ------ 就和虛擬機的pid = 0 的進程創建子進程所擁有的一樣
4 One more thing
讓我們再來看看開篇提出的問題:
linux啟動流程 中,容器需要使用其中的幾步?
看完了fork,clone以及一大堆隔離后,相信讀者很容易有答案了,這中間容器做完了隔離之后就算啟動完畢,根本就不會來做kernel init之類的步驟,所以答案是一步都不用。
5 how to learn more
- 比較除docker外其他的容器類產品,如coreOS,LXC
- 了解linux如何做隔離,請參考:namespaces(7)
- 了解freebsd如何做隔離,請參考:freebsd jail
- docker 其實真正想做的事情是把資源隔離的接口標準化(最新的版本里windows的接口也被抽象到了docker自己的體系),嚴格說它是所有相似資源隔離的一層抽象和搬運工
- docker 鏡像很小的優勢,主要是靠AUFS實現的,本篇不詳細說明,因為AUFS在docker原理介紹的口水文里被用濫了,隨便搜搜到處都是,而且我很不喜歡官方用的集裝箱比喻
總結
以上是生活随笔為你收集整理的一篇不一样的docker原理解析 提高篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一篇不一样的docker原理解析
- 下一篇: 资源隔离之 Linux namespac