什麼是容器鏡像?
容器是當今 IT 運維的一個關鍵部分。 容器鏡像 包含了一個打包的應用,以及它的依賴關係,還有它在啟動時運行的進程信息。
你可以通過提供一組特殊格式的指令來創建容器鏡像,可以是提交給 註冊中心 ,或者是作為 Dockerfile 保存。例如,這個 Dockerfile 為 PHP Web 應用創建了一個容器:
FROM registry.access.redhat.com/ubi8/ubi:8.1
RUN yum --disableplugin=subscription-manager -y module enable php:7.3
&& yum --disableplugin=subscription-manager -y install httpd php
&& yum --disableplugin=subscription-manager clean all
ADD index.php /var/www/html
RUN sed -i 's/Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf
&& sed -i 's/listen.acl_users = apache,nginx/listen.acl_users =/' /etc/php-fpm.d/www.conf
&& mkdir /run/php-fpm
&& chgrp -R 0 /var/log/httpd /var/run/httpd /run/php-fpm
&& chmod -R g=u /var/log/httpd /var/run/httpd /run/php-fpm
EXPOSE 8080
USER 1001
CMD php-fpm & httpd -D FOREGROUND
這個文件中的每條指令都會在容器鏡像中增加一個 層 。每一層只增加與下面一層的區別,然後,所有這些堆疊在一起,形成一個只讀的容器鏡像。
它是如何工作的?
你需要知道一些關於容器鏡像的事情,按照這個順序理解這些概念很重要:
- 聯合文件系統
- 寫入時複製(COW)
- 疊加文件系統
- 快照器
聯合文件系統
聯合文件系統 (UnionFS)內置於 Linux 內核中,它允許將一個文件系統的內容與另一個文件系統的內容合併,同時保持「物理」內容的分離。其結果是一個統一的文件系統,即使數據實際上是以分支形式組織。
這裡的想法是,如果你有多個鏡像有一些相同的數據,不是讓這些數據再次複製過來,而是通過使用一個叫做 層 的東西來共享。
![UnionFS](/data/attachment/album/202109/08/152744o5se88jz5j3srb4p.png "UnionFS")
每一層都是一個可以在多個容器中共享的文件系統,例如,httpd 基礎層是 Apache 的官方鏡像,可以在任何數量的容器中使用。想像一下,由於我們在所有的容器中使用相同的基礎層,我們節省了多少磁碟空間。
這些鏡像層總是只讀的,但是當我們用這個鏡像創建一個新的容器時,我們會在它上面添加一個薄的可寫層。這個可寫層是你創建、修改、刪除或進行每個容器所需的其他修改的地方。
寫時複製(COW)
當你啟動一個容器時,看起來好像這個容器有自己的整個文件系統。這意味著你在系統中運行的每個容器都需要自己的文件系統副本。這豈不是要佔用大量的磁碟空間,而且還要花費大量的時間讓容器啟動?不是的,因為每個容器都不需要它自己的文件系統副本!
容器和鏡像使用 寫時複製 (COW)機制來實現這一點。寫時複製策略不是複製文件,而是將同一個數據實例分享給多個進程,並且只在一個進程需要修改或寫入數據時進行複製。所有其他進程將繼續使用原始數據。
Docker 對鏡像和容器都使用了寫時複製的機制。為了做到這一點,在舊版本中,鏡像和運行中的容器之間的變化是通過 圖驅動 來跟蹤的,現在則是通過 快照器 來跟蹤。
在運行中的容器中執行任何寫操作之前,要修改的文件的副本被放在容器的可寫層上。這就是發生 寫 的地方。現在你知道為什麼它被稱為「寫時複製」了么。
這種策略既優化了鏡像磁碟空間的使用,也優化了容器啟動時間的性能,並與 UnionFS 一起工作。
疊加文件系統
疊加文件系統 位於現有文件系統的頂部,結合了上層和下層的目錄樹,並將它們作為一個單一的目錄來呈現。這些目錄被稱為 層 。下層保持不被修改。每一層只增加與下一層的差異(計算機術語為 「diff」),這種統一的過程被稱為 聯合掛載 。
最低的目錄或鏡像層被稱為 下層目錄 ,上面的目錄被稱為 上層目錄 。最後的覆蓋層或統一層被稱為 合併層 。
![Layered file system](/data/attachment/album/202109/08/152744f7zx2iu792z91qs9.jpg "Layered file system")
常見的術語包括這些層的定義:
- 基礎層 :是你的文件系統的文件所在的地方。就容器鏡像而言,這個層就是你的基礎鏡像。
- 疊加層 :通常被稱為 容器層 ,因為對運行中的容器所做的所有改變,如添加、刪除或修改文件,都會寫到這個可寫層。對這一層所做的所有修改都存儲在下一層,是基礎層和差異層的聯合視圖。
- 差異層 包含了在疊加層所作的所有修改。如果你寫的東西已經在基礎層了,那麼疊加文件系統就會把文件複製到差異層,並做出你想寫的修改。這被稱為寫時複製。
快照器
通過使用層和圖驅動,容器可以將其更改作為其容器文件系統的一部分來構建、管理和分發。但是使用 圖驅動 的工作真的很複雜,而且容易出錯。 快照器 與圖驅動不同,因為它們不用了解鏡像或容器。
快照器的工作方式與 Git 非常相似,比如有樹的概念,並跟蹤每次提交對樹的改變。一個 快照 代表一個文件系統狀態。快照有父子關係,使用一組目錄。可以在父級和其快照之間進行差異比較(diff
),以創建一個層。
快照器提供了一個用於分配、快照和掛載抽象的分層文件系統的 API。
總結
你現在對什麼是容器鏡像以及它們的分層方法如何使容器可移植有了很好的認識。接下來,我將介紹容器的運行機制和內部結構。
本文基於 techbeatly 的文章,經許可後改編。
via: https://opensource.com/article/21/8/container-image
作者:Nived V 選題:lujun9972 譯者:geekpi 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive