Docker容器化應(yīng)用與結(jié)構(gòu)
容器化應(yīng)用
什么是容器化應(yīng)用
containerized applications 指容器化的應(yīng)用,我們常常說使用鏡像打包應(yīng)用程序,使用 Docker 發(fā)布、部署應(yīng)用程序,那么當(dāng)你的應(yīng)用成功在 Docker 上運(yùn)行時(shí),稱這個(gè)應(yīng)用是 containerized applications。
應(yīng)用怎么打包
容器化應(yīng)用的最主要特征是使用鏡像打包應(yīng)用的運(yùn)行環(huán)境以及應(yīng)用程序,可以通過 Docker 啟動(dòng)這個(gè)鏡像,進(jìn)而將 應(yīng)用程序啟動(dòng)起來。
將一個(gè)應(yīng)用程序打包為鏡像,大約分為以下過程:
- 編寫 Dockerfile 文件 -- 定義構(gòu)建鏡像的流程
- 選擇一個(gè)基礎(chǔ)鏡像(操作系統(tǒng)) -- 操作系統(tǒng)
- 安裝應(yīng)用的需要的環(huán)境 -- 運(yùn)行環(huán)境
- 復(fù)制程序文件 -- 應(yīng)用程序
- 啟動(dòng) Dockerfile -- 生成鏡像
操作系統(tǒng)運(yùn)行環(huán)境Web程序(C#)Ubuntu 18.04.NET Core Runtime3.1安裝運(yùn)行環(huán)境操作系統(tǒng)運(yùn)行環(huán)境Web程序(C#)
Docker 鏡像組成
以 .NET Core(C#) 程序?yàn)槔?,一個(gè) Docker 鏡像的層次如下圖所示:
在 Docker 鏡像中,操作系統(tǒng)是高度精簡的,可能只有一個(gè)精簡的 Shell,甚至沒有 Shell。而且鏡像中的操作系統(tǒng)還不包含內(nèi)核,容器都是共享所在的宿主機(jī)的內(nèi)核。所以有時(shí)會(huì)說容器僅包含必要的操作系統(tǒng)(通常只有操作系統(tǒng)文件和文件系統(tǒng)對象),容器中查看到的 Linux 內(nèi)核版本與宿主機(jī)一致。
Docker 鏡像的是由一系統(tǒng)文件組成的。
聯(lián)合文件系統(tǒng)
Linux 有名為 Unionfs 的文件系統(tǒng)服務(wù),可以將不同文件夾中的文件聯(lián)合到一個(gè)文件夾中。Unionfs 有稱為分支的概念,一個(gè)分支包含了多個(gè)目錄和文件,多個(gè)分支可以掛載在一起,在掛載時(shí),可以指定一個(gè)分支優(yōu)先級大于另一個(gè)分支,這樣當(dāng)兩個(gè)分支都包含相同的文件名時(shí),一個(gè)分支會(huì)優(yōu)先于另一個(gè)分支,在合并的目錄中,會(huì)看到高優(yōu)先級分支的文件。
Docker 中,層層組成鏡像的技術(shù)也是聯(lián)合文件系統(tǒng),Union File System。Docker 鏡像中的操作系統(tǒng)是根文件系統(tǒng),在上一小節(jié)的圖片中,可以看到有 bin、boot 等目錄。我們都知道,Docker 鏡像是由多層文件組成的,在上面的示例圖片中有三層組成:根文件系統(tǒng)、環(huán)境依賴包、應(yīng)用程序文件。當(dāng)鏡像層生成后,便不能被修改,如果再進(jìn)行操作,則會(huì)在原來的基礎(chǔ)上生成新的鏡像層,層層聯(lián)合,最終生成鏡像。當(dāng)然生成的鏡像可能會(huì)因?yàn)閷訑?shù)太多或者操作過多,導(dǎo)致出現(xiàn)大量冗余,鏡像臃腫。
Docker 的鏡像分層是受 Linux Unionfs 啟發(fā)而開發(fā)的,Docker 支持多種文件聯(lián)合系統(tǒng),如 AUFS、OverlayFS、VFS 等。
Docker 在不同系統(tǒng)中可以選擇的聯(lián)合文件系統(tǒng):
Linux發(fā)行版 | 推薦的存儲(chǔ)驅(qū)動(dòng)程序 | 替代驅(qū)動(dòng)程序 |
---|---|---|
Ubuntu | overlay2 | overlay, devicemapper, aufs, zfs,vfs |
Debian | overlay2 | overlay, devicemapper, aufs,vfs |
CentOS | overlay2 | overlay, devicemapper, zfs,vfs |
提示
Docker Desktop for Mac 和 Docker Desktop for Windows 不支持修改存儲(chǔ)驅(qū)動(dòng)程序,只能使用默認(rèn)存儲(chǔ)驅(qū)動(dòng)程序。
Linux 內(nèi)核
既然 Docker 容器需要與 Linux 內(nèi)核結(jié)合才能使用,那么我們看一下 Linux 內(nèi)核的功能,稍微了解一下 Linux 內(nèi)核在支撐 Docker 容器運(yùn)作中起到什么作用。
Linux 內(nèi)核主要包含以下功能:
內(nèi)存管理:追蹤記錄有多少內(nèi)存存儲(chǔ)了什么以及存儲(chǔ)在哪里;
進(jìn)程管理:確定哪些進(jìn)程可以使用中央處理器(CPU)、何時(shí)使用以及持續(xù)多長時(shí)間;
設(shè)備驅(qū)動(dòng)程序:充當(dāng)硬件與進(jìn)程之間的調(diào)解程序/解釋程序;
系統(tǒng)調(diào)用和安全防護(hù):接受程序請求調(diào)用系統(tǒng)服務(wù);
- 文件系統(tǒng):操作系統(tǒng)中負(fù)責(zé)管理持久數(shù)據(jù)的子系統(tǒng),在 Linux 中,一切皆文件。
Linux 層次結(jié)構(gòu)如下:
Docker 容器中包含了一個(gè)操作系統(tǒng),包含簡單的 shell 或者不包含,其層次結(jié)構(gòu)如圖所示:
Docker 結(jié)構(gòu)
本節(jié)將了解 Docker 的組成部件和結(jié)構(gòu)。
Docker 服務(wù)與客戶端
Docker 由 Service 和 Client 兩部分組成,在服務(wù)器上可以不安裝 Docker Client,可以通過 Http Api 等方式與 Docker Servie 通訊。
在安裝了 Docker 的主機(jī)上執(zhí)行命令 docker version
查看版本號。
Client: Docker Engine - Community Version: 20.10.7 API version: 1.41 Go version: go1.13.15 Git commit: f0df350 Built: Wed Jun 2 11:58:10 2021 OS/Arch: linux/amd64 Context: default Experimental: true Server: Docker Engine - Community Engine: Version: 20.10.7 API version: 1.41 (minimum version 1.12) Go version: go1.13.15 Git commit: b0f5bc3 Built: Wed Jun 2 11:56:35 2021 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.4.6 GitCommit: d71fcd7d8303cbf684402823e425e9dd2e99285d runc: Version: 1.0.0-rc95 GitCommit: b9ee9c6314599f1b4a7f497e1f1f856fe433d3b7 docker-init: Version: 0.19.0 GitCommit: de40ad0
Docker 客戶端
要想跟 Docker Server 通訊,可以使用 Restful API、UNIX 套接字或網(wǎng)絡(luò)接口(Socket)。Docker 官方的客戶端是一個(gè)二進(jìn)制命令行程序,使用 Go 語言編寫,我們也可以使用 C#、Java 等語言寫一個(gè)類似的程序,Docker 客戶端不需要安裝到 Docker Server 所在的主機(jī),Client 跟 Server 可以遠(yuǎn)程通訊。
Docker 的客戶端是許多 Docker 用戶與 Docker 交互的主要方式,當(dāng)我們使用 docker run
之類的命令時(shí),客戶端會(huì)將這些命令發(fā)送到 Docker Server,由 Docker Server 解析并執(zhí)行命令。
Docker for Linux 中最為常見的同主機(jī)通訊方式是 Unix 域套接字。很多軟件都支持使用域套接字與 Docker 通訊,例如 CI/CD 軟件 Jenkins,使用域套接字連接 Docker,能夠利用 Docker 啟動(dòng)容器構(gòu)建應(yīng)用程序以及使用 Docker 來做一些不可描述的事情。
容器運(yùn)行時(shí)
容器運(yùn)行時(shí)是提供運(yùn)行環(huán)境并啟動(dòng)容器的軟件,我們最常聽說的是 Docker,此外還有 containerd、CRI-O 等??梢院敛豢鋸埖恼f,整個(gè) Kubernetes 建立在容器之上。
默認(rèn)情況下,Kubernetes 使用 容器運(yùn)行時(shí)接口(Container Runtime Interface,CRI) 來與服務(wù)器中容器運(yùn)行時(shí)交互。所以 Kubernetes 支持多種容器軟件,但只能使用一種容器運(yùn)行時(shí)進(jìn)行工作,在有多個(gè)容器運(yùn)行時(shí)的情況下,我們需要指定使用何種運(yùn)行時(shí),如果你不指定運(yùn)行時(shí),則 kubeadm 會(huì)自動(dòng)嘗試檢測到系統(tǒng)上已經(jīng)安裝的運(yùn)行時(shí), 方法是掃描一組眾所周知的 Unix 域套接字。
Linux 是多進(jìn)程操作系統(tǒng),為了讓多個(gè)系統(tǒng)中的多個(gè)進(jìn)程能夠進(jìn)行高效的通訊,出現(xiàn)和很多方法,其中一種是域套接字(Unix domain socket),只能用于在同一計(jì)算機(jī)中的進(jìn)程間通訊,但是其效率高于網(wǎng)絡(luò)套接字(socket),域套接字不需要經(jīng)過網(wǎng)絡(luò)協(xié)議處理,通過系統(tǒng)調(diào)用將數(shù)據(jù)從一個(gè)進(jìn)程復(fù)制到另一個(gè)進(jìn)程中。
域套接字使用一個(gè) .sock 文件進(jìn)行通訊,常見的容器軟件其對應(yīng)域套接字如下:
運(yùn)行時(shí) | 域套接字 |
---|---|
Docker | /var/run/dockershim.sock |
containerd | /run/containerd/containerd.sock |
CRI-O | /var/run/crio/crio.sock |
同一主機(jī)下常見進(jìn)程通訊方式有 共享內(nèi)存、消息隊(duì)列、管道通訊(共享文件)。
Unux 域套接字是套接字和管道之間的混合物。 在 Linux 中,有很多進(jìn)程,為了讓多個(gè)進(jìn)程能夠進(jìn)行通訊,出現(xiàn)和很多方法,其中一種是套接字(socket)。一般的 socket 都是基于 TCP/IP 的,稱為網(wǎng)絡(luò)套接字,可以實(shí)現(xiàn)跨主機(jī)進(jìn)程通訊。在 Linux 中有一種套接字,名為域套接字,只能用于在同一計(jì)算機(jī)中的進(jìn)程間通訊,但是其效率高于網(wǎng)絡(luò)套接字。域套接字使用一個(gè) .sock 文件進(jìn)行通訊。
當(dāng)計(jì)算機(jī)中有多種容器運(yùn)行時(shí),Kubernetes 默認(rèn)優(yōu)先使用 Docker。
如果你想了解 CRI ,請點(diǎn)擊:
Docker 引擎
Docker 引擎也可以說是 Docker Server,它由 Docker 守護(hù)進(jìn)程(Docker daemon)、containerd 以及 runc 組成。
當(dāng)使用 Docker client 輸入命令時(shí),命令會(huì)被發(fā)送到 Docker daemon ,daemon 會(huì)偵聽請求并管理 Docker 對象,daemon 可以管理 鏡像、容器、網(wǎng)絡(luò)和存儲(chǔ)卷等。
下面這個(gè)圖是新 Docker 版本的結(jié)構(gòu)組成。
Docker 引擎變化
Docker 首次發(fā)布時(shí),Docker 引擎由兩個(gè)核心組件構(gòu)成:LXC 和 Docker daemon,這也是很多文章中稱 Docker 是基于 LXC 的原因,舊版本的 Docker 利用了 LXC、cgroups、Linux 內(nèi)核編寫。接下來我們了解一下 LXC 。
LXC (Linux Container)是 Linux 提供的一種內(nèi)核虛擬化技術(shù),可以提供輕量級的虛擬化,以便隔離進(jìn)程和資源,它是操作系統(tǒng)層面上的虛擬化技術(shù)。LXC 提供了對諸如命名空間(namespace) 和控制組(cgroups) 等基礎(chǔ)工具的操作能力,它們是基于 Linux 內(nèi)核的容器虛擬化技術(shù)。我們不需要深入了解這個(gè)東西。
Docker 一開始是使用 LXC 做的,LXC 是一個(gè)很牛逼的開源項(xiàng)目,但是隨著 Docker 的成熟,Docker 開始拋棄 LXC,自己動(dòng)手手撕容器引擎。
為什么 Docker 要拋棄 LXC 呢?首先,LXC 是基于 Linux 的。這對于一個(gè)立志于跨平臺(tái)的 Docker 來說是個(gè)問題,離開 LXC,怎么在 MAC、Windows 下運(yùn)行?其次,如此核心的組件依賴于外部工具,這會(huì)給項(xiàng)目帶來巨大風(fēng)險(xiǎn),甚至影響其發(fā)展。
Docker 引擎的架構(gòu)
下面是一張 Docker 的架構(gòu)圖。
Docker client 和 Docker daemon 在前面已經(jīng)介紹過了,接下來介紹其他組件。
containerd
containerd 是一個(gè)開源容器引擎,是從 Docker 開源出去的。之前有新聞?wù)f Kubernetes 不再支持 Docker,只支持 containerd,很多人以為 Docker 不行了。
一開始 Docker 是一個(gè) “大單體”,隨著 Docker 的成長,Docker 開始進(jìn)行模塊化,Docker 中的許多模塊都是可替換的,如 Docker 網(wǎng)絡(luò)。支持容器運(yùn)行的核心代碼自然也抽出來,單獨(dú)做一個(gè)模塊,便是 containerd。Kubernetes 不再支持 Docker,只不過是降低依賴程度,減少對其他模塊的依賴,只集中在 containerd 上。當(dāng)我們安裝 Docker 時(shí),自然會(huì)包含 containerd。如果我們不需要 Docker 太多組件,那么我們可以僅僅安裝 containerd,由 Kubernetes 調(diào)度,只不過我們不能使用 Docker client 了。因此可以說,Kubernetes 不再支持 Docker,并不代表會(huì)排斥 Docker。
containerd 的主要任務(wù)是容器的生命周期管理,如啟動(dòng)容器、暫停容器、停止容器等。containerd 位于 daemon 和 runc 所在的 OCI 層之間。
shim
shim 它的作用非常單一,那就是實(shí)現(xiàn) CRI 規(guī)定的每個(gè)接口,然后把具體的 CRI 請求“翻譯”成對后端容器項(xiàng)目的請求或者操作。
這里要區(qū)別一下,dockershim 和 containerd-shim,dockershim 是一個(gè)臨時(shí)性的方案,dockershim 會(huì)在 Kubernetes v1.24中 刪除(2022年),這也是 Kubernetes 不再支持 Docker 的另一組件。
提示
CRI 即 Container Runtime Interface,容器運(yùn)行時(shí)接口,容器引擎要支持 Kubernetes ,需要實(shí)現(xiàn) CRI 接口,例如 runc 、crun 兩種是常見的 Container Runtime。
shim 是容器進(jìn)程的父進(jìn)程,shim 的生命周期跟容器一樣長,shim 是一個(gè)輕量級的守護(hù)進(jìn)程,它與容器進(jìn)程緊密相關(guān),但是 shim 與容器中的進(jìn)程完全分離。shim 可以將容器的 stdin、stdout、srderr 流重定向到日志中,我們使用 docker logs
即可看到容器輸出到控制臺(tái)的流。
關(guān)于 shim,我們就先了解到這里,后面會(huì)繼續(xù)講解一個(gè)示例。
runc
runc 實(shí)質(zhì)上是一個(gè)輕量級的、針對 Libcontainer 進(jìn)行了包裝的命令行交互工具,runc 生來只有一個(gè)作用——創(chuàng)建容器,即 runc 是一個(gè)由于運(yùn)行容器的命令行工具。
提示
Libcontainer 取代了早期 Docker 架構(gòu)中的 LXC。
如果主機(jī)安裝了 Docker,我們可以使用 runc --help
來查看使用說明。我們可以這樣來理解 runc,runc 是在隔離環(huán)境生成新的進(jìn)程的工具,在這個(gè)隔離環(huán)境中有一個(gè)專用的根文件系統(tǒng)(ubuntu、centos等)和新的進(jìn)程樹,這個(gè)進(jìn)程樹的根進(jìn)程 PID=1
。
到此這篇關(guān)于Docker容器化應(yīng)用與結(jié)構(gòu)的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
使用DockerFile構(gòu)建鏡像與鏡像上傳的實(shí)現(xiàn)步驟
本文主要介紹了使用DockerFile構(gòu)建鏡像與鏡像上傳的實(shí)現(xiàn)步驟,使用Dockerfile好處是自動(dòng)化構(gòu)建,確保環(huán)境的一致性和可重復(fù)性,跟蹤構(gòu)建過程的演化等,文中通過圖文講解的非常詳細(xì),需要的朋友可以參考下2024-02-02Docker Compose引用環(huán)境變量的方法示例
在項(xiàng)目中,往往需要在 docker-compose.yml 文件中使用環(huán)境變量來控制不同的條件和使用場景。本文集中介紹 docker compose 引用環(huán)境變量的方式,感興趣的小伙伴們可以參考一下2018-12-12supervisor下的Dockerfile的多服務(wù)鏡像封裝操作
這篇文章主要介紹了supervisor下的Dockerfile的多服務(wù)鏡像封裝操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11如何使用Docker部署briefing視頻聊天系統(tǒng)
briefing是一個(gè)開源的、安全的直接視頻群聊平臺(tái),這篇文章主要介紹了使用Docker部署briefing視頻聊天系統(tǒng)的詳細(xì)過程,需要的朋友可以參考下2024-01-01