如果你認真對著前三篇教程做了練習,那麼想必現在對 docker 的使用已經比較熟悉,對於不太複雜的需求也能做到胸有成竹,但是,你還是不敢聲稱熟悉 docker,因為你完全不瞭解 docker 的內部原理,對於你它完全是個孤立的黑匣子。
那麼接下來,我將帶領你去認識它,讓它不再陌生。
首先,容器和虛擬機器的區別是什麼呢?你一定看到過很多答案,說容器更輕量,更快,虛擬機器要虛擬化硬體等等,還有這張經典圖,但是可能你並不是很理解,至少我當時看的一頭霧水。
我們知道,ubuntu 16.04和 ubuntu18.04的核心版本是不一樣的,ubuntu16.04的虛擬機器和 ubuntu18.04的虛擬機器的核心版本也必定不一致。那麼,如果是 ubuntu16.04和 ubuntu18.04的 docker 環境呢?
我們來試一下:檢視linux 系統核心資訊可以使用命令 uname -a,剩下的你應該知道怎麼做了。不知道的話,再去看一下前幾篇。
這是我在 macos上的執行結果:
我們發現,debian 和 ubuntu 的核心版本竟然是一樣的!如果你有興趣,還可以試驗 debian或者其他系統,你會發現他們都是一樣的!
我們知道,作業系統分為核心和使用者程式,進而存在核心空間(kernel space)和使用者空間(user Space)。簡單說,Kernel Space 是 Linux 核心的執行空間,User space 是使用者程式的執行空間。Kernel space 可以執行任意命令,呼叫系統的一切資源;User space 只能執行簡單的運算,不能直接呼叫系統資源,必須透過系統介面(又稱 system call),才能向核心發出指令。
而容器事實上就是一個使用者程式,它同樣透過呼叫系統介面實現功能。對於 docker 而言,如果宿主機是 linux,它就直接使用宿主機核心,如果宿主機是 macos 或者 windows,docker服務會提供一個公用的 linux核心供各容器呼叫,因此你會看到 ubuntu18.04和16.04的核心版本是一致的。
而容器映象裡的檔案,包括了可執行程式以及它的依賴,例如 ubuntu18.04映象,就是把18.04的所有可執行程式以及它們的依賴進行打包,容器啟動的時候檔案被載入進記憶體,事實上就對應著使用者空間,而這些程式的執行,還需要呼叫系統介面。
你一定會說,那現在容器依賴核心介面,如果核心介面變了,容器不就無法正常執行了?
事實上,核心介面的變更是比較慎重、緩慢的,在短時間內,我們可以預期容器能夠正常執行。但是,隨著宿主系統尤其是核心的升級,我們並不能保證 docker 容器永遠可以正常執行。
現在,你應該明白了為什麼ubuntu16.04和18.04的 docker 容器核心版本一樣,那麼,容器和虛擬機器的區別也就明顯了,它們虛擬化的層次並不一樣。
虛擬機器完整虛擬了核心和使用者空間,而 docker 僅僅虛擬了使用者空間,那麼 docker 必然更輕量、更快。
再回頭看第一張圖,也就清晰了。虛擬機器建立在虛擬硬體層之上,每個虛擬機器都有獨立的核心和使用者程式以及依賴庫;而 docker 容器建立在宿主機核心和 docker 服務之上,使用共同的核心,每個容器僅僅是使用者程式、依賴庫不同;再更進一步,普通的程式都使用共同的依賴庫,只有程式檔案不同。
縱觀全域性,從普通的應用程式,到docker 容器,再到虛擬機器技術,無非是對磁碟空間、系統資源和隔離性、安全性的權衡取捨而已。至於 docker 的自動化,對比虛擬機器似乎並不公平,於 Vagrant 這樣的工具相比倒是更加合適。
再解釋下之前的問題,既然 docker容器僅僅是一個程式,與虛擬機器並不一樣,也就不適合以虛擬機器的方式使用 docker。 docker 容器的建立、關閉代價很小,我們應該使用獨立的docker 容器執行獨立的任務,就像之前 mysql、app、nginx各自起獨立的 docker 容器,這樣更方便容器的複用及更新,也方便對系統資源進行管理。
既然 docker 容器只是一個程式,為什麼我們使用的時候感覺和虛擬機器很像?在容器裡使用 ps 看不到其它程式,看不到其它檔案等等。這就涉及到了 linux 核心提供的CGroups機制,它為程式提供了檔案、cpu、記憶體、網路等資源的隔離,是虛擬化技術的基礎,也即是我們第五篇要介紹的內容,敬請期待。
本作品採用《CC 協議》,轉載必須註明作者和本文連結