Docker 架構及工作原理

通過下圖可以得知,Docker 在運行時分為 Docker 引擎(服務端守護進程)客戶端工具,我們日常使用各種 docker 命令,其實就是在使用 客戶端工具Docker 引擎 進行交互。

Client 客戶端

Docker 是一個客戶端-伺服器(C/S)架構程式。Docker 客戶端只需要向 Docker 伺服器或者守護進程發出請求,伺服器或者守護進程將完成所有工作並返回結果。Docker 提供了一個命令行工具 Docker 以及一整套 RESTful API。你可以在同一台宿主機上運行 Docker 守護進程和客戶端,也可以從本地的 Docker 客戶端連接到運行在另一台宿主機上的遠程 Docker 守護進程。

Host 主機(Docker 引擎)

一個物理或者虛擬的機器用於執行 Docker 守護進程和容器。

Image 鏡像

什麼是 Docker 鏡像?簡單的理解,Docker 鏡像就是一個 Linux 的文件系統(Root FileSystem),這個文件系統裡面包含可以運行在 Linux 內核的程式以及相應的數據。

通過鏡像啟動一個容器,一個鏡像就是一個可執行的包,其中包括運行應用程式所需要的所有內容:包含程式碼,運行時間,庫,環境變數和配置文件等。

Docker 把 App 文件打包成為一個鏡像,並且採用類似多次快照的存儲技術,可以實現:

  • 多個 App 可以共用相同的底層鏡像(初始的作業系統鏡像);
  • App 運行時的 IO 操作和鏡像文件隔離;
  • 通過掛載包含不同配置/數據文件的目錄或者卷(Volume),單個 App 鏡像可以用來運行無數個不同業務的容器。

Container 容器

鏡像(Image)和容器(Container)的關係,就像是面向對象程式設計中的類和實例一樣,鏡像是靜態的定義,容器是鏡像運行時的實體。容器可以被創建、啟動、停止、刪除、暫停等。

Docker 面向對象
容器 對象
鏡像

鏡像分層

Docker 支援通過擴展現有鏡像,創建新的鏡像。實際上,Docker Hub 中 99% 的鏡像都是通過在 base 鏡像中安裝和配置需要的軟體構建出來的。

從上圖可以看到,新鏡像是從 base 鏡像一層一層疊加生成的。每安裝一個軟體,就在現有鏡像的基礎上增加一層。

鏡像分層最大的一個好處就是共享資源。比如說有多個鏡像都從相同的 base 鏡像構建而來,那麼 Docker Host 只需在磁碟上保存一份 base 鏡像;同時記憶體中也只需載入一份 base 鏡像,就可以為所有容器服務了。而且鏡像的每一層都可以被共享。

如果多個容器共享一份基礎鏡像,當某個容器修改了基礎鏡像的內容,比如 /etc 下的文件,這時其他容器的 /etc 是不會被修改的,修改只會被限制在單個容器內。這就是容器 Copy-on-Write 特性。

可寫的容器層

當容器啟動時,一個新的可寫層被載入到鏡像的頂部。這一層通常被稱作「容器層」,「容器層」之下的都叫「鏡像層」。

所有對容器的改動 – 無論添加、刪除、還是修改文件都只會發生在容器層中。只有容器層是可寫的,容器層下面的所有鏡像層都是只讀的

鏡像層數量可能會很多,所有鏡像層會聯合在一起組成一個統一的文件系統。如果不同層中有一個相同路徑的文件,比如 /a,上層的 /a 會覆蓋下層的 /a,也就是說用戶只能訪問到上層中的文件 /a。在容器層中,用戶看到的是一個疊加之後的文件系統。

文件操作 說明
添加文件 在容器中創建文件時,新文件被添加到容器層中。
讀取文件 在容器中讀取某個文件時,Docker 會從上往下依次在各鏡像層中查找此文件。一旦找到,立即將其複製到容器層,然後打開並讀入記憶體。
修改文件 在容器中修改已存在的文件時,Docker 會從上往下依次在各鏡像層中查找此文件。一旦找到,立即將其複製到容器層,然後修改之。
刪除文件 在容器中刪除文件時,Docker 也是從上往下依次在鏡像層中查找此文件。找到後,會在容器層中記錄下此刪除操作。(只是記錄刪除操作)

只有當需要修改時才複製一份數據,這種特性被稱作 Copy-on-Write。可見,容器層保存的是鏡像變化的部分,不會對鏡像本身進行任何修改。

總結下來就是:容器層記錄對鏡像的修改,所有鏡像層都是只讀的,不會被容器修改,所以鏡像可以被多個容器共享。

Volume 數據卷

實際上我們的容器就好像是一個簡易版的作業系統,只不過系統中只安裝了我們的程式運行所需要的環境,前邊說到我們的容器是可以刪除的,那如果刪除了,容器中的程式產生的需要持久化的數據怎麼辦呢?容器運行的時候我們可以進容器去查看,容器一旦刪除就什麼都沒有了。

所以數據卷就是來解決這個問題的,是用來將數據持久化到我們宿主機上,與容器間實現數據共享,簡單的說就是將宿主機的目錄映射到容器中的目錄,應用程式在容器中的目錄讀寫數據會同步到宿主機上,這樣容器產生的數據就可以持久化了,比如我們的資料庫容器,就可以把數據存儲到我們宿主機上的真實磁碟中。

Registry 倉庫

Docker 用 Registry 來保存用戶構建的鏡像。Registry 分為公共和私有兩種。Docker 公司運營公共的 Registry 叫做 Docker Hub。用戶可以在 Docker Hub 註冊帳號,分享並保存自己的鏡像。

Docker 公司提供了公共的鏡像倉庫 //hub.docker.com(Docker 稱之為 Repository)提供了龐大的鏡像集合供使用。

一個 Docker Registry 中可以包含多個倉庫(Repository);每個倉庫可以包含多個標籤(Tag);每個標籤對應一個鏡像。

通常,一個倉庫會包含同一個軟體不同版本的鏡像,而標籤對應該軟體的各個版本。我們可以通過 <倉庫名>:<標籤> 的格式來指定具體是這個軟體哪個版本的鏡像。如果不給出標籤,將以 latest 作為默認標籤。

總結

Docker 官網寫著這樣一句話:Build and Ship any Application Anywhere,再結合剛才我們所理解的內容,總結下來就是:一次構建,到處運行。

此外,Docker 公司提供了公共的鏡像倉庫 //hub.docker.com(Docker 稱之為 Repository),GitHub connect,自動構建鏡像,大大簡化了應用分發、部署、升級流程。加上 Docker 可以非常方便的建立各種自定義的鏡像文件,這些都是 Docker 成為最流行的容器技術的重要因素。

通過以上這些技術的組合,最後的結果就是:絕大部分應用,開發者都可以通過 docker build 創建鏡像,通過 docker push 上傳鏡像,用戶通過 docker pull 下載鏡像,使用 docker run 運行容器應用。用戶不再需要去關心如何搭建環境,如何安裝,如何解決不同發行版的庫衝突——而且通常不會消耗更多的硬體資源,不會明顯降低性能。

從下文開始,我們就進入 Docker 實操部分,先從 Docker 的安裝及配置鏡像加速講起,然後再學習一些鏡像和容器最常用的命令。

本文採用 知識共享「署名-非商業性使用-禁止演繹 4.0 國際」許可協議

大家可以通過 分類 查看更多關於 Docker 的文章。

🤗 您的點贊轉發是對我最大的支援。

📢 掃碼關注 哈嘍沃德先生「文檔 + 影片」每篇文章都配有專門影片講解,學習更輕鬆噢 ~