文章目錄 1.Docker關鍵內核知識總結 2.namespace資源隔離 3.cgroups資源限制 4.Docker架構 5.libcontainer 6.Docker鏡像 7.Docker存儲管理
1.Docker關鍵內核知識總結
Docker通過namespace實現資源隔離 Docker通過cgroups實現了資源限制 Docker通過寫時復制(copy-on-write)實現高效的文件操作
2.namespace資源隔離
(
1 )UTS(UNIX Time
- sharing System) namepace提供了主機名和域名的隔離,這樣每個Docker容器就可以擁有獨立的主機名和
域名了,在網絡上可被視作一個獨立的節點,在非宿主機上的一個進程,指的是hostname(
2 )IPC namespace:申請IPC對象就申請了一個全局唯一的32bitID,實際包含:系統IPC標識符和實現POSIX消息隊列的文件系統,
在同一個IPC namespace下的進程彼此可見,不同IPC namespace下的進程互相不可見。eg:PostgreSQL實現了該機制,Docker的
IPC namespace實現了容器與宿主機、容器與容器之間的IPC隔離,指的是hostname(
3 )PID namespace:對進程PID重新標號,即:兩個不同namespace下的進程可以有相同的PID。
包括:
PID namespace中的init進程:當一個Docker容器中運行多個進程,最先啟動的命令進程應該是具有資源監控與回收等管理能力的,如bash
信號與init進程,當一個容器內存在多個進程時,容器內的init進程可以對信號進行捕獲;
掛載proc文件系統:如果只想看到PID namespace本身應該應該看到的進程,需要重新掛載
/ proc
mount
- t proc proc
/ proc
ps a
unshare
( ) 和setns
( ) : 創建了PID namespace后,調用者不會進入新的PID namespace,而是隨后創建的子進程進入
注:每個PID namespace中的第一個進程PID
1 ,都會像傳統Linux中的init進程一樣擁有特權,起特殊作用。(
4 )mount namespace
掛載傳播:定義了掛載對象之間的關系
掛載關系:共享關系和從屬關系
掛載狀態:共享掛載
( share
) , 從屬掛載slave,共享
/ 存儲掛載shared
and slave,私有掛載private,不可綁定掛載unbindable
eg:如圖
3 - 1
(
5 )network namespace:
一個網絡設備最多存在于一個network namespace中,可以通過創建veth pair在不同的network namespace間創建通道,以達到通信的目的。
veth pair:虛擬網絡設備對:有
2 端,類似管道
容器的經典做法是:創建一個veth pair,一端訪置在新的namespace中,通常命名為eth0,一段放在原先的namespace中連接物理網絡設備,
再通過把多個設備接入網橋或者進行路由轉發,來實現通信的目的。eg:
3 - 2
(
6 )user namespace:
只要用戶在啟動Docker daemon的時候,指定了
- - user
- remap,那么當用戶運行容器時,容器內部的root用戶并不等于宿主機的root用戶,
而是映射到宿主機上的普通用戶。
namespace實際上就是按層次關聯起來,每個namespace都發源于最初的root namespac,并與之建立映射,如圖
3 - 3
Docker同時使用user namespace和Capability,這在很大程度上加強了容器的安全性。
Linux內核實現namespace的一個目的是:實現輕量級的虛擬化(容器)服務,在同一個namespace下的進程可以感知彼此的變化,而對外界的進程一無所知,以達到獨立和隔離的目的。 進行namespace API的4種類方式 (1)通過clone()在創建新進程的同時創建namespace (2)查看/proc/[pid]/ns文件,可以看到指向不同namesoace號的文件,eg:[4026531839]就是namesoace號,若兩個進程指向的namespace編號相同,就說明他們在一個namespace下。 在Docker中,通過文件描述符定位和加入一個存在的namespace是最基本的方式。 (3)通過setns()加入一個已經存在的namespace (4)通過unshare()在原先進程上進行namespace隔離
( 2 ) 的eg
ll
/ proc
/ $$
/ ns等價于
touch
~ / uts
mount
- - bind
/ proc
/ 27514 / ns
/ uts
~ / uts
3.cgroups資源限制
cgroups:限制被namespace隔離起來的資源,還可以為資源設置權重,計算使用量,控制任務(進程或線程)啟停等
在Linux中,內核本身的調度和管理并不對進程和線程進行區分,只根據clone創建時傳入的參數的不同,來從概念上區別進程和線程,統一稱之為任務
cgroups:control groups (1)把任務放到一個組里面統一加以控制,eg:子任務創建之初與其父任務處于同一個cgroups的控制組 (2)cgroups可以限制、記錄任務組使用的物理資源(CPU,Memory,IO等),為容器實現虛擬化提供了基本保證,是構建Docker等一系列虛擬化管理工具的基石。 (3)本質上,cgroups是內核附加在程序上的一系列鉤子hook,通過程序運行時,對資源的調度,來觸發相應的鉤子以達到資源追蹤和限制的目的。
cgroups作用:實現不同用戶層面的資源的管理 (1)四大功能:資源限制,優先級分配,資源統計,任務控制
cgroups術語表 (1)task任務:任務表示一個進程或線程 (2)cgroup控制組:cgroup中的資源控制都是以cgroup為單位實現的。一個任務可以加入某個cgroup,也可以從某個cgroup遷移到另外一個cgroup (3)subsystem子系統:資源調度控制器。eg:CPU子系統可以控制CPU時間分配 (4)hierarchy層級:層級由一系列cgroup,以一個樹狀結構排練而成,每個層級通過綁定對應的子系統進程資源控制。
傳統的Unix任務管理和cgroups的組織結構的區別 (1)Unix實際先啟動init任務作為根節點,再由init節點創建子任務作為子節點,而每個子節點又可以創建新的子節點,從而形成一個樹狀結構。cgroups也構成類似的樹狀結構,子節點從父節點繼承屬性 (2)多個cgroup構成的層級并非單跟結構,可以允許存在多個。在Docker中,每個子系統獨自構成一個層級,這樣易于管理。
cgroups、任務、子系統、層級四者之間的規則關系 (1)規則1:CPU和Memory的子系統可以附加到一個層級 (2)規則2:CPU子系統附加到層級A的同時不能再附加到層級B,因為層級B已經附加到了內存子系統。 如果層級B沒有附加過內存子系統 ,那么CPU子系統同時附加到兩個層級是允許的。 (3)規則3:httpd任務已經加入到層級A中的/cg1,而不能加入同一個層級中的/cg2,但是可以加入層級B中的/cg3 (4)規則4:當httpd剛fork出另外一個httpd時,兩者在同一個層級中的同一個cgroup中,但是隨后ID=4840的httpd需要移動到其它cgroup也是可以的,因為父子任務間已經獨立。
子系統 (1)子系統實際上就是cgroups的資源控制系統,每種子系統獨立地控制一種資源。 (2)Docker的9個子系統:blkio,cpu,cpuacct,cpuset,devices,freezer,memory,perf_event,net_cls (3)基本操作如下:
ubuntu16
. 04 Linux的cgroup表現為一個文件系統,需要mount
root@ubuntu
: / home
/ jiwangreal
cgroup on
/ sys
/ fs
/ cgroup
/ systemd
type cgroup
( rw
, nosuid
, nodev
, noexec
, relatime
, xattr
, release_agent
= / lib
/ systemd
/ systemd
- cgroups
- agent
, name
= systemd
)
cgroup on
/ sys
/ fs
/ cgroup
/ devices
type cgroup
( rw
, nosuid
, nodev
, noexec
, relatime
, devices
)
cgroup on
/ sys
/ fs
/ cgroup
/ cpu
, cpuacct
type cgroup
( rw
, nosuid
, nodev
, noexec
, relatime
, cpu
, cpuacct
)
cgroup on
/ sys
/ fs
/ cgroup
/ net_cls
, net_prio
type cgroup
( rw
, nosuid
, nodev
, noexec
, relatime
, net_cls
, net_prio
)
cgroup on
/ sys
/ fs
/ cgroup
/ perf_event
type cgroup
( rw
, nosuid
, nodev
, noexec
, relatime
, perf_event
)
cgroup on
/ sys
/ fs
/ cgroup
/ blkio
type cgroup
( rw
, nosuid
, nodev
, noexec
, relatime
, blkio
)
cgroup on
/ sys
/ fs
/ cgroup
/ freezer
type cgroup
( rw
, nosuid
, nodev
, noexec
, relatime
, freezer
)
cgroup on
/ sys
/ fs
/ cgroup
/ pids
type cgroup
( rw
, nosuid
, nodev
, noexec
, relatime
, pids
)
cgroup on
/ sys
/ fs
/ cgroup
/ hugetlb
type cgroup
( rw
, nosuid
, nodev
, noexec
, relatime
, hugetlb
)
cgroup on
/ sys
/ fs
/ cgroup
/ memory
type cgroup
( rw
, nosuid
, nodev
, noexec
, relatime
, memory
)
cgroup on
/ sys
/ fs
/ cgroup
/ cpuset
type cgroup
( rw
, nosuid
, nodev
, noexec
, relatime
, cpuset
)
cgroup on
/ sys
/ fs
/ cgroup
/ rdma
type cgroup
( rw
, nosuid
, nodev
, noexec
, relatime
, rdma
) cpu子系統的控制組下的文件
root@ubuntu
: / home
/ jiwangreal
cgroup
. clone_children cpuacct
. stat cpuacct
. usage_percpu cpuacct
. usage_sys cpu
. cfs_quota_us init
. scope system
. slice
cgroup
. procs cpuacct
. usage cpuacct
. usage_percpu_sys cpuacct
. usage_user cpu
. shares notify_on_release tasks
cgroup
. sane_behavior cpuacct
. usage_all cpuacct
. usage_percpu_user cpu
. cfs_period_us cpu
. stat release_agent user
. slice 在
/ sys
/ fs
/ cgroup
/ cpu目錄下創建控制組
root@ubuntu
: / home
/ jiwangreal
root@ubuntu
: / sys
/ fs
/ cgroup
/ cpu
root@ubuntu
: / sys
/ fs
/ cgroup
/ cpu
total
0
drwxr
- xr
- x
2 root root
0 Feb
5 15 : 58 . /
dr
- xr
- xr
- x
6 root root
0 Feb
5 15 : 58 . . /
- rw
- r
- - r
- - 1 root root
0 Feb
5 15 : 58 cgroup
. clone_children
- rw
- r
- - r
- - 1 root root
0 Feb
5 15 : 58 cgroup
. procs
- r
- - r
- - r
- - 1 root root
0 Feb
5 15 : 58 cpuacct
. stat
- rw
- r
- - r
- - 1 root root
0 Feb
5 15 : 58 cpuacct
. usage
- r
- - r
- - r
- - 1 root root
0 Feb
5 15 : 58 cpuacct
. usage_all
- r
- - r
- - r
- - 1 root root
0 Feb
5 15 : 58 cpuacct
. usage_percpu
- r
- - r
- - r
- - 1 root root
0 Feb
5 15 : 58 cpuacct
. usage_percpu_sys
- r
- - r
- - r
- - 1 root root
0 Feb
5 15 : 58 cpuacct
. usage_percpu_user
- r
- - r
- - r
- - 1 root root
0 Feb
5 15 : 58 cpuacct
. usage_sys
- r
- - r
- - r
- - 1 root root
0 Feb
5 15 : 58 cpuacct
. usage_user
- rw
- r
- - r
- - 1 root root
0 Feb
5 15 : 58 cpu
. cfs_period_us
- rw
- r
- - r
- - 1 root root
0 Feb
5 15 : 58 cpu
. cfs_quota_us
- rw
- r
- - r
- - 1 root root
0 Feb
5 15 : 58 cpu
. shares
- r
- - r
- - r
- - 1 root root
0 Feb
5 15 : 58 cpu
. stat
- rw
- r
- - r
- - 1 root root
0 Feb
5 15 : 58 notify_on_release
- rw
- r
- - r
- - 1 root root
0 Feb
5 15 : 58 tasks限制PID
= 18828 進程的cpu使用配額
root@ubuntu
: / sys
/ fs
/ cgroup
/ cpu
將cpu限制為最高使用
20 %
root@ubuntu
: / sys
/ fs
/ cgroup
/ cpu
(4)在Docker中,docker daemon會在單獨掛載了每一個子系統的控制組目錄下創建一個名為docker的控制組,然后在docker控制組里面,再為每個容器創建一個以容器ID為名稱的容器控制組,這個容器里的所有進程號都會寫到控制組tasks中,并且在控制文件(eg:cpu.cfs_quota_us)中寫入預設的限制參數值
eg:
/ sys
/ fs
/ cgroup
/ cpu
/ 下創建一個名為docker的控制組
一個cgroup創建完成,不管綁定了何種子系統,其目錄下都會生成以下的幾個文件,用來描述cgroup的相應信息root@ubuntu
: / sys
/ fs
/ cgroup
/ cpu
/ sys
/ fs
/ cgroup
/ cpu
/ docker
/
├──
7df87b1892980b546f7ae7036cc5454efe48ae3a3e83f30a33bf72929edb3462
│ ├── cgroup
. clone_children
│ ├── cgroup
. procs
│ ├── cpuacct
. stat
│ ├── cpuacct
. usage
│ ├── cpuacct
. usage_all
│ ├── cpuacct
. usage_percpu
│ ├── cpuacct
. usage_percpu_sys
│ ├── cpuacct
. usage_percpu_user
│ ├── cpuacct
. usage_sys
│ ├── cpuacct
. usage_user
│ ├── cpu
. cfs_period_us
│ ├── cpu
. cfs_quota_us
│ ├── cpu
. shares
│ ├── cpu
. stat
│ ├── notify_on_release
│ └── tasks 所有在該cgroup中任務的TID,即:所有的進程或線程ID
├── cgroup
. clone_children
├── cgroup
. procs 線程組中第一個進程的PID
├── cpuacct
. stat
├── cpuacct
. usage
├── cpuacct
. usage_all
├── cpuacct
. usage_percpu
├── cpuacct
. usage_percpu_sys
├── cpuacct
. usage_percpu_user
├── cpuacct
. usage_sys
├── cpuacct
. usage_user
├── cpu
. cfs_period_us
├── cpu
. cfs_quota_us
├── cpu
. shares
├── cpu
. stat
├── notify_on_release 表示是否在cgroup中最后一個任務退出時,通知運行release agent
└── tasks
1 directory
, 32 files
cgroups是如何對容器中的進程產生作用的? (1)cgroups的實現本質上是給任務掛上鉤子,當任務運行的過程中涉及某種資源時,就會觸發鉤子上所附帶的子系統進行監測,依據資源類別的不同,使用對應的技術進行資源限制和優先級分配 (2)cgroups判斷資源超限及超處配額之后的措施:cgroups提供了統一的接口對資源進行控制和統計,Docker默認是開啟OOMControl的(內存超限控制) (3)cgroup與任務之間的關聯關系:cgroup與任務之間是多對多的關系,他們并不直接關聯,而是通過一個中間結構把雙向的關聯信息記錄起來。 (4)Docker在使用cgroup時的注意事項:目前無法將一個新的子系統綁定到激活的層級上,或者從一個激活的層級中解除某個子系統的綁定;只有遞歸式地卸載層級中的所有cgroup,那個層級才會被真正的卸載。
4.Docker架構
Docker client與Docker daemon建立通信,并將請求發送給后者
Docker daemon是Docker架構中的主要用戶接口,他提供了API server用于接收來自Docker client的請求
Docker通過driver模塊來實現對Docker容器執行環境的創建和管理,eg:要為容器創建數據卷colume時,則通過volume模塊調用某個具體的volumedriver,來創建一個數據卷并負責后序的掛載操作。
當運行容器的命令執行完畢后,一個實際的容器就處于運行狀態,該容器擁有獨立的文件系統和相對安全且隔離的運行環境。
Docker daemon負責將docker client的用戶請求 轉譯成系統調用,進而創建和管理容器。包括3類接口: (1)容器執行驅動execdriver,對namespace,cgroups等所需的系統操作的二次封裝 (2)volumedriver存儲驅動,對volume數據卷存儲操作的最終執行者,負責volume的增刪改查 (3)鏡像存儲驅動grapdriver,所有與容器鏡像相關操作的最終執行者。
network (1)通過networkdriver模塊以及libcontainer庫完成 (2)網絡驅動負責完成具體的操作,包括:創建容器通信所需的網絡,容器的network namespace,這個網絡所需的虛擬網卡,分配通信所需的IP,服務訪問的端口和容器與宿主機之間的端口映射,設置hosts,resove.conf,iptables等
docker命令的2種模式: client模式和daemon模式 (1)client模式:解析flag信息,創建client實例,執行具體的命令(具體過程交給cli/cli.go) (2)daemon模式:通過一個server模塊(api/server/server.go)接收來自client的請求(該server會通過與daemon對象綁定來接收并處理完成具體的請求,類似于一個API接收器綁定了一個業務邏輯處理器 ),然后根據請求類型,交由具體的方法去執行;Docker daemon需要在Docker根目錄(/var/lib/docker)下創建并初始化一系列跟容器文件系統密切相關的目錄和文件。
Docker daemon網絡 (1)libnetwork實現了host、null、bridge和overlay的驅動。bridge driver不提供跨主機通信的能力,overlay driver提供多主機環境。 (2)初始化execdriver。execdriver是Docker中用來管理Docker容器的驅動。Docker execdriver運行的root路徑默認是:/var/run/docker,Docker運行時的root路徑是:/var/lib/docker (3)daemon對象:創建daemon對象實例 (4)恢復已有的Docker容器:當Docker daemon啟動時,會去查看在daemon.repository,即/var/lib/docker/containers中的內容 (5)Docker daemon進程啟動的3步:
(
1 )啟動一個API server,他工作在用戶通過
- H指定的socket上面
(
2 )Docker使用NewDaemon方法創建一個daemon對象來保存信息和處理業務邏輯
(
2 )最后將API Server和daemon對象綁定起來,接收并處理client的請求
一個運行的daemon是如何相應并處理來自client的請求呢? (1)發起請求:client通過反射機制找到CmdRun方法,CmdRun解析用戶提供的容器參數,發出創建容器和啟動容器的兩個POST請求 (2)創建容器:這里并不創建一個Linux容器 ,它只需要解析用戶通過client提交的POST表單,然后使用這些參數在daemon中新建以惡container對象出來 (3)啟動容器:API Servie接收到start請求后,會告訴Docker daemon進行container啟動容器操作,Docker daemon調用containerMonitor方法將daemon設置為自己的supervisor,即:告訴daemon進程,請使用本container相關參數作為參數,執行對應execdriver的Run方法 (4)最后一步,最后執行Run操作的命令,所有與OS打交道的任務全都交給ExecDriver.Run,從而創建namespace,配置cgroup,掛載rootfs 總結的話就是:execdriver的Run方法通過Docker daemon提交的command信息創建了一份可以供libcontainer解讀的容器配置container。
5.libcontainer
libcontainer主要分為三大塊內容:(1)容器的創建及初始化,(2)容器生命周期管理,(3)進程管理,調用者是Docker的execdriver
Docker通過對namesoaces,cgroups,capablities以及文件系統的管理和分配來隔離出一個執行環境,即Docker容器
在Docker daemon提交過來的command中,包含namespace,cgroups以及未來容器中將要運行的進程的重要信息,其中Network,Ipc,Pid等字段描述了隔離容器所需的namespace。等到上述容器配置模板container中 的所有項都按照command提供的內容填好之,一份該容器專屬的容器配置container就生成好了。 container可以理解為libcantaineer與Docker daemon之間進行信息交換的標準格式。
libcontainer的工作方式 主要內容是:Process,Container以及Factory這3個邏輯實體實現的原理,而execdriver或者其它調用者只需要按次序:使用Factory創建邏輯容器Container,啟動邏輯容器Container,和用邏輯容器創建物理容器,即可完成Docker容器的創建
Docker daemon與容器之間的通信方式 (1)容器進程啟動后需要做初始化工作,使用了namespace隔離后的兩個進程間的通信 (2)將負責創建容器的進程稱之為父進程,將容器進程稱之為子進程。 通過pipe(int fd[2]),在fd[1]寫入數據,從fd[0]端讀取數據,創建的子進程會內嵌這個打開的文件描述符,通信完成的標志在于EOF信號的傳遞。 注意:Docker會加入network namespace,所以初始化時網絡棧是完全隔離的,所以不能采取sockets通信。 父進程ParentProcess:負責從物理容器外部處理容器啟動工作,與Container對象直接進行交互; 子進程Process:永無物理容器內進程的配置和IO的管理 如下圖:在libcontainer中,ParentProcess進程與容器進程(cmd,即dockerinit進程)的通信方式如下
6.Docker鏡像
Docker鏡像的文件內容及一些運行Docker容器的配置文件組成了Docker容器的靜態文件系統運行環境——rootfs 。 Docker鏡像是Docker容器的靜態視角,Docker容器是Docker鏡像的運行狀態。
rootfs是Docker容器在啟動時內部進程可見的文件系統,即:Docker容器的根目錄,其包含一個OS運行所需的文件系統。
在Docker架構中,Docker daemon為Docker容器掛載rootfs時,將rootfs設置為只讀模式。利用聯合掛載技術,在已有的只讀rootfs上,再掛載一個讀寫層。
Docker鏡像的主要特點 (1)分層:分層是Docker鏡像如此輕量的重要原因。 當需要修改容器鏡像內的某個文件時,只對處于最上方的讀寫層進行變動,不覆蓋下層已有文件系統的內容,已有文件在只讀層依然存在,但是被讀寫層的新版文件所隱藏 (2)寫時復制 未更改文件內容時,所有容器共享同一份數據,只有在Docker容器運行過程中,文件系統發生變化的時候,才把變化的文件內容寫到可讀寫層,并隱藏只讀寫層中的老版本文件 (3)內容尋址 利用基于內容哈希來索引鏡像層,在一定程度上減少了ID的沖突,并且增強了鏡像層的共享。 (4)聯合掛載 該技術可以在一個掛載點同時掛載多個文件系統,將掛載點的原目錄與被掛載內容進行整合,使得最終可見的文件系統將會包含整合之后的各層的文件和目錄。eg:當docker commit這個修改過的容器文件系統為一個新的鏡像時,保存的內容僅僅為最上層讀寫文件系統中被更新過的文件,如下圖所示
Docker鏡像的存儲組織方式 可讀寫部分(read-write layer及及volumes),init-layer,只讀層(read-only layer)3部分工通組成了一個容器所需的下層文件系統,通過聯合掛載表現為一層。 如下圖
Docker鏡像關鍵概念 (1)registry:用以保存Docker鏡像,還包括鏡像層次結構和關于鏡像的元數據 (2)repository:由具有某個功能的Docker鏡像的所有迭代版本構成的鏡像組 registry是repository的集合,repository是鏡像的集合 (3)mainfest描述文件:鏡像pull到本地Docker宿主機時,轉化為本地的鏡像配置文件config (4)image:鏡像的架構(eg:amd64),鏡像的默認配置信息,構建鏡像的容器配置信息,包含所有鏡像層信息的rootfs layer:鏡像由鏡像層組成 ,存訪鏡像層的diff_id,size,cache-id和parent等內容,實際的文件內容由存儲驅動進行管理 (5)Dockerfile:通過docker build命令構建自己的Docker鏡像所使用的定義文件
Docker鏡像的構建操作 (1)docker commit是將容器提交為一個鏡像,從容器更新或者構建鏡像 (2)docker build是在一個鏡像的基礎上構建鏡像
Docker鏡像的分發方法 (1)直接對容器進行持久化和使用鏡像進行持久化的區別: docker export用于持久化容器,docker push和docker save用于持久化鏡像; 將容器導出后再導入(export-imported)后的容器會丟失所有的歷史,而保存后再加載(saved-loaded)的鏡像則沒有丟失歷史和層,后者可以通過docker tag命令實現歷史層回滾! (2)pull鏡像:Docker client端在pull鏡像時,如果用戶沒有指定tag,則clientt會默認使用latest作為tag (3)push鏡像 (4)docker export命令導出容器 (5)docker save命令保存鏡像
7.Docker存儲管理
Docker鏡像將鏡像元數據與鏡像文件的存儲完全隔離開了 repository與image這兩類元數據并無物理上的鏡像文件與之對應,而layer這種元數據則存在于物理上的鏡像層文件與之對應 (1)repository元數據: repository在本地的持久化文件放置于:
每個人存訪的位置細節上,可能不太一樣
root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ var
/ lib
/ docker
/ image
/ overlay2
root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
{ "Repositories" : { "busybox" : { "busybox:latest" : "sha256:6d5fcfe5ff170471fcc3c8b47631d6d71202a1fd44cf3c147e50c8de21cf0648" , "busybox@sha256:6915be4043561d64e0ab0f8f098dc2ac48e077fe23f488ac24b665166898115a" : "sha256:6d5fcfe5ff170471fcc3c8b47631d6d71202a1fd44cf3c147e50c8de21cf0648" } , "django" : { "django:latest" : "sha256:eb40dcf64078249a33f68fdd8d80624cb81b524c24f50b95fff5c2b40bdc3fdc" , "django@sha256:5bfd3f442952463f5bc97188b7f43cfcd6c2f631a017ee2a6fca3cb8992501e8" : "sha256:eb40dcf64078249a33f68fdd8d80624cb81b524c24f50b95fff5c2b40bdc3fdc" } , "haproxy" : { "haproxy:latest" : "sha256:9b5ff4593b4e4cbc4506e7ca65f1ffd78aecd97cbf15cb32eda4a0baa1ebf451" , "haproxy@sha256:6f921726b32ac07177885c8ed180d07d0da322aecc11b1ade75c4aa31ee686a8" : "sha256:9b5ff4593b4e4cbc4506e7ca65f1ffd78aecd97cbf15cb32eda4a0baa1ebf451" } , "hello-world" : { "hello-world:latest" : "sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e" , "hello-world@sha256:9572f7cdcee8591948c2963463447a53466950b3fc15a247fcad1917ca215a2f" : "sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e" } , "httpd" : { "httpd:latest" : "sha256:c2aa7e16edd855da8827aa0ccf976d1d50f0827c08622c16e0750aa1591717e5" , "httpd@sha256:769018135ba22d3a7a2b91cb89b8de711562cdf51ad6621b2b9b13e95f3798de" : "sha256:c2aa7e16edd855da8827aa0ccf976d1d50f0827c08622c16e0750aa1591717e5" } , "redis" : { "redis:latest" : "sha256:44d36d2c2374b240abcf5da2130abf49938b8fb49446df6eec028718520332ef" , "redis@sha256:7b84b346c01e5a8d204a5bb30d4521bcc3a8535bbf90c660b8595fad248eae82" : "sha256:44d36d2c2374b240abcf5da2130abf49938b8fb49446df6eec028718520332ef" } , "ubuntu" : { "ubuntu:latest" : "sha256:ccc6e87d482b79dd1645affd958479139486e47191dfe7a997c862d89cd8b4c0" , "ubuntu@sha256:8d31dad0c58f552e890d68bbfb735588b6b820a46e459672d96e585871acc110" : "sha256:ccc6e87d482b79dd1645affd958479139486e47191dfe7a997c862d89cd8b4c0" } }
}
(2)image 元數據 imageStore則是管理鏡像ID與鏡像元數據之間的映射關系 以及元數據的持久化操作
每個人存訪的位置細節上,可能不太一樣
root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ imagedb
/ metadata
/ sha256
(3)layer元數據 用戶在Docker宿主機上下載了某個鏡像層之后,Docker會在宿主機上基于鏡像層文件包和image元數據,構建本地的layer元數據,包括:diff,parent,size等; 當Docker將在宿主機上產生的鏡像層上傳到registry時,與新鏡像層相關的宿主機上的元數據不會與鏡像層一塊打包上傳。
持久化文件的位置:
全都是mountID
root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
/ mounts
total
48
drwxr
- xr
- x
12 root root
4096 Feb
5 16 : 08 . /
drwx
- - - - - - 5 root root
4096 Jan
23 21 : 11 . . /
drwxr
- xr
- x
2 root root
4096 Jan
23 21 : 11 0ebb039b2e2857e093bce2ebed4953436473d04d7a29a0ecdc2e30eca8ca6544 /
drwxr
- xr
- x
2 root root
4096 Feb
4 15 : 38 171b215cd75aafadc82c61f83ed44290e87830fb4cf03cad2a1e3908a05d29d1 /
drwxr
- xr
- x
2 root root
4096 Feb
5 16 : 08 7df87b1892980b546f7ae7036cc5454efe48ae3a3e83f30a33bf72929edb3462 /
drwxr
- xr
- x
2 root root
4096 Feb
4 15 : 37 8eb9fd0012b3ab2475fa37a1aa081252544d5941403301dd8f68c9a722f6e551 /
drwxr
- xr
- x
2 root root
4096 Feb
4 15 : 35 c3c46778a8acd1eb6378459f26c229f53bb58415d5cc5ca6528232b299eb2dfe
/
drwxr
- xr
- x
2 root root
4096 Jan
23 21 : 14 ca318115d2728b1e5a0d351c4a9291a266d382057c4606d78f77808d5cdab139
/
drwxr
- xr
- x
2 root root
4096 Feb
4 15 : 37 d5ff3ca4e01fd66019def444b81ccdd8ee69e1a19254ee7f86ba14ca8b436aa4
/
drwxr
- xr
- x
2 root root
4096 Feb
5 16 : 07 f6282cc03404fbf2aa1e7db0330096d4302854bd81bfdd18bbafafc76eb5ea28
/
drwxr
- xr
- x
2 root root
4096 Feb
4 15 : 36 f9c829a376f56a8b529cfa56a2e5951d5c8eaca7c29994a29f4965152e2d288d
/
drwxr
- xr
- x
2 root root
4096 Feb
4 15 : 36 ff8329b53facdc58674e0af62e1785bd4b63c3ec6096bfe72eaa1bde15102767
/
Docker存儲驅動 (1)存儲驅動依據OS底層的支持,提供了針對某種文件系統的初始化操作以及對鏡像層的增刪改查和差異比較等操作 (2)Docker中管理文件系統的驅動為graphdriver ,定義了Driver和ProtoDriver兩個接口 docker daemon -s some_driver_name (1)aufs存儲驅動:這些目錄的掛載是分層次的,通常最上層是可讀可寫的,下層是只讀層 Docker容器的文件系統有3層:可讀寫層(將來被commit的內容),init層和只讀層。但是這不影響我們傳統認識的可讀寫層+只讀寫層所組成的容器文件系統,因為init層對于用戶來說是完全透明的。 這些目錄的掛載是分層次的,通常來說最上層是可讀寫層,下面的層是只讀層。所以,aufs 的每一層都是一個普通的文件系統。
參考:
https
: // www
. cnblogs
. com
/ sparkdev
/ p
/ 9121188. html
https
: // arkingc
. github
. io
/ 2017 / 04 / 13 / 2017 - 04 - 13 - docker
- filesystem
- aufs
/ (
1 )ubuntu的存儲驅動默認是overlay2,首先修改成aufs
參考:https
: // blog
. csdn
. net
/ shida_csdn
/ article
/ details
/ 80784132
root@ubuntu
: / home
/ jiwangreal
ExecStart
= / usr
/ bin / dockerd
- - storage
- driver
= aufs
- H fd
: // - - containerd
= / run
/ containerd
/ containerd
. sockroot@ubuntu
: / home
/ jiwangreal
root@ubuntu
: / home
/ jiwangreal
WARNING
: No swap limit support
WARNING
: the aufs storage
- driver
is deprecated
, and will be removed
in a future release
. Storage Driver
: aufsRoot Dir
: / var
/ lib
/ docker
/ aufs(
2 )repository 元數據
repository 是由具有某個功能的 docker 鏡像的所有迭代版本構成的鏡像庫。
Repository 在本地的持久化文件存放于
/ var
/ lib
/ docker
/ image
/ < graph_driver
> / repositories
. json 中,下面
顯示了 docker 使用 aufs 存儲驅動時 repositories
. json 文件的路徑:
root@ubuntu
: / var
/ lib
/ docker
/ image
/ aufs
distribution imagedb layerdb repositories
. json
root@ubuntu
: / var
/ lib
/ docker
/ image
/ aufs
{ "Repositories" : { "ubuntu" : { "ubuntu:latest" : "sha256:ccc6e87d482b79dd1645affd958479139486e47191dfe7a997c862d89cd8b4c0" , "ubuntu@sha256:8d31dad0c58f552e890d68bbfb735588b6b820a46e459672d96e585871acc110" : "sha256:ccc6e87d482b79dd1645affd958479139486e47191dfe7a997c862d89cd8b4c0" } }
}
文件中存儲了所有本地鏡像的 repository 的名字,比如 ubuntu ,還有每個 repository
下的鏡像的名字、標簽及其對應的鏡像 ID。
當前 docker 默認采用 SHA256 算法根據鏡像元數據配置文件計算出鏡像 ID。
上面的兩條記錄本質上是一樣的,第二條記錄和第一條記錄指向同一個鏡像 ID。
其中ubuntu@sha256
: 8d31dad0c58f552e890d68bbfb735588b6b820a46e459672d96e585871acc110 被稱為
鏡像的摘要,在拉取鏡像時可以看到它:
{ "Repositories" : { } } root@ubuntu
: / var
/ lib
/ docker
/ image
/ aufs
Using default tag
: latest
latest
: Pulling
from library
/ ubuntu
5c939e3a4d10 : Pull complete
c63719cdbe7a
: Pull complete
19a861ea6baf : Pull complete
651c9d2d6c4f : Pull complete
Digest
: sha256
: 8d31dad0c58f552e890d68bbfb735588b6b820a46e459672d96e585871acc110
Status
: Downloaded newer image
for ubuntu
: latest
docker
. io
/ library
/ ubuntu
: latest(
3 )image 元數據
image 元數據包括了鏡像架構
( 如 amd64
) 、操作系統
( 如 linux
) 、鏡像默認配置、
構建該鏡像的容器 ID 和配置、創建時間、創建該鏡像的 docker 版本、構建鏡像的歷史信息以及
rootfs 組成。其中構建鏡像的歷史信息和 rootfs 組成部分除了具有描述鏡像的作用外,
還將鏡像和構成該鏡像的鏡像層關聯了起來。Docker 會根據歷史信息和 rootfs 中的 diff_ids 計算出構成該鏡像的鏡像層的存儲索引 chainID,
這也是 docker
1.10 鏡像存儲中基于內容尋址的核心技術。鏡像 ID 與鏡像元數據之間的映射關系以及元數據被保存在文件
/ var
/ lib
/ docker
/ image
/ < graph_driver
> / imagedb
/ content
/ sha256
/ < image_id
> 中。
root@ubuntu
: / var
/ lib
/ docker
/ image
/ aufs
/ imagedb
/ content
/ sha256
total
12
drwx
- - - - - - 2 root root
4096 Feb
7 09 : 27 . /
drwx
- - - - - - 3 root root
4096 Feb
7 09 : 22 . . /
- rw
- - - - - - - 1 root root
3407 Feb
7 09 : 27 ccc6e87d482b79dd1645affd958479139486e47191dfe7a997c862d89cd8b4c0
上面的內容就是鏡像的IDroot@ubuntu
: / var
/ lib
/ docker
/ image
/ aufs
/ imagedb
/ content
/ sha256
。。。。
"os" : "linux" , "rootfs" : { "diff_ids" : [ "sha256:43c67172d1d182ca5460fc962f8f053f33028e0a3a1d423e05d91b532429e73d" , "sha256:21ec61b65b20ec53a1b7f069fd04df5acb0e75434bd3603c88467c8bfc80d9c6" , "sha256:1d0dfb259f6a31f95efcba61f0a3afa318448890610c7d9a64dc4e95f9add843" , "sha256:f55aa0bd26b801374773c103bed4479865d0e37435b848cb39d164ccb2c3ba51" ] , "type" : "layers" }
} 它包含所有鏡像層信息的 rootfs
( 見上圖的 rootfs 部分
) ,docker 利用 rootfs 中的 diff_id
計算出內容尋址的索引
( chainID
) 來獲取 layer 相關信息,進而獲取每一個鏡像層的文件內容。注意,每個 diff_id 對應一個鏡像層。上面的 diff_id 的排列也是有順序的,
從上到下依次表示鏡像層的最低層到最頂層:(
4 )layer 元數據
鏡像層只包含一個具體的鏡像層文件包。用戶在 docker 宿主機上下載了某個鏡像層之后,
docker 會在宿主機上基于鏡像層文件包和 image 元數據構建本地的 layer 元數據,
包括 diff、parent、size 等。而當 docker 將在宿主機上產生的新的鏡像層上傳到 registry 時,
與新鏡像層相關的宿主機上的元數據也不會與鏡像層一塊打包上傳。Docker 中定義了 Layer 和 RWLayer 兩種接口,分別用來定義只讀層和可讀寫層的一些操作,
又定義了 roLayer 和 mountedLayer,分別實現了上述兩種接口。
其中,roLayer 用于描述不可改變的鏡像層,mountedLayer 用于描述可讀寫的容器層。具體來說,roLayer 存儲的內容主要有索引該鏡像層的 chainID、該鏡像層的校驗碼 diffID、
父鏡像層 parent、graphdriver 存儲當前鏡像層文件的 cacheID、該鏡像層的 size 等內容。這些元數據被保存在
/ var
/ lib
/ docker
/ image
/ < graph_driver
> / layerdb
/ sha256
/ < chainID
> / 文件夾下,目錄下的目錄名稱都是鏡像層的存儲索引 chainID
root@ubuntu
: / var
/ lib
/ docker
/ image
/ aufs
/ layerdb
/ sha256
total
24
drwxr
- xr
- x
6 root root
4096 Feb
7 09 : 27 . /
drwx
- - - - - - 4 root root
4096 Feb
7 09 : 27 . . /
drwx
- - - - - - 2 root root
4096 Feb
7 09 : 27 340bed96497252624f5e4b0f42accfe7edbb7a01047e2bb5a8142b2464008e73 /
drwx
- - - - - - 2 root root
4096 Feb
7 09 : 27 43c67172d1d182ca5460fc962f8f053f33028e0a3a1d423e05d91b532429e73d /
drwx
- - - - - - 2 root root
4096 Feb
7 09 : 27 6357c335cdfcc3a120e288bbd203bf4c861a14245ce5094634ee097e5217085b /
drwx
- - - - - - 2 root root
4096 Feb
7 09 : 27 d1b7fedd4314279a7c28d01177ff56bcff65300f6d41655394bf5d8b788567f6
/ 存儲索引 chainID 目錄下的內容為:
root@ubuntu
: / var
/ lib
/ docker
/ image
/ aufs
/ layerdb
/ sha256
total
28
drwx
- - - - - - 2 root root
4096 Feb
7 09 : 27 . /
drwxr
- xr
- x
6 root root
4096 Feb
7 09 : 27 . . /
- rw
- r
- - r
- - 1 root root
64 Feb
7 09 : 27 cache
- id
- rw
- r
- - r
- - 1 root root
71 Feb
7 09 : 27 diff
- rw
- r
- - r
- - 1 root root
71 Feb
7 09 : 27 parent
- rw
- r
- - r
- - 1 root root
3 Feb
7 09 : 27 size
- rw
- r
- - r
- - 1 root root
1467 Feb
7 09 : 27 tar
- split
. json
. gz
其中 diffID 和 size 可以通過鏡像層包計算出來
( diff 文件的內容即 diffID,
其內容就是 image 元數據中對應層的 diff_id
) 。chainID 和父鏡像層 parent 需要從所屬 image 元數據中計算得到。
而 cacheID 是在當前 docker 宿主機上隨機生成的一個 uuid,在當前的宿主機上,
cacheID 與該鏡像層一一對應,用于標識并索引 graphdriver 中的鏡像層文件:mountedLayer 存儲的內容主要為:
索引某個容器的可讀寫層
( 也叫容器層
) 的 ID
( 也對應容器層的 ID
) 、
容器 init 層在 graphdriver 中的ID
( initID
) 、
讀寫層在 graphdriver 中的 ID
( mountID
) 以及容器層的父層鏡像的 chainID
( parent
) 。
root@ubuntu
: / var
/ lib
/ docker
/ image
/ aufs
/ layerdb
/ mounts
/ 1434657d0976bbdc6a15d6ca3f1d4edc18f887213e5497818e687465dd09a8cf
total
20
drwxr
- xr
- x
2 root root
4096 Feb
7 09 : 56 . /
drwxr
- xr
- x
3 root root
4096 Feb
7 09 : 56 . . /
- rw
- r
- - r
- - 1 root root
69 Feb
7 09 : 56 init
- id
- rw
- r
- - r
- - 1 root root
64 Feb
7 09 : 56 mount
- id
- rw
- r
- - r
- - 1 root root
71 Feb
7 09 : 56 parent(
5 )那么鏡像文件在本地存放在哪里呢?
drwx
- - - - - - 5 root root
4096 Feb
7 09 : 22 . /
drwx
- - x
- - x
15 root root
4096 Feb
7 09 : 22 . . /
drwx
- - - - - - 8 root root
4096 Feb
7 09 : 56 diff
/
drwx
- - - - - - 2 root root
4096 Feb
7 09 : 56 layers
/
drwx
- - - - - - 8 root root
4096 Feb
7 09 : 56 mnt
/
其中 mnt 為 aufs 的掛載目錄,
diff 為實際的數據來源,包括只讀層和可讀寫層,
所有這些層最終一起被掛載在 mnt 下面的目錄上,layers 下為與每層依賴有關的層描述文件。最初,mnt 和 layers 都是空目錄,文件數據都在 diff 目錄下。
一個 docker 容器創建與啟動的過程中,會在
/ var
/ lib
/ docker
/ aufs 下面新建出對應的文件和目錄。由于 docker 鏡像管理部分與存儲驅動在設計上完全分離了,
鏡像層或者容器層在存儲驅動中擁有一個新的標識 ID,在鏡像層
( roLayer
) 中稱為 cacheID,
容器層
( mountedLayer
) 中為 mountID。在 Linux 環境下,mountID 是隨機生成的并保存在 mountedLayer 的元數據 mountID 中,持久化在 image
/ aufs
/ layserdb
/ mounts
/ < container_id
> / mount
- id 中下面以 mountID 為例,創建一個新讀寫層的結果如下:
root@ubuntu
: / var
/ lib
/ docker
/ aufs
/ layers
total
28
drwx
- - - - - - 2 root root
4096 Feb
7 09 : 56 . /
drwx
- - - - - - 5 root root
4096 Feb
7 09 : 22 . . /
- rw
- r
- - r
- - 1 root root
330 Feb
7 09 : 56 06394379d741c96068edd55e598c1f31bc9b89c97d78d6d5da74bdce50faf77c
- rw
- r
- - r
- - 1 root root
260 Feb
7 09 : 56 06394379d741c96068edd55e598c1f31bc9b89c97d78d6d5da74bdce50faf77c - init
- rw
- r
- - r
- - 1 root root
130 Feb
7 09 : 27 16f9270d0924771f8e389ff5f30738285d63ff46e4015b2dc1cfe592fbf9d814
- rw
- r
- - r
- - 1 root root
65 Feb
7 09 : 27 4139a0b6d660f5602780be33fdbeb3fd9ba4e867949a7b38c1f135ad803b6740
- rw
- r
- - r
- - 1 root root
195 Feb
7 09 : 27 59bc27fd2691f4cfdec635003f8fb71fc06d1c786d976d4283bb0a78e42315df
- rw
- r
- - r
- - 1 root root
0 Feb
7 09 : 27 65fa2339190e9406ce6dfeec14f0900663a4aa9a79ba7203bdfda5ac71526f9c 上面結果中
06394379d741c96068edd55e598c1f31bc9b89c97d78d6d5da74bdce50faf77c 為 mountID。
隨后 GraphDriver 會將 diff 中屬于容器鏡像的所有層目錄以只讀方式掛載到 mnt 下,
然后在 diff 中生成一個以當前容器對應的
< mountID
> - init 命名的文件夾作為最后一層只讀層
root@ubuntu
: / var
/ lib
/ docker
/ aufs
/ diff
total
32
drwx
- - - - - - 8 root root
4096 Feb
7 09 : 56 . /
drwx
- - - - - - 5 root root
4096 Feb
7 09 : 22 . . /
drwxr
- xr
- x
4 root root
4096 Feb
7 09 : 56 06394379d741c96068edd55e598c1f31bc9b89c97d78d6d5da74bdce50faf77c /
drwxr
- xr
- x
6 root root
4096 Feb
7 09 : 56 06394379d741c96068edd55e598c1f31bc9b89c97d78d6d5da74bdce50faf77c - init
/
drwxr
- xr
- x
6 root root
4096 Feb
7 09 : 27 16f9270d0924771f8e389ff5f30738285d63ff46e4015b2dc1cfe592fbf9d814 /
drwxr
- xr
- x
3 root root
4096 Feb
7 09 : 27 4139a0b6d660f5602780be33fdbeb3fd9ba4e867949a7b38c1f135ad803b6740 /
drwxr
- xr
- x
3 root root
4096 Feb
7 09 : 27 59bc27fd2691f4cfdec635003f8fb71fc06d1c786d976d4283bb0a78e42315df /
drwxr
- xr
- x
21 root root
4096 Feb
7 09 : 27 65fa2339190e9406ce6dfeec14f0900663a4aa9a79ba7203bdfda5ac71526f9c / 接下來會在 diff 中生成一個以容器對應 mountID 為名的可讀寫目錄,也掛載到 mnt 目錄下。
所以,將來用戶在容器中新建文件就會出現在 mnt 下一 mountID 為名的目錄下,
而該層對應的實際內容則保存在 diff 目錄下。至此我們需要明確,所有文件的實際內容均保存在 diff 目錄下,
包括可讀寫層也會以 mountID 為名出現在 diff 目錄下,最終會整合到一起聯合掛載到 mnt 目錄下
以 mountID 為名的文件夾下。(
6 )接下來我們統一觀察 mnt 對應的 mountID 下的變化。
先創建一個容器:
root@ubuntu
: / var
/ lib
/ docker
/ aufs
/ diff
0a4b299bb8e8a27dad1f5d5ae54bcec44a4c65987561fe65d528993780192770
root@ubuntu
: / var
/ lib
/ docker
/ aufs
/ diff
root@ubuntu
: / var
/ lib
/ docker
/ aufs
/ diff
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0a4b299bb8e8 ubuntu
"bash" 5 seconds ago Created mycon比如我們得到的容器 ID 為:
0a4b299bb8e8a27dad1f5d5ae54bcec44a4c65987561fe65d528993780192770 ,
此時容器的狀態為
"Created" 。然后在
/ var
/ lib
/ docker
/ image
/ aufs
/ layerdb
/ mounts 目錄中,查看
0a4b299bb8e8a27dad1f5d5ae54bcec44a4c65987561fe65d528993780192770 目錄下 mount
- id 文件的內容如下:
root@ubuntu
: / var
/ lib
/ docker
/ image
/ aufs
/ layerdb
/ mounts
/ 0a4b299bb8e8a27dad1f5d5ae54bcec44a4c65987561fe65d528993780192770
443c2a7e1e731ae1347d00a76385bfb71881b4f6635440caa55c1063884c8d4broot@ubuntu
: / var
/ lib
/ docker
/ image
/ aufs
/ layerdb
/ mounts
/ 0a4b299bb8e8a27dad1f5d5ae54bcec44a4c65987561fe65d528993780192770 這就是容器層對應的 mountID。接下來查看容器運行前對應的 mnt 目錄:
root@ubuntu
: / var
/ lib
/ docker
/ aufs
/ mnt
4. 0K
. / 443c2a7e1e731ae1347d00a76385bfb71881b4f6635440caa55c1063884c8d4b
4. 0K
. / 443c2a7e1e731ae1347d00a76385bfb71881b4f6635440caa55c1063884c8d4b - init
此時 mountID 對應的文件夾下是空的接著,啟動一個容器
root@ubuntu
: / var
/ lib
/ docker
/ aufs
/ mnt
root@
0a4b299bb8e8 : /
root@ubuntu
: / var
/ lib
/ docker
/ aufs
/ mnt
root@ubuntu
: / var
/ lib
/ docker
/ aufs
/ mnt
70M
. / 443c2a7e1e731ae1347d00a76385bfb71881b4f6635440caa55c1063884c8d4b
4. 0K
. / 443c2a7e1e731ae1347d00a76385bfb71881b4f6635440caa55c1063884c8d4b - init容器層變大了,進入到文件夾中可以看到掛載好的文件系統:
root@
0a4b299bb8e8 : /
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var接著,在容器中創建文件
下面我們進入到容器中,創建一個 1G 大小的文件:
root@
0a4b299bb8e8 : /
1024 + 0 records
in
1024 + 0 records out
1073741824 bytes ( 1.1 GB
, 1.0 GiB
) copied
, 28.384 s
, 37.8 MB
/ s
root@
0a4b299bb8e8 : /
1. 1G test
. txt此時再來查看 mnt 下對應目錄的大小:
root@ubuntu
: / var
/ lib
/ docker
/ aufs
/ mnt
1. 1G
. / 443c2a7e1e731ae1347d00a76385bfb71881b4f6635440caa55c1063884c8d4b
4. 0K
. / 443c2a7e1e731ae1347d00a76385bfb71881b4f6635440caa55c1063884c8d4b - init最后,停止容器
root@ubuntu
: / var
/ lib
/ docker
/ aufs
/ mnt
mycon停止容器后,
/ var
/ lib
/ docker
/ aufs
/ mnt 目錄下對應的 mountID 目錄被卸載
( umount
) ,
此時該目錄為空。
root@ubuntu
: / var
/ lib
/ docker
/ aufs
/ mnt
4. 0K
. / 443c2a7e1e731ae1347d00a76385bfb71881b4f6635440caa55c1063884c8d4b
4. 0K
. / 443c2a7e1e731ae1347d00a76385bfb71881b4f6635440caa55c1063884c8d4b - init但是
/ var
/ lib
/ docker
/ aufs
/ diff 目錄下對應的目錄和文件都還存在。
root@ubuntu
: / var
/ lib
/ docker
/ aufs
/ diff
1. 1G
. / 443c2a7e1e731ae1347d00a76385bfb71881b4f6635440caa55c1063884c8d4b
28K
. / 443c2a7e1e731ae1347d00a76385bfb71881b4f6635440caa55c1063884c8d4b - init
注意:下面是aufs的image元數據中的所有鏡像層的rootfs,其diff_id可能對不上,重在理解 理解 docker aufs 驅動的主要存儲目錄和作用: 最后,當我們用 docker container commit 命令把容器提交成鏡像后,就會在 diff 目錄下生成一個新的 cacheID 命名的文件夾,它存放了最新的差異變化文件,這時一個新的鏡像層就誕生了。 而原來的以 mountID 為名的文件夾會繼續存在,直至對應容器被刪除。
(2)Device Mapper 這是一種從邏輯設備到物理設備的映射框架機制; Device Mapper本質功能就是:依據映射關系描述IO處理規則,當映射設備接收到IO請求時,該IO請求會依據映射表逐級轉發,直到該請求最終傳到最底層的物理設備上。
(
1 )devicemapper鏡像層結構解釋
devicemapper存儲驅動是使用Device Mapper的精簡配置和快照功能實現鏡像的分層。
資源池:使用了
2 個塊設備:一個用于存儲數據,另一個用于存儲元數據,構建資源池用以創建其它存儲鏡像的塊設備
數據區為生成其他塊設備提供資源;
元信息存儲了虛擬設備和物理設備的映射關系;
所有的容器層和鏡像層都有自己的塊設備,均是通過從其父鏡像層創建快照的方式來創建,父鏡像層的層從基礎設備創建快照。由于需要在塊設備中建卷等操作,我用的虛擬機沒法建立卷,因為已經掛載的卷我不敢動
(
2 )與aufs一樣,
在
/ var
/ lib
/ docker
/ devicemapper下有:
/ mnt為設備的額掛載目錄
metadata下存儲了每個設備驅動層的元數據信息在
/ var
/ lib
/ docker
/ image
/ devicemappe目錄下
存鏡像和邏輯鏡像層的元數據
(3)OverlayFS:允許用戶將一個文件系統與另一個文件系統重疊overlay,在上層的文件系統中記錄更改,而下層的文件系統保持不變。Docker中的overlay驅動如下圖
在上述圖中可以看到三個層結構,即:lowerdir、uperdir、merged,
其中lowerdir是只讀的image layer,其實就是rootfs,對比我們上述演示的目錄A和B,
我們知道image layer可以分很多層,所以對應的lowerdir是可以有多個目錄。而upperdir則是在lowerdir之上的一層,這層是讀寫層,在啟動一個容器時候會進行創建,
所有的對容器數據更改都發生在這里層,對比示例中的C。最后merged目錄是容器的掛載點,也就是給用戶暴露的統一視角,對比示例中的
/ tmp
/ test。
而這些目錄層都保存在了
/ var
/ lib
/ docker
/ overlay2
/ 或者
/ var
/ lib
/ docker
/ overlay
/
( 如果使用overlay
) 。
OverlayFS文件系統的相關測試如下
(
1 )查詢內核中是否存在overlay模塊
root@ubuntu
: /
overlay
77824 0 參考:https
: // www
. cnblogs
. com
/ wdliu
/ p
/ 10483252. html
overlayfs通過三個目錄:lower目錄、upper目錄、以及work目錄實現,
其中lower目錄可以是多個,work目錄為工作基礎目錄,掛載后內容會被清空,
且在使用過程中其內容用戶不可見,最后聯合掛載完成給用戶呈現的統一視圖稱為為merged目錄
創建三個目錄A、B、C
, 以及worker目錄:
root@ubuntu
: / tmp
/ demo
root@ubuntu
: / tmp
/ demo
root@ubuntu
: / tmp
/ demo
root@ubuntu
: / tmp
/ demo
root@ubuntu
: / tmp
/ demo
.
├── A
│ ├── aa
│ └── a
. test
├── B
│ └── b
. test
├── C
│ └── c
. test
└── worker
5 directories
, 3 files使用mount命令掛載
root@ubuntu
: / tmp
/ demo然后我們再去查看
/ tmp
/ test目錄,你會發現目錄A、B、C被合并到了一起
, 并且相同文件名的文
件會進行“覆蓋”,這里覆蓋并不是真正的覆蓋,而是當合并時候目錄中兩個文件名稱都相同時,
merged層目錄會顯示離它最近層的文件:
root@ubuntu
: / tmp
/ demo
root@ubuntu
: / tmp
/ test
.
├── aa
├── a
. text
├── b
. text
├── c
. textroot@ubuntu
: / tmp
/ test
from A(
2 )容器的演示
root@ubuntu
: / etc
/ docker
修改的內容:
ExecStart
= / usr
/ bin / dockerd
- - storage
- driver
= overlay2
- H fd
: // - - containerd
= / run
/ containerd
/ containerd
. sock
root@ubuntu
: / etc
/ dockerroot@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
/ mounts
WARNING
: No swap limit supportStorage Driver
: overlay2Network
: bridge host ipvlan macvlan null overlayroot@ubuntu
: / tmp
/ demo查看其overlay掛載點
, 可以發現其掛載的merged目錄、lowerdir、upperdir以及workdir:
root@ubuntu
: / tmp
/ demo
overlay on
/ var
/ lib
/ docker
/ overlay2
/ b290f8a0d1e53dc7e7d495b347a30f1289e351ccd330fd5da0d794eefb4a7926
/ merged
type overlay
( rw
, relatime
,
lowerdir
= / var
/ lib
/ docker
/ overlay2
/ l
/ OVHT2GRNO2EZLZG33UPVZJONJR
: / var
/ lib
/ docker
/ overlay2
/ l
/ M6LDBD7J7RZBSYKQ52RALHYCFR
: / var
/ lib
/ docker
/ overlay2
/ l
/ JZ3U2U6V2ODPCH3HYTR4RH3BF7
: / var
/ lib
/ docker
/ overlay2
/ l
/ MLRL6AS5MXCMHRM3OC35Y5LRAV
: / var
/ lib
/ docker
/ overlay2
/ l
/ YUWOUIQMUCDU4D5MYNGWW473GL
,
upperdir
= / var
/ lib
/ docker
/ overlay2
/ b290f8a0d1e53dc7e7d495b347a30f1289e351ccd330fd5da0d794eefb4a7926
/ diff
,
workdir
= / var
/ lib
/ docker
/ overlay2
/ b290f8a0d1e53dc7e7d495b347a30f1289e351ccd330fd5da0d794eefb4a7926
/ work
) (
3 )當容器中發生數據修改時候overlayfs存儲驅動又是如何進行工作的?
讀:
如果文件在容器層(upperdir),直接讀取文件;
如果文件不在容器層(upperdir),則從鏡像層(lowerdir)讀取;修改:
首次寫入: 如果在upperdir中不存在,overlay和overlay2執行copy_up操作,
把文件從lowdir拷貝到upperdir,由于overlayfs是文件級別的(即使文件只有很少的一點修改,
也會產生的copy_up的行為),后續對同一文件的在此寫入操作將對已經復制到容器的文件的副本進行操作。
這也就是常常說的寫時復制(copy
- on
- write)
刪除文件和目錄: 當文件在容器被刪除時,在容器層(upperdir)創建whiteout文件,
鏡像層
( lowerdir
) 的文件是不會被刪除的,因為他們是只讀的,但without文件會阻止他們顯示,
當目錄在容器內被刪除時,在容器層(upperdir)一個不透明的目錄,
這個和上面whiteout原理一樣,阻止用戶繼續訪問,即便鏡像層仍然存在。 注意事項
(a)copy_up操作只發生在文件首次寫入,以后都是只修改副本
,
(b)overlayfs只適用兩層目錄,
, 相比于比AUFS,查找搜索都更快。
(c)容器層的文件刪除只是一個“障眼法”,是靠whiteout文件將其遮擋
, image層并沒有刪除,
這也就是為什么使用docker commit 提交保存的鏡像會越來越大,無論在容器層怎么刪除數據,
image層都不會改變。 (
4 )overlay2鏡像存儲結構
pull的鏡像的所有層都在這里
root@ubuntu
: / tmp
/ demo
total
184
drwx
- - - - - - 46 root root
4096 Feb
6 16 : 54 . /
drwx
- - x
- - x
14 root root
4096 Feb
6 16 : 54 . . /
drwx
- - - - - - 4 root root
4096 Feb
4 23 : 18 123c6e8619f78d854a9508d83209b239d0cd45a8df9d4dfb1a597b0c03e7b5af /
drwx
- - - - - - 4 root root
4096 Feb
4 15 : 38 123c6e8619f78d854a9508d83209b239d0cd45a8df9d4dfb1a597b0c03e7b5af - init
/
. . . . 這里面多了一個l目錄包含了所有層的軟連接,短鏈接使用短名稱,避免mount時候參數達到頁面大小限制
root@ubuntu
: / tmp
/ demo
total
180
drwx
- - - - - - 2 root root
4096 Feb
6 16 : 21 . /
drwx
- - - - - - 46 root root
4096 Feb
6 16 : 54 . . /
lrwxrwxrwx
1 root root
72 Feb
1 16 : 40 456JAXBHVS3JHXRZFZ4LXP4OOZ
- > . . / ac90d6ede0b864ef666050b1e8980d41c5fb8daa9a01459bb2494d3fa549a9b1
/ diff
/
lrwxrwxrwx
1 root root
72 Feb
4 15 : 37 4CSNIDNNPSX2NO7OQ6TUCC6VSW
- > . . / 6edfae29cca3fd2d621d18658cc22a9e02697b86c66af60de05538b307449216 / diff
/
lrwxrwxrwx
1 root root
72 Feb
3 17 : 28 5YY33SJ3A3JNXPT2HHINC5NCRR
- > . . / 4ea285ea7a639ae2c7f2957d42fa42e99cb043c1f9c40c6116e4b39e991763a4 / diff
/
lrwxrwxrwx
1 root root
72 Feb
3 17 : 21 65ZYEDM4K772KYCMM7FM2UCUVY
- > . . / ea812cc72aafe62062855a1ed4627276dd543a3d792a1824be3e6374f93756f4
/ diff
/
lrwxrwxrwx
1 root root
72 Feb
1 17 : 28 67V34XWNBPMSZHLPENWF2V24HZ
- > . . / b0ef105b999d7c79b14597bd36954768b04dbe93f6aa100f8a0c7ae333ce3224
/ diff
/
lrwxrwxrwx
1 root root
72 Feb
4 15 : 36 6BOFETT6YGPKBKQROMSRS5W4KK
- > . . / 1a6d97004e6e9087f0e8516072afe2db07709818d1eb009ed1a48fd8025d668e / diff
/
lrwxrwxrwx
1 root root
72 Feb
5 16 : 07 6NBISRY3PPDIWABZI3YIPPSOI3
- > . . / aa72293e2126cffe4742775f212c489512d540f39e01b5b3a330ea2c1658a4fe
/ diff
/
lrwxrwxrwx
1 root root
72 Feb
4 15 : 37 6SLLLZPLJYRI6LI3VPDKHZZTJQ
- > . . / c69b5f0de3677526dbb0c635e157cac4b2612e4d9b39156e673f6c68ab845008
/ diff
/
lrwxrwxrwx
1 root root
72 Feb
1 17 : 28 7VBMC2I47YQVC3BJTUTL7YQBGI
- > . . / 42fa3c0843a115b4b84aa13cf7e7c8ce6a14361e21aa4e34d793723f0d90e021 / diff
/ 處于底層的鏡像目錄包含了一個diff和一個link文件,
diff目錄存放了當前層的鏡像內容,
link文件則是與之對應的短名稱,
lower文件用于記錄父層的短名稱,
work目錄用于聯合掛載指定的工作目錄
而這些目錄和鏡像的關系是怎么組織在的一起呢?答案是通過元數據關聯。
元數據分為image元數據和layer元數據。
root@ubuntu
: / tmp
/ demo
diff link lower work(
5 )image元數據
名稱是以鏡像ID命名的文件,鏡像ID可通過docker images查看,這些文件以json的形
式保存了該鏡像的rootfs信息、鏡像創建時間、構建歷史信息、所用容器、包括啟動的
Entrypoint和CMD等等
root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ imagedb
/ content
/ sha256
REPOSITORY TAG IMAGE ID CREATED SIZE
redis latest
44d36d2c2374 4 days ago
98. 2MB
haproxy latest
9b5ff4593b4e 4 days ago
92. 3MB
ubuntu latest ccc6e87d482b
3 weeks ago
64. 2MB
httpd latest c2aa7e16edd8
5 weeks ago 165MB
busybox latest
6d5fcfe5ff17 5 weeks ago
1. 22MB
hello
- world latest fce289e99eb9
13 months ago
1. 84kB
django latest eb40dcf64078
3 years ago 436MB鏡像元數據存儲的位置:
root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ imagedb
/ content
/ sha256
total
52
drwx
- - - - - - 2 root root
4096 Feb
3 17 : 46 . /
drwx
- - - - - - 3 root root
4096 Jan
23 19 : 10 . . /
- rw
- - - - - - - 1 root root
6864 Feb
3 17 : 28 44d36d2c2374b240abcf5da2130abf49938b8fb49446df6eec028718520332ef
- rw
- - - - - - - 1 root root
1497 Feb
1 16 : 40 6d5fcfe5ff170471fcc3c8b47631d6d71202a1fd44cf3c147e50c8de21cf0648
- rw
- - - - - - - 1 root root
4990 Feb
3 17 : 46 9b5ff4593b4e4cbc4506e7ca65f1ffd78aecd97cbf15cb32eda4a0baa1ebf451
- rw
- - - - - - - 1 root root
7351 Feb
1 17 : 28 c2aa7e16edd855da8827aa0ccf976d1d50f0827c08622c16e0750aa1591717e5
- rw
- - - - - - - 1 root root
3407 Jan
23 21 : 20 ccc6e87d482b79dd1645affd958479139486e47191dfe7a997c862d89cd8b4c0
- rw
- - - - - - - 1 root root
6263 Feb
3 17 : 21 eb40dcf64078249a33f68fdd8d80624cb81b524c24f50b95fff5c2b40bdc3fdc
- rw
- - - - - - - 1 root root
1510 Jan
23 21 : 02 fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587eeg:
root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ imagedb
/ content
/ sha256
。。。。
] , "os" : "linux" , "rootfs" : { "diff_ids" : [ "sha256:488dfecc21b1bc607e09368d2791cb784cf8c4ec5c05d2952b045b3e0f8cc01e" , "sha256:6d35c327901c03885dc2646367382a9cf90b77e07fb5bc1347905eed9a9f464b" , "sha256:35e1c7a160662fc0b9a97d6cd893978b6a531d81bede805e47fcae1a06ebe751" , "sha256:9f839e56c43407961d93dcb97372ffbe5abf7b313f0db9d4328770b1e5caaeab" , "sha256:d7344f36256ca9a11964e67a4b16fb51e147c69bf4f7b9f3e150f5d13c64f781" , "sha256:0233556febffa2d711e3f9d34f3daaab58063987b910232728bbea71ba5906bb" ] , "type" : "layers" }
}
上面的 diff_id 對應的的是一個鏡像層,其排列也是有順序的,從上到下依次表示鏡像層的最低層到最頂層,
這也是rootfs的內容diff_id如何關聯進行層?
具體說來,docker 利用 rootfs 中的每個diff_id 和歷史信息計算出與之對應的內容尋址的
索引
( chainID
) ,而chaiID則關聯了layer層,進而關聯到每一個鏡像層的鏡像文件。(
6 )layer元數據
layer 對應鏡像層的概念,
鏡像層只包含一個具體的鏡像層文件包。
用戶在 docker 宿主機上下載了某個鏡像層之后,docker 會在宿主機上基于鏡像層文件包和
image 元數據構建本地的 layer 元數據,包括 diff、parent、size 等。
而當 docker 將在宿主機上產生的新的鏡像層上傳到 registry 時,
與新鏡像層相關的宿主機上的元數據也不會與鏡像層一塊打包上傳。Docker 中定義了 Layer 和 RWLayer 兩種接口,分別用來定義只讀層和可讀寫層的一些操作,
又定義了 roLayer 和 mountedLayer,分別實現了上述兩種接口。
其中,roLayer 用于描述不可改變的鏡像層,mountedLayer 用于描述可讀寫的容器層。
具體來說,roLayer 存儲的內容主要有索引該鏡像層的 chainID、該鏡像層的校驗碼 diffID、
父鏡像層 parent、storage_driver 存儲當前鏡像層文件的 cacheID、該鏡像層的 size 等內容。這些元數據被保存在
root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
/ sha256
total
108
drwxr
- xr
- x
27 root root
4096 Feb
3 17 : 32 . /
drwx
- - - - - - 5 root root
4096 Jan
23 21 : 11 . . /
drwx
- - - - - - 2 root root
4096 Feb
1 17 : 28 06020df9067f8f2547f53867de8e489fed315d964c9f17990c3e5e6a29838d98 /
drwx
- - - - - - 2 root root
4096 Feb
3 17 : 21 16e6b55f22cca357d6d1c156ffde240ebd570d707409b959bdd5791ebe8d6968 /
drwx
- - - - - - 2 root root
4096 Feb
1 16 : 40 195be5f8be1df6709dafbba7ce48f2eee785ab7775b88e0c115d8205407265c5 /
drwx
- - - - - - 2 root root
4096 Feb
3 17 : 28 31a81e216e79c54ea97523674895bf12d76e1b8cbb20e2ca1ced60925744a161 / 每個chainID目錄下會存在三個文件cache
- id 、diff、zize:cache
- id 文件:
docker隨機生成的uuid,內容是保存鏡像層的目錄索引,
也就是
/ var
/ lib
/ docker
/ overlay2
/ 中的目錄,這就是為什么通過chainID能找到對應的layer目錄。
以chainID為
06020df9067f8f2547f53867de8e489fed315d964c9f17990c3e5e6a29838d98 所對應的目錄:
b0ef105b999d7c79b14597bd36954768b04dbe93f6aa100f8a0c7ae333ce3224,
保存在:
/ var
/ lib
/ docker
/ overlay2
/ bd36954768b04dbe93f6aa100f8a0c7ae333ce3224root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
/ sha256
b0ef105b999d7c79b14597bd36954768b04dbe93f6aa100f8a0c7ae333ce3224root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
/ sha256diff文件:
保存了鏡像元數據中的diff_id(與元數據中的diff_ids中的uuid對應)
root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
/ sha256
sha256
: 525297c1b6d2bad3afab694c55c2ba5e11bdb567e1c270494f662ed8bd55b9c9root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
/ sha256size文件:
保存了鏡像層的大小
sha256
: 525297c1b6d2bad3afab694c55c2ba5e11bdb567e1c270494f662ed8bd55b9c9root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
/ sha256
0root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
/ sha256(
7 )mountedLayer 信息存儲的可讀init層以及容器掛載點信息包括:
容器 init 層ID(init
- id )、
聯合掛載使用的ID(mount
- id )以及容器層的父層鏡像的 chainID
( parent
) 。
相關文件位于:
root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
/ sha256
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
729f0d3454a8 ubuntu
"/bin/bash" 3 hours ago Up
2 hours wangji1root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
/ mounts
total
44
drwxr
- xr
- x
11 root root
4096 Feb
6 16 : 21 . /
drwx
- - - - - - 5 root root
4096 Jan
23 21 : 11 . . /
drwxr
- xr
- x
2 root root
4096 Feb
4 15 : 38 171b215cd75aafadc82c61f83ed44290e87830fb4cf03cad2a1e3908a05d29d1 /
drwxr
- xr
- x
2 root root
4096 Feb
6 16 : 21 729f0d3454a8f66d20fee88994b167603041f5a350c68aa21f8817d3eb94f9fd /
drwxr
- xr
- x
2 root root
4096 Feb
6 16 : 09 8eb9fd0012b3ab2475fa37a1aa081252544d5941403301dd8f68c9a722f6e551 /
drwxr
- xr
- x
2 root root
4096 Feb
4 15 : 35 查看其對應的mountedLayer三個文件:
root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
/ mounts
init
- id mount
- id parent可以看到initID是在mountID后加了一個
- init,
同時initID就是存儲在
/ var
/ lib
/ docker
/ overlay2
/ 的目錄名稱:
root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
/ mounts
total
184
drwx
- - - - - - 46 root root
4096 Feb
6 16 : 54 . /
drwx
- - x
- - x
14 root root
4096 Feb
6 16 : 54 . . /
drwx
- - - - - - 4 root root
4096 Feb
4 23 : 18 123c6e8619f78d854a9508d83209b239d0cd45a8df9d4dfb1a597b0c03e7b5af /
drwx
- - - - - - 4 root root
4096 Feb
4 15 : 38 123c6e8619f78d854a9508d83209b239d0cd45a8df9d4dfb1a597b0c03e7b5af - init
/
drwx
- - - - - - 4 root root
4096 Feb
4 23 : 18 1a6d97004e6e9087f0e8516072afe2db07709818d1eb009ed1a48fd8025d668e /
drwx
- - - - - - 4 root root
4096 Feb
4 15 : 36 1a6d97004e6e9087f0e8516072afe2db07709818d1eb009ed1a48fd8025d668e - init
/ 查看mountID還可以直接通過mount命令查看對應掛載的mountID,
對應著
/ var
/ lib
/ docker
/ overlay2
/ 目錄,這也是overlayfs呈現的merged目錄
oot@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
/ mounts
overlay on
/ var
/ lib
/ docker
/ overlay2
/ b290f8a0d1e53dc7e7d495b347a30f1289e351ccd330fd5da0d794eefb4a7926
/ merged ty在容器中創建了一文件,
root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
/ mounts
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
729f0d3454a8 ubuntu
"/bin/bash" 3 hours ago Up
2 hours wangji1
root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
/ layerdb
/ mounts
root@
729f0d3454a8 : /
root@
729f0d3454a8 : / 此時到宿主的merged目錄就能看到對應的文件:
root@ubuntu
: / var
/ lib
/ docker
/ image
/ overlay2
root@ubuntu
: / var
/ lib
/ docker
/ overlay2
root@ubuntu
: / var
/ lib
/ docker
/ overlay2
/ b290f8a0d1e53dc7e7d495b347a30f1289e351ccd330fd5da0d794eefb4a7926
total
28
drwx
- - - - - - 5 root root
4096 Feb
6 17 : 46 . /
drwx
- - - - - - 46 root root
4096 Feb
6 16 : 54 . . /
drwxr
- xr
- x
3 root root
4096 Feb
6 16 : 21 diff
/
- rw
- r
- - r
- - 1 root root
26 Feb
6 16 : 21 link
- rw
- r
- - r
- - 1 root root
144 Feb
6 16 : 21 lower
drwxr
- xr
- x
1 root root
4096 Feb
6 16 : 21 merged
/
drwx
- - - - - - 3 root root
4096 Feb
6 17 : 46 work
/
root@ubuntu
: / var
/ lib
/ docker
/ overlay2
/ b290f8a0d1e53dc7e7d495b347a30f1289e351ccd330fd5da0d794eefb4a7926
root@ubuntu
: / var
/ lib
/ docker
/ overlay2
/ b290f8a0d1e53dc7e7d495b347a30f1289e351ccd330fd5da0
root@ubuntu
: / var
/ lib
/ docker
/ overlay2
/ b290f8a0d1e53dc7e7d495b347a30f1289e351ccd330fd5da0d794eefb4a7926
/ diff
wangji docker(
8 )關于init層
nit層是以一個uuid
+ - init結尾表示,夾在只讀層和讀寫層之間,作用是專門存放
/ etc
/ hosts、
/ etc
/ resolv
. conf等信息,需要這一層的原因是當容器啟動時候,
這些本該屬于image層的文件或目錄,比如hostname,用戶需要修改,但是image層又不允許修改,
所以啟動時候通過單獨掛載一層init層,通過修改init層中的文件達到修改這些文件目的。
而這些修改往往只讀當前容器生效,而在docker commit提交為鏡像時候,并不會將init層提交。
該層文件存放的目錄為
/ var
/ lib
/ docker
/ overlay2
/ < init_id
> / diff
總結: 一個容器完整的層應由三個部分組成,如下圖:
鏡像層:也稱為rootfs,提供容器啟動的文件系統
init層: 用于修改容器中一些文件如
/ etc
/ hostname、
/ etc
/ resolv
. conf等
容器層:使用聯合掛載統一給用戶提供的可讀寫目錄。
總結
以上是生活随笔 為你收集整理的(第3章)Docker核心原理解读 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。