Docker技術原理

🏡Docker概念
📁Docker is an open-source project that automates the deployment of applications indise software containers,by providing an additional layer of abstraction and automation of operating-system-level virtualization on Linux.
📁Docker是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的容器中,然後發佈到任何流行的LInux及其上,也可以實現虛擬化.容器是完全使用沙箱機制,相互之間不會有任何接口(類似iPhone的app).幾乎沒有性能開銷,可以很容易地在機器和數據中心中運行.
在這裏插入圖片描述
Docker 的出現一定是因爲目前的後端在開發和運維階段確實需要一種虛擬化技術解決開發環境和生產環境環境一致的問題,通過 Docker 我們可以將程序運行的環境也納入到版本控制中,排除因爲環境造成不同運行結果的可能.但是上述需求雖然推動了虛擬化技術的產生,但是如果沒有合適的底層技術支撐,那麼我們仍然得不到一個完美的產品.
🏡Namespaces
命名空間 (namespaces) 是 Linux 爲我們提供的用於分離進程樹、網絡接口、掛載點以及進程間通信等資源的方法.在日常使用 Linux 或者 macOS 時,我們並沒有運行多個完全分離的服務器的需要,但是如果我們在服務器上啓動了多個服務,這些服務其實會相互影響的,每一個服務都能看到其他服務的進程,也可以訪問宿主機器上的任意文件,這是很多時候我們都不願意看到的,我們更希望運行在同一臺機器上的不同服務能做到完全隔離,就像運行在多臺不同的機器上一樣.
在這裏插入圖片描述
在這種情況下,一旦服務器上的某一個服務被入侵,那麼入侵者就能夠訪問當前機器上的所有服務和文件,這也是我們不想看到的,而Docker其實就通過Linux的Namespaces對不同的容器實現了隔離.
Linux的命名空間機制提供了以下其中不同的命名空間:

Namespace 系統調用參數 功能 隔離內容
IPC CLONE_NEWIPC 保證容器內的進程能夠相互通信,但是不能跨容器訪問其他容器的數據 信號量、消息隊列和共享內存
Mount CLONE_NEWNS 獨立的根文件系統,以實現在容裏面啓動服務並且構建出容器的運行環境 掛載點(文件系統)
UTS CLONE_NEWUTS 用於系統標識,包含主機名和域名,用來唯一標識獨立於宿主機系統和運行在其上的其他容器 主機名或域名
PID CLONE_NEWPID 每個容器處有一個PID爲1的進程,用來管理進程的創建和回收 進程編號
Network CLONE_NEWNET 網絡是容器中非常重要的一環,每個容器都類似於虛擬機一樣有自己的網卡、監聽端口、TCP/IP協議棧等,在運行容器時會自動生成一些防火牆規則用於和外界通訊 網絡設備、網絡棧、端口等
User CLONE_NEWUSER 每個容器中都有單獨的用戶和組,和宿主機並不衝突,只是會把用戶的作用範圍限制在每個容器內 用戶和用戶組

🏡CGroups
通過Linux的命名空間爲新創建的進程隔離了文件系統、網絡並與宿主機器之間的進程相互隔離,但是命名空間並不能夠爲我們提供物力資源上的隔離,比如CPU或者內存,如果同一臺機器上運行了多個對彼此以及宿主機器一無所知的容器,這些容器卻共同佔用了宿主機器的物理資源.
在這裏插入圖片描述
如果其中的一個容器正在執行CPU密集型的任務,那麼就會影響其他容器中任務的性能與執行效率,導致多個容器互相影響並且搶佔資源.如何對多個容器的資源使用進行限制就成了解決進程虛擬資源隔離之後的主要問題,而Control Groups(簡稱CGroups)就是能夠隔離宿主機器上的物理資源,例如CPU、內存、磁盤I/O和網絡帶寬.
每一個CGroup都是一組被相同的標準和參數限制的進程,不同的CGroup支架是由層級關係的,也就是說它們之間可以從父類繼承一些用於限制資源使用的標準和參數.
在這裏插入圖片描述
Linux的CGroup能夠爲一組進程分配資源,也就是我們再上面提到的CPU、內存、網絡帶寬等資源,通過對資源的分配,CGroup能夠提供以下的幾種功能:
在這裏插入圖片描述
在Cgroup中,所有的任務就是一個系統的一個進程,而CGroup就是一組按照某種標準劃分的進程,在CGroup這種機制中,所有的資源控制都是以CGroup作爲單位實現的,每一個進程都可以隨時加入一個CGroup,也可以隨時退出一個CGroup.
CGroup介紹、應用實例以及原理描述
Linux使用文件系統來實現CGroup,可以直接使用如下命令查看當前CGroup中有哪些子系統.
在這裏插入圖片描述
大多數Linux的發行版都有這非常相似的子系統,之所以將上面的cpuset、cpu等東西稱作子系統,是因爲它們能夠爲相對應的控制組分配資源並限制資源的使用.
如果要創建一個新的CGroup只需要在想要分配或者限制資源的子系統下面創建一個新的文件夾,然後這個文件夾就會自動出現很多內容.如果在Linux上安裝了Docker,就會發現所有的子系統目錄下都有一個名爲docker的文件夾:
在這裏插入圖片描述
9c3057xxx 其實就是我們運行的一個 Docker 容器,啓動這個容器時,Docker 會爲這個容器創建一個與容器標識符相同的 CGroup,在當前的主機上 CGroup 就會有以下的層級關係:
在這裏插入圖片描述
每一個 CGroup 下面都有一個 tasks 文件,其中存儲着屬於當前控制組的所有進程的 pid,作爲負責 cpu 的子系統,cpu.cfs_quota_us 文件中的內容能夠對 CPU 的使用作出限制,如果當前文件的內容爲 50000,那麼當前控制組中的全部進程的 CPU 佔用率不能超過 50%.
如果系統管理員想要控制 Docker 某個容器的資源使用率就可以在 docker 這個父控制組下面找到對應的子控制組並且改變它們對應文件的內容,當然我們也可以直接在程序運行時就使用參數,讓 Docker 進程去改變相應文件中的內容.
在這裏插入圖片描述
當我們使用Dokcer關閉掉正在運行的容器時,Docker的子控制組對應的文件夾也會被Docker進程移除,Docker在使用CGroup時也只是做了一些創建文件夾改變文件內容的文件操作,不過CGroup的使用也確實解決了限制子容器資源佔用的問題,系統管理員能夠爲多個容器合理分配的資源並且不會出現多個容器互相搶佔資源的問題.


