前言
-
《Docker Practice(Docker從入門到實踐)》學習筆記
這本書講的非常清晰透徹,細節內容也非常全面。因此,關于這本書的學習筆記,我希望可以注重對其邏輯和思維的總結,而不是僅僅羅列知識點。
書中的語言實在是非常簡練且清晰,單純總結成點會缺少很多思維上的邏輯連貫性,完全羅列又會顯得過于復雜。因此我將以下面這種方式來進行學習:- 對重要的知識點或概念進行引用
- 在知識點后加入自己的理解,或是對其概括總結
- 一個知識塊結束,對整個塊的內容總結
Docker定義
Docker 使用 Google 公司推出的 Go 語言 進行開發實現,基于 Linux 內核的 cgroup,namespace,以及 AUFS 類的 Union FS 等技術,對進程進行封裝隔離,屬于操作系統層面的虛擬化技術。由于隔離的進程獨立于宿主和其它的隔離的進程,因此也稱其為容器。
Docker 在容器的基礎上,進行了進一步的封裝,從文件系統、網絡互聯到進程隔離等等,極大的簡化了容器的創建和維護。使得 Docker 技術比虛擬機技術更為輕便、快捷。
Docker的三個基本概念
- 鏡像(
Image
) - 容器(
Container
) - 倉庫(
Repository
)
Docker的這三個基本概念,確定了Docker的整個生命周期,我們不僅僅需要理解每一個單獨的概念,更需要理解這三者之間的相互關系。
Docker鏡像(Image)
操作系統分為內核和用戶空間。對于Linux而言,內核啟動后,掛載
root
文件系統為其提供用戶空間支持。而 Docker 鏡像(Image),就相當于是一個root
文件系統。比如官方鏡像 ubuntu:16.04 就包含了完整的一套 Ubuntu 16.04 最小系統的root
文件系統。
Docker 鏡像是一個特殊的文件系統,除了提供容器運行時所需的程序、庫、資源、配置等文件外,還包含了一些為運行時準備的一些配置參數(如匿名卷、環境變量、用戶等)。鏡像不包含任何動態數據,其內容在構建之后也不會被改變。
- Docker鏡像是一個特殊的文件系統
- 功能: 為容器運行提供必要的(1)程序、庫、資源、配置等文件及(2)配置參數(匿名卷、環境變量、用戶等)
- 要求:
- 不包含動態數據
- 其內容在構建之后不會改變
小結:
這段內容給出了Docker鏡像的定義:Docker鏡像本質是一個文件系統,功能是提供了Docker容器運行所需環境的所有內容,對于鏡像文件的要求是不能包含動態文件且內容構建后不會發生改變。
分層存儲
因為鏡像包含操作系統完整的 root 文件系統,其體積往往是龐大的,因此在 Docker 設計時,就充分利用Union FS的技術,將其設計為分層存儲的架構。
鏡像構建時,會一層層構建,前一層是后一層的基礎。每一層構建完就不會再發生改變,后一層上的任何改變只發生在自己這一層。
在構建鏡像的時候,需要額外小心,每一層盡量只包含該層需要添加的東西,任何額外的東西應該在該層構建結束前清理掉。
分層存儲的特征還使得鏡像的復用、定制變的更為容易。甚至可以用之前構建好的鏡像作為基礎層,然后進一步添加新的層,以定制自己所需的內容,構建新的鏡像。
這部分內容實際是對Docker鏡像的要求做出解釋:包含動態數據必然會導致鏡像文件體積變大,內容在構建之后不發生變化則能保證對鏡像的復用,同時也是Docker本身定位的要求。
Docker容器(Container)
容器與鏡像的關系:
鏡像(Image)和容器(Container)的關系,就像是面向對象程序設計中的 類 和 實例 一樣,鏡像是靜態的定義,容器是鏡像運行時的實體。容器可以被創建、啟動、停止、刪除、暫停等。
容器的本質及特征:
容器的實質是進程,但與直接在宿主執行的進程不同,容器進程運行于屬于自己的獨立的 命名空間。因此容器可以擁有自己的 root 文件系統、自己的網絡配置、自己的進程空間,甚至自己的用戶 ID 空間。
容器內的進程是運行在一個隔離的環境里,使用起來,就好像是在一個獨立于宿主的系統下操作一樣。這種特性使得容器封裝的應用比直接在宿主運行更加安全。
- 容器本質是進程
- 容器基于Docker鏡像,容器進程本身具有程序運行的所有環境,因此獨立運行,與宿主系統同相互隔離。
容器存儲層
每一個容器運行時,是以鏡像為基礎層,在其上創建一個當前容器的存儲層,我們可以稱這個為容器運行時讀寫而準備的存儲層為容器存儲層。
容器存儲層的生存周期和容器一樣,容器消亡時,容器存儲層也隨之消亡。因此,任何保存于容器存儲層的信息都會隨容器刪除而丟失。
按照 Docker 最佳實踐的要求,容器不應該向其存儲層內寫入任何數據,容器存儲層要保持無狀態化。所有的文件寫入操作,都應該使用 數據卷(Volume)、或者綁定宿主目錄,在這些位置的讀寫會跳過容器存儲層,直接對宿主(或網絡存儲)發生讀寫,其性能和穩定性更高。
數據卷的生存周期獨立于容器,容器消亡,數據卷不會消亡。因此,使用數據卷后,容器刪除或者重新運行之后,數據卻不會丟失。
- 定義:以鏡像為基礎層,在其上創建一個當前容器的存儲層
- 生存周期:隨容器的消亡而消亡,存儲的信息也隨容器刪除而丟失
- 要求:容器不應該向其存儲層內寫入任何數據,容器存儲層要保持無狀態化
- 數據存儲:使用 數據卷(Volume)、或者綁定宿主目錄
Docker倉庫(Registry)
鏡像構建完成后,可以很容易的在當前宿主機上運行,但是,如果需要在其它服務器上使用這個鏡像,我們就需要一個集中的存儲、分發鏡像的服務,Docker Registry 就是這樣的服務。
一個 Docker Registry 中可以包含多個倉庫(
Repository
);每個倉庫可以包含多個標簽(Tag
);每個標簽對應一個鏡像。通常,一個倉庫會包含同一個軟件不同版本的鏡像,而標簽就常用于對應該軟件的各個版本。我們可以通過
<倉庫名>:<標簽>
的格式來指定具體是這個軟件哪個版本的鏡像。如果不給出標簽,將以latest
作為默認標簽。以 Ubuntu 鏡像 為例,
ubuntu
是倉庫的名字,其內包含有不同的版本標簽,如,14.04
,16.04
。我們可以通過ubuntu:14.04
,或者ubuntu:16.04
來具體指定所需哪個版本的鏡像。如果忽略了標簽,比如ubuntu
,那將視為ubuntu:latest
。倉庫名經常以 兩段式路徑 形式出現,比如
jwilder/nginx-proxy
,前者往往意味著 Docker Registry 多用戶環境下的用戶名,后者則往往是對應的軟件名。但這并非絕對,取決于所使用的具體 Docker Registry 的軟件或服務。
Docker倉庫的作用是為了讓Docker鏡像可以被廣泛使用,其模式類似于GitHub的功能。
Docker Registry 公開服務
Docker Registry 公開服務是開放給用戶使用、允許用戶管理鏡像的 Registry 服務。一般這類公開服務允許用戶免費上傳、下載公開的鏡像,并可能提供收費服務供用戶管理私有鏡像。
最常使用的 Registry 公開服務是官方的 Docker Hub,這也是默認的 Registry,并擁有大量的高質量的官方鏡像。除此以外,還有 CoreOS 的 Quay.io,CoreOS 相關的鏡像存儲在這里;Google 的 Google Container Registry,Kubernetes 的鏡像使用的就是這個服務。
由于某些原因,在國內訪問這些服務可能會比較慢。國內的一些云服務商提供了針對 Docker Hub 的鏡像服務(
Registry Mirror
),這些鏡像服務被稱為加速器。常見的有 阿里云加速器、DaoCloud 加速器 等。使用加速器會直接從國內的地址下載 Docker Hub 的鏡像,比直接從 Docker Hub 下載速度會提高很多。在 安裝 Dcoekr 一節中有詳細的配置方法。國內也有一些云服務商提供類似于 Docker Hub 的公開服務。比如 時速云鏡像倉庫、網易云鏡像服務、DaoCloud 鏡像市場、阿里云鏡像庫 等。
私有 Docker Registry
除了使用公開服務外,用戶還可以在本地搭建私有 Docker Registry。Docker 官方提供了 Docker Registry 鏡像,可以直接使用做為私有 Registry 服務。在 私有倉庫 一節中,會有進一步的搭建私有 Registry 服務的講解。
開源的 Docker Registry 鏡像只提供了 Docker Registry API 的服務端實現,足以支持
docker
命令,不影響使用。但不包含圖形界面,以及鏡像維護、用戶管理、訪問控制等高級功能。在官方的商業化版本 Docker Trusted Registry 中,提供了這些高級功能。除了官方的 Docker Registry 外,還有第三方軟件實現了 Docker Registry API,甚至提供了用戶界面以及一些高級功能。比如,VMWare Harbor 和 Sonatype Nexus。
總結
Docker的三個概念,鏡像(Image)、容器(Container)和倉庫(Repository),定義了Docker的整個工作模式。鏡像是一個文件系統,為容器提供所需的運行環境;容器運行時基于鏡像提供的環境,從而達到和宿主系統的環境隔離;為了能讓鏡像大量復用和廣泛使用,提出了倉庫的概念,且Docker倉庫和GitHub很相似。
本文內容是從整體上來介紹Docker,說明Docker中三個基本概念的功能和定位,從而在整體上來理解Docker。之后會對各個模塊進行更細致的學習。