Docker技術三大要點:cgroup,namespace和unionFS的理解
www.docker.com的網頁有這樣一張有意思的動畫:
從這張gif圖片,我們不難看出Docker網站想傳達這樣一條資訊, 使用Docker加速了build,ship和run的過程。
Docker最早問世是2013年,以一個開源專案的方式被大家熟知。
Docker的奠基者是dotcloud,一家開發PaaS平臺的技術公司。
不過可惜的是,這家公司把Docker開源之後,於2016年倒閉了,因為其主業務PaaS無法和微軟,亞馬遜等PaaS業界巨頭競爭,不禁讓人唏噓。
Docker其實是容器化技術的具體技術實現之一,採用go語言開發。很多朋友剛接觸Docker時,認為它就是一種更輕量級的虛擬機器,這種認識其實是錯誤的,Docker和虛擬機器有本質的區別。容器本質上講就是執行在作業系統上的一個程式,只不過加入了對資源的隔離和限制。而Docker是基於容器的這個設計思想,基於Linux Container技術實現的核心管理引擎。
為什麼資源的隔離和限制在雲時代更加重要?在預設情況下,一個作業系統裡所有執行的程式共享CPU和記憶體資源,如果程式設計不當,最極端的情況,某程式出現死迴圈可能會耗盡CPU資源,或者由於記憶體洩漏消耗掉大部分系統資源,這在企業級產品場景下是不可接受的,所以程式的資源隔離技術是非常必要的。
我當初剛接觸Docker時,以為這是一項新的技術發明,後來才知道,Linux作業系統本身從作業系統層面就支援虛擬化技術,叫做Linux container,也就是大家到處能看到的LXC的全稱。
LXC的三大特色:cgroup,namespace和unionFS。
cgroup:
CGroups 全稱control group,用來限定一個程式的資源使用,由Linux 核心支援,可以限制和隔離Linux程式組 (process groups) 所使用的物理資源 ,比如cpu,記憶體,磁碟和網路IO,是Linux container技術的物理基礎。
namespace:
另一個維度的資源隔離技術,大家可以把這個概念和我們熟悉的C++和Java裡的namespace相對照。
如果CGroup設計出來的目的是為了隔離上面描述的物理資源,那麼namespace則用來隔離PID(程式ID),IPC,Network等系統資源。
我們現在可以將它們分配給特定的Namespace,每個Namespace裡面的資源對其他Namespace都是透明的。
不同container內的程式屬於不同的Namespace,彼此透明,互不干擾。
我們用一個例子來理解namespace的必要。
假設多個使用者購買了一臺Linux伺服器的Nginx服務,每個使用者在該伺服器上被分配了一個Linux系統的賬號。我們希望每個使用者只能訪問分配給其的資料夾,這當然可以通過Linux檔案系統本身的許可權控制來實現,即一個使用者只能訪問屬於他本身的那些資料夾。
但是有些操作仍然需要系統級別的許可權,比如root,但我們肯定不可能給每個使用者都分配root許可權。因此我們就可以使用namespace技術:
我們能夠為UID = n的使用者,虛擬化一個namespace出來,在這個namespace裡面,該使用者具備root許可權,但是在宿主機上,該UID =n的使用者還是一個普通使用者,也感知不到自己其實不是一個真的root使用者這件事。
同樣的方式可以通過namespace虛擬化程式樹。
在每一個namespace內部,每一個使用者都擁有一個屬於自己的init程式,pid = 1,對於該使用者來說,彷彿他獨佔一臺物理的Linux伺服器。
對於每一個名稱空間,從使用者看起來,應該像一臺單獨的Linux計算機一樣,有自己的init程式(PID為1),其他程式的PID依次遞增,A和B空間都有PID為1的init程式,子容器的程式對映到父容器的程式上,父容器可以知道每一個子容器的執行狀態,而子容器與子容器之間是隔離的。從圖中我們可以看到,程式3在父名稱空間裡面PID 為3,但是在子名稱空間內,他就是1.也就是說使用者從子名稱空間 A 內看程式3就像 init 程式一樣,以為這個程式是自己的初始化程式,但是從整個 host 來看,他其實只是3號程式虛擬化出來的一個空間而已。
看下面的圖加深理解。
父容器有兩個子容器,父容器的名稱空間裡有兩個程式,id分別為3和4, 對映到兩個子名稱空間後,分別成為其init程式,這樣名稱空間A和B的使用者都認為自己獨佔整臺伺服器。
Linux作業系統到目前為止支援的六種namespace:
unionFS:
顧名思義,unionFS可以把檔案系統上多個目錄(也叫分支)內容聯合掛載到同一個目錄下,而目錄的物理位置是分開的。
要理解unionFS,我們首先要認識bootfs和rootfs。
1. boot file system (bootfs):包含作業系統boot loader 和 kernel。使用者不會修改這個檔案系統。
一旦啟動完成後,整個Linux核心載入進記憶體,之後bootfs會被解除安裝掉,從而釋放出記憶體。
同樣核心版本的不同的 Linux 發行版,其bootfs都是一致的。
2. root file system (rootfs):包含典型的目錄結構,包括 /dev, /proc, /bin, /etc, /lib, /usr, and /tmp
就是我下面這張圖裡的這些資料夾:
等再加上要執行使用者應用所需要的所有配置檔案,二進位制檔案和庫檔案。這個檔案系統在不同的Linux 發行版中是不同的。而且使用者可以對這個檔案進行修改。
Linux 系統在啟動時,roofs 首先會被掛載為只讀模式,然後在啟動完成後被修改為讀寫模式,隨後它們就可以被修改了。
不同的Linux版本,實現unionFS的技術可能不一樣,使用命令docker info檢視,比如我的機器上實現技術是overlay2:
看個實際的例子。
新建兩個資料夾abap和java,在裡面用touch命名分別建立兩個空檔案:
新建一個mnt資料夾,用mount命令把abap和java資料夾merge到mnt資料夾下,-t執行檔案系統型別為aufs:
sudo mount -t aufs -o dirs=./abap:./java none ./mnt
mount完成後,到mnt資料夾下檢視,發現了來自abap和java資料夾裡總共4個檔案:
現在我到java資料夾裡修改spring,比如加上一行spring is awesome, 然後到mnt資料夾下檢視,發現mnt下面的檔案內容也自動被更新了。
那麼反過來會如何呢?比如我修改mnt資料夾下的aop檔案:
而java資料夾下的原始檔案沒有受到影響:
實際上這就是Docker容器映象分層實現的技術基礎。如果我們瀏覽Docker hub,能發現大多數映象都不是從頭開始製作,而是從一些base映象基礎上建立,比如debian基礎映象。
而新映象就是從基礎映象上一層層疊加新的邏輯構成的。這種分層設計,一個優點就是資源共享。
想象這樣一個場景,一臺宿主機上執行了100個基於debian base映象的容器,難道每個容器裡都有一份重複的debian拷貝呢?這顯然不合理;藉助Linux的unionFS,宿主機只需要在磁碟上儲存一份base映象,記憶體中也只需要載入一份,就能被所有基於這個映象的容器共享。
當某個容器修改了基礎映象的內容,比如 /bin資料夾下的檔案,這時其他容器的/bin資料夾是否會發生變化呢?
根據容器映象的寫時拷貝技術,某個容器對基礎映象的修改會被限制在單個容器內。
這就是我們接下來要學習的容器 Copy-on-Write 特性。
容器映象由多個映象層組成,所有映象層會聯合在一起組成一個統一的檔案系統。如果不同層中有一個相同路徑的檔案,比如 /text,上層的 /text 會覆蓋下層的 /text,也就是說使用者只能訪問到上層中的檔案 /text。
假設我有如下這個dockerfile:
FROM debian
RUN apt-get install emacs
RUN apt-get install apache2
CMD [“/bin/bash”]
執行docker build .看看發生了什麼。
生成的容器映象如下:
當用docker run啟動這個容器時,實際上在映象的頂部新增了一個新的可寫層。這個可寫層也叫容器層。
容器啟動後,其內的應用所有對容器的改動,檔案的增刪改操作都只會發生在容器層中,對容器層下面的所有隻讀映象層沒有影響。
要獲取更多Jerry的原創文章,請關注公眾號”汪子熙”:
相關文章
- Docker技術三大要點:cgroup, namespace和unionFS的理解DockernamespaceNFS
- docker容器技術基礎之linux cgroup、namespaceDockerLinuxnamespace
- linux namespace and cgroupLinuxnamespace
- 深入理解 Docker 核心原理:Namespace、Cgroups 和 RootfsDockernamespace
- 搞懂容器技術的基石: namespace (上)namespace
- 一篇搞懂容器技術的基石: cgroup
- Docker:技術和商業的結合點在哪裡?Docker
- 徹底搞懂容器技術的基石: namespace (下)namespace
- 對5G技術的一點理解
- 容器技術|Docker三劍客之docker-swarmDockerSwarm
- 容器技術|Docker三劍客之docker-composeDocker
- Web前端開發技術核心思想,這兩大要點你要懂!Web前端
- 容器技術和Docker介紹Docker
- Docker | Docker技術基礎梳理(四) - 深入理解映象與容器Docker
- gslb(global server load balance)技術的一點理解Server
- 玩轉 Cgroup 系列之三:挑戰手動管理 Cgroup
- 1.01 容器技術和docker簡介Docker
- docker架構和底層技術Docker架構
- Docker | Docker技術基礎梳理(三) - 容器生命週期管理Docker
- Docker是什麼技術?Docker容器具有哪些特點?Docker
- Docker進階與實踐之一:CgroupDocker
- 做資料視覺化,謹記三大要點視覺化
- 玩轉 Cgroup 系列之一: Cgroup 的起源、重要性和基本工作原理
- 淺談沉浸式投影的三大技術特點
- GSLB是什麼?談談對該技術的一點理解
- Docker技術( 容器虛擬化技術 )Docker
- aardio教程四) 理解名字空間(namespace)namespace
- docker技術總結Docker
- docker技術學習Docker
- docker容器技術原理Docker
- Docker--容器技術Docker
- Docker之Docker Compose技術詳解。Docker
- Docker容器技術與Docker介紹Docker
- Docker | Docker技術基礎梳理(一)Docker
- Docker進階與實踐之二:NamespaceDockernamespace
- 『現學現忘』Docker相關概念 — 8、虛擬化技術和容器技術的關係Docker
- containerd中的cgroupAI
- Python技術分享:深入理解ThreadLocal變數的功能和使用Pythonthread變數