🏡UnionFS
Linux的命名空間和控制組分別解決了不同資源隔離的問題,前者解決了進程、網絡以及文件系統的隔離,後者實現了CPU、內存等資源的隔離,但是在Docker中還有一個非常重要的問題需要解決,就是鏡像.
Docker鏡像其實本質就是一個壓縮包,我們可以使用下面的命令講一個Docker鏡像中的文件導出:
在這裏插入圖片描述
可以看到這個busybox鏡像中的目錄結構和Linux操作系統的根目錄中的內容並沒有太多的卻別,可以說Docker鏡像就是一個文件.

  • 💿存儲驅動
    Docker使用了一系列不同的存儲驅動管理鏡像內的文件系統並運行容器,這些存儲驅動與Docker卷(Volume)有些不同,存儲引擎管理者能夠在多個容器之間共享的存儲.
    首先需要理解 Docker 是如何構建並且存儲鏡像的,也需要明白 Docker 的鏡像是如何被每一個容器所使用的;Docker 中的每一個鏡像都是由一系列只讀的層組成的,Dockerfile 中的每一個命令都會在已有的只讀層上創建一個新的層:
    在這裏插入圖片描述
    容器中的每一層都只對當前容器進行了非常小的修改,上述的 Dockerfile 文件會構建一個擁有四層 layer 的鏡像:
    在這裏插入圖片描述
    當鏡像被 docker run 命令創建時就會在鏡像的最上層添加一個可寫的層,也就是容器層,所有對於運行時容器的修改其實都是對這個容器讀寫層的修改.
    容器和鏡像的區別就在於,所有的鏡像都是隻讀的,而每一個容器其實等於鏡像加上一個可讀寫的層,也就是同一個鏡像可以對應多個容器.
    在這裏插入圖片描述
  • 💿AUFS
    UnionFS其實是一種爲Linux操作系統設計的用於把多個文件系統聯合到同一個掛載點的文件系統服務.而AUFS即Advanced UnionFSQISHI JIUSHI UnionFS的升級版,能夠提供更優秀的性能和效率.
    AUFS 作爲聯合文件系統,它能夠將不同文件夾中的層聯合(Union)到了同一個文件夾中,這些文件夾在 AUFS 中稱作分支,整個『聯合』的過程被稱爲聯合掛載(Union Mount):
    在這裏插入圖片描述
    每一個鏡像層或者容器層都是 /var/lib/docker/ 目錄下的一個子文件夾;在 Docker 中,所有鏡像層和容器層的內容都存儲在 /var/lib/docker/aufs/diff/ 目錄中:
    在這裏插入圖片描述
    而 /var/lib/docker/aufs/layers/ 中存儲着鏡像層的元數據,每一個文件都保存着鏡像層的元數據,最後的 /var/lib/docker/aufs/mnt/ 包含鏡像或者容器層的掛載點,最終會被 Docker 通過聯合的方式進行組裝.
    在這裏插入圖片描述
    上圖非常好地展示了組裝的過程,每一個鏡像層都是建立在另一個鏡像層之上的,同時所有的鏡像層都是隻讀的,只有每個容器最頂層的容器層纔可以被用戶直接讀寫,所有的容器都建立在一些底層服務(Kernel)上,包括命名空間,控制組,rootfs等等,這種容器的組裝方式提供了非常大的靈活性,只讀的鏡像層通過共享也能夠減少磁盤的佔用.

🖨總結
Docker目前已經成爲了非常主流的技術,已經在很多成熟公司的生產環境中使用,但是Docker的核心技術其實已經有很多年曆史了,Linux命名空間、控制組和UnionFS三大技術支撐了目前Docker的實現,也是Docker能夠出現的最重要原因.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章