網站首頁 編程語言 正文
容器化應用
什么是容器化應用
containerized applications 指容器化的應用,我們常常說使用鏡像打包應用程序,使用 Docker 發布、部署應用程序,那么當你的應用成功在 Docker 上運行時,稱這個應用是 containerized applications。
應用怎么打包
容器化應用的最主要特征是使用鏡像打包應用的運行環境以及應用程序,可以通過 Docker 啟動這個鏡像,進而將 應用程序啟動起來。
將一個應用程序打包為鏡像,大約分為以下過程:
- 編寫 Dockerfile 文件 -- 定義構建鏡像的流程
- 選擇一個基礎鏡像(操作系統) -- 操作系統
- 安裝應用的需要的環境 -- 運行環境
- 復制程序文件 -- 應用程序
- 啟動 Dockerfile -- 生成鏡像
操作系統運行環境Web程序(C#)Ubuntu 18.04.NET Core Runtime3.1安裝運行環境操作系統運行環境Web程序(C#)
Docker 鏡像組成
以 .NET Core(C#) 程序為例,一個 Docker 鏡像的層次如下圖所示:
在 Docker 鏡像中,操作系統是高度精簡的,可能只有一個精簡的 Shell,甚至沒有 Shell。而且鏡像中的操作系統還不包含內核,容器都是共享所在的宿主機的內核。所以有時會說容器僅包含必要的操作系統(通常只有操作系統文件和文件系統對象),容器中查看到的 Linux 內核版本與宿主機一致。
Docker 鏡像的是由一系統文件組成的。
聯合文件系統
Linux 有名為 Unionfs 的文件系統服務,可以將不同文件夾中的文件聯合到一個文件夾中。Unionfs 有稱為分支的概念,一個分支包含了多個目錄和文件,多個分支可以掛載在一起,在掛載時,可以指定一個分支優先級大于另一個分支,這樣當兩個分支都包含相同的文件名時,一個分支會優先于另一個分支,在合并的目錄中,會看到高優先級分支的文件。
Docker 中,層層組成鏡像的技術也是聯合文件系統,Union File System。Docker 鏡像中的操作系統是根文件系統,在上一小節的圖片中,可以看到有 bin、boot 等目錄。我們都知道,Docker 鏡像是由多層文件組成的,在上面的示例圖片中有三層組成:根文件系統、環境依賴包、應用程序文件。當鏡像層生成后,便不能被修改,如果再進行操作,則會在原來的基礎上生成新的鏡像層,層層聯合,最終生成鏡像。當然生成的鏡像可能會因為層數太多或者操作過多,導致出現大量冗余,鏡像臃腫。
Docker 的鏡像分層是受 Linux Unionfs 啟發而開發的,Docker 支持多種文件聯合系統,如 AUFS、OverlayFS、VFS 等。
Docker 在不同系統中可以選擇的聯合文件系統:
Linux發行版 | 推薦的存儲驅動程序 | 替代驅動程序 |
---|---|---|
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 不支持修改存儲驅動程序,只能使用默認存儲驅動程序。
Linux 內核
既然 Docker 容器需要與 Linux 內核結合才能使用,那么我們看一下 Linux 內核的功能,稍微了解一下 Linux 內核在支撐 Docker 容器運作中起到什么作用。
Linux 內核主要包含以下功能:
內存管理:追蹤記錄有多少內存存儲了什么以及存儲在哪里;
進程管理:確定哪些進程可以使用中央處理器(CPU)、何時使用以及持續多長時間;
設備驅動程序:充當硬件與進程之間的調解程序/解釋程序;
系統調用和安全防護:接受程序請求調用系統服務;
- 文件系統:操作系統中負責管理持久數據的子系統,在 Linux 中,一切皆文件。
Linux 層次結構如下:
Docker 容器中包含了一個操作系統,包含簡單的 shell 或者不包含,其層次結構如圖所示:
Docker 結構
本節將了解 Docker 的組成部件和結構。
Docker 服務與客戶端
Docker 由 Service 和 Client 兩部分組成,在服務器上可以不安裝 Docker Client,可以通過 Http Api 等方式與 Docker Servie 通訊。
在安裝了 Docker 的主機上執行命令?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 套接字或網絡接口(Socket)。Docker 官方的客戶端是一個二進制命令行程序,使用 Go 語言編寫,我們也可以使用 C#、Java 等語言寫一個類似的程序,Docker 客戶端不需要安裝到 Docker Server 所在的主機,Client 跟 Server 可以遠程通訊。
Docker 的客戶端是許多 Docker 用戶與 Docker 交互的主要方式,當我們使用?docker run
?之類的命令時,客戶端會將這些命令發送到 Docker Server,由 Docker Server 解析并執行命令。
Docker for Linux 中最為常見的同主機通訊方式是 Unix 域套接字。很多軟件都支持使用域套接字與 Docker 通訊,例如 CI/CD 軟件 Jenkins,使用域套接字連接 Docker,能夠利用 Docker 啟動容器構建應用程序以及使用 Docker 來做一些不可描述的事情。
容器運行時
容器運行時是提供運行環境并啟動容器的軟件,我們最常聽說的是 Docker,此外還有?containerd、CRI-O?等。可以毫不夸張的說,整個 Kubernetes 建立在容器之上。
默認情況下,Kubernetes 使用 容器運行時接口(Container Runtime Interface,CRI) 來與服務器中容器運行時交互。所以 Kubernetes 支持多種容器軟件,但只能使用一種容器運行時進行工作,在有多個容器運行時的情況下,我們需要指定使用何種運行時,如果你不指定運行時,則 kubeadm 會自動嘗試檢測到系統上已經安裝的運行時, 方法是掃描一組眾所周知的 Unix 域套接字。
Linux 是多進程操作系統,為了讓多個系統中的多個進程能夠進行高效的通訊,出現和很多方法,其中一種是域套接字(Unix domain socket),只能用于在同一計算機中的進程間通訊,但是其效率高于網絡套接字(socket),域套接字不需要經過網絡協議處理,通過系統調用將數據從一個進程復制到另一個進程中。
域套接字使用一個 .sock 文件進行通訊,常見的容器軟件其對應域套接字如下:
運行時 | 域套接字 |
---|---|
Docker | /var/run/dockershim.sock |
containerd | /run/containerd/containerd.sock |
CRI-O | /var/run/crio/crio.sock |
同一主機下常見進程通訊方式有 共享內存、消息隊列、管道通訊(共享文件)。
Unux 域套接字是套接字和管道之間的混合物。 在 Linux 中,有很多進程,為了讓多個進程能夠進行通訊,出現和很多方法,其中一種是套接字(socket)。一般的 socket 都是基于 TCP/IP 的,稱為網絡套接字,可以實現跨主機進程通訊。在 Linux 中有一種套接字,名為域套接字,只能用于在同一計算機中的進程間通訊,但是其效率高于網絡套接字。域套接字使用一個 .sock 文件進行通訊。
當計算機中有多種容器運行時,Kubernetes 默認優先使用 Docker。
如果你想了解 CRI ,請點擊:
https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/container-runtime-interface.md
Docker 引擎
Docker 引擎也可以說是 Docker Server,它由 Docker 守護進程(Docker daemon)、containerd 以及 runc 組成。
當使用 Docker client 輸入命令時,命令會被發送到 Docker daemon ,daemon 會偵聽請求并管理 Docker 對象,daemon 可以管理 鏡像、容器、網絡和存儲卷等。
下面這個圖是新 Docker 版本的結構組成。
Docker 引擎變化
Docker 首次發布時,Docker 引擎由兩個核心組件構成:LXC 和 Docker daemon,這也是很多文章中稱 Docker 是基于 LXC 的原因,舊版本的 Docker 利用了 LXC、cgroups、Linux 內核編寫。接下來我們了解一下 LXC 。
LXC (Linux Container)是 Linux 提供的一種內核虛擬化技術,可以提供輕量級的虛擬化,以便隔離進程和資源,它是操作系統層面上的虛擬化技術。LXC 提供了對諸如命名空間(namespace) 和控制組(cgroups) 等基礎工具的操作能力,它們是基于 Linux 內核的容器虛擬化技術。我們不需要深入了解這個東西。
Docker 一開始是使用 LXC 做的,LXC 是一個很牛逼的開源項目,但是隨著 Docker 的成熟,Docker 開始拋棄 LXC,自己動手手撕容器引擎。
為什么 Docker 要拋棄 LXC 呢?首先,LXC 是基于 Linux 的。這對于一個立志于跨平臺的 Docker 來說是個問題,離開 LXC,怎么在 MAC、Windows 下運行?其次,如此核心的組件依賴于外部工具,這會給項目帶來巨大風險,甚至影響其發展。
Docker 引擎的架構
下面是一張 Docker 的架構圖。
Docker client 和 Docker daemon 在前面已經介紹過了,接下來介紹其他組件。
containerd
containerd 是一個開源容器引擎,是從 Docker 開源出去的。之前有新聞說 Kubernetes 不再支持 Docker,只支持 containerd,很多人以為 Docker 不行了。
一開始 Docker 是一個 “大單體”,隨著 Docker 的成長,Docker 開始進行模塊化,Docker 中的許多模塊都是可替換的,如 Docker 網絡。支持容器運行的核心代碼自然也抽出來,單獨做一個模塊,便是 containerd。Kubernetes 不再支持 Docker,只不過是降低依賴程度,減少對其他模塊的依賴,只集中在 containerd 上。當我們安裝 Docker 時,自然會包含 containerd。如果我們不需要 Docker 太多組件,那么我們可以僅僅安裝 containerd,由 Kubernetes 調度,只不過我們不能使用 Docker client 了。因此可以說,Kubernetes 不再支持 Docker,并不代表會排斥 Docker。
containerd 的主要任務是容器的生命周期管理,如啟動容器、暫停容器、停止容器等。containerd 位于 daemon 和 runc 所在的 OCI 層之間。
shim
shim 它的作用非常單一,那就是實現 CRI 規定的每個接口,然后把具體的 CRI 請求“翻譯”成對后端容器項目的請求或者操作。
這里要區別一下,dockershim 和 containerd-shim,dockershim 是一個臨時性的方案,dockershim 會在 Kubernetes v1.24中 刪除(2022年),這也是 Kubernetes 不再支持 Docker 的另一組件。
?提示
CRI 即 Container Runtime Interface,容器運行時接口,容器引擎要支持 Kubernetes ,需要實現 CRI 接口,例如 runc 、crun 兩種是常見的 Container Runtime。
shim 是容器進程的父進程,shim 的生命周期跟容器一樣長,shim 是一個輕量級的守護進程,它與容器進程緊密相關,但是 shim 與容器中的進程完全分離。shim 可以將容器的 stdin、stdout、srderr 流重定向到日志中,我們使用?docker logs
?即可看到容器輸出到控制臺的流。
關于 shim,我們就先了解到這里,后面會繼續講解一個示例。
runc
runc 實質上是一個輕量級的、針對 Libcontainer 進行了包裝的命令行交互工具,runc 生來只有一個作用——創建容器,即 runc 是一個由于運行容器的命令行工具。
?提示
Libcontainer 取代了早期 Docker 架構中的 LXC。
如果主機安裝了 Docker,我們可以使用?runc --help
?來查看使用說明。我們可以這樣來理解 runc,runc 是在隔離環境生成新的進程的工具,在這個隔離環境中有一個專用的根文件系統(ubuntu、centos等)和新的進程樹,這個進程樹的根進程?PID=1
。
原文鏈接:https://www.cnblogs.com/whuanle/p/15565415.html
相關推薦
- 2022-07-18 Android 解決InputMethodManager 內存泄露問題
- 2022-07-30 react組件的生命周期
- 2022-11-03 Python日期與時間模塊(datetime+time+Calendar+dateuil?)相關使用
- 2022-12-03 linux?shell?編程之函數使用詳解_linux shell
- 2022-04-18 html2canvas 畫圖出現空白的情況,引出圖片跨域的相關問題
- 2022-09-04 關于python?DataFrame的合并方法總結_python
- 2022-04-25 SpringBoot集成redis錯誤問題及解決方法_Redis
- 2022-03-16 Oracle表空間管理和用戶管理介紹(oracle表空間與用戶的關系)
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支