Docker 依賴的linux內核技術


更好的閱讀體驗建議點擊下方原文鏈接。
原文鏈接:http://maoqide.live/post/cloud/docker-%E5%8E%9F%E7%90%86/

  • Namespace
  • Cgroup
  • UnionFS

docker 的實現,主要依賴 linux 的 namespace、cgroup 和 unionFS 三種技術實現,達到容器的環境隔離、資源控制和鏡像打包。

Namespace

Namespace 隔離內容
UTS 主機名與域名
IPC 信號量、消息隊列和共享內存
PID 進程編號
Network 網絡設備、網絡棧、端口等
Mount 掛載點(文件系統)
User 用戶和用戶組

Cgroup

  • blkio: 為塊設備設定輸入輸出/限制,比如物理驅動設備(包括磁盤、固態硬盤、USB等)
  • cpu: 使用調度程序控制任務對 CPU 的使用
  • cpuacct: 自動生成 cgroup 中任務對 CPU 資源使用情況的報告
  • cpuset: 為 cgroup 中的任務分配獨立的 CPU 和內存
  • devices: 可以開啟或關閉 cgroup 中任務對設備的訪問
  • freezer: 可以掛起或恢復 cgroup 中的任務
  • memory: 可以設定 cgroup 中任務對內存使用量的限定,並且自動生成這些任務對內存資源使用情況的報告
  • perf_event: 使用后使 cgroup 中的任務可以進行統一的性能測試
  • net_cls: Docker 沒有直接使用它,它通過使用等級識別符(classid)標記網絡數據包,從而允許 Linux 流量控制程序識別從具體 cgroup 中生成的數據包

子系統文件

公共

  • tasks: 這個文件羅列所有該 cgroup 中任務的 TID,即所有線程或進程的 ID
  • cgroup.procs: 這個文件羅列所有該 cgroup 中的線程組ID(TGID), 及線程組中第一個進程的ID
  • notify_on_release: 0或1,表示是否在 cgroup 中最后一個任務退出時通知運行 release agent, 默認0, 表示不運行
  • release_agent: 指定 release agent 執行腳本的文件路徑,這個腳本通常用於自動化卸載無用的 cgroup

cpu

cpu子系統根據進程設置的調度屬性,選擇對應的CPU資源調度方法。

  1. 完全公平調度 Completely Fair Scheduler (CFS)
    限上限,cpu.cfs_period_us, cpu.cfs_quota_us
    cpu.cfs_period_us = 統計CPU使用時間的周期
    cpu.cfs_quota_us = 周期內允許占用的CPU時間(指單核的時間, 多核則需要在設置時累加)

CFS 用於處理以下幾種進程調度策略:

  • SCHED_OTHER
  • SCHED_BATCH
  • SCHED_IDLE

cfs_period_us用來配置時間周期長度, cfs_quota_us用來配置當前 cgroup 在設置的周期長度內所能使用的 CPU 時間數,兩個文件配合起來設置 CPU 的使用上限。兩個文件的單位都是微秒(us),cfs_period_us的取值范圍為1毫秒(ms)到1秒(s),cfs_quota_us的取值大於 1ms 即可,如果 cfs_quota_us 的值為 -1(默認值),表示不受 cpu 時間的限制。
例:

#設置只能使用1個cpu的20%的時間
echo 50000 > cpu.cfs_period_us
echo 10000 > cpu.cfs_quota_us
#設置完全使用4個cpu的時間
echo 1000000 > cpu.cfs_period_us
echo 4000000 > cpu.cfs_quota_us
  1. 實時調度 Real-Time scheduler (RT)
    限實時任務上限,cpu.rt_period_us,cpu.rt_runtime_us
    cpu.rt_period_us = 統計CPU使用時間的周期
    cpu.rt_runtime_us = 周期內允許任務使用單個CPU核的時間,如果系統中有多個核,則可以使用核倍數的時間 (計算方法與cfs不一樣,需要注意)

RT用於處理以下幾種進程調度策略

  • SCHED_FIFO
  • SCHED_RR
  1. cpu.shares
    shares用來設置CPU的相對值,並且是針對所有的CPU(內核),默認值是1024。
    假如系統中有兩個cgroup,分別是A和B,A的shares值是1024,B的shares值是512,那么A將獲得1024/(1204+512)=66%的CPU資源,而B將獲得33%的CPU資源。
    shares有兩個特點:
  • 如果A不忙,沒有使用到66%的CPU時間,那么剩余的CPU時間將會被系統分配給B,即B的CPU使用率可以超過33%
  • 如果添加了一個新的cgroup C,且它的shares值是1024,那么A的限額變成了1024/(1204+512+1024)=40%,B的變成了20%
  1. cpu.stat
    包含了下面三項統計結果:
    nr_periods: 表示過去了多少個cpu.cfs_period_us里面配置的時間周期
    nr_throttled: 在上面的這些周期中,有多少次是受到了限制(即cgroup中的進程在指定的時間周期中用光了它的配額)
    throttled_time: cgroup中的進程被限制使用CPU持續了多長時間(納秒)

memory

 cgroup.event_control       #用於eventfd的接口
 memory.usage_in_bytes      #顯示當前已用的內存
 memory.limit_in_bytes      #設置/顯示當前限制的內存額度
 memory.failcnt             #顯示內存使用量達到限制值的次數
 memory.max_usage_in_bytes  #歷史內存最大使用量
 memory.soft_limit_in_bytes #設置/顯示當前限制的內存軟額度
 memory.stat                #顯示當前cgroup的內存使用情況
 memory.use_hierarchy       #設置/顯示是否將子cgroup的內存使用情況統計到當前cgroup里面
 memory.force_empty         #觸發系統立即盡可能的回收當前cgroup中可以回收的內存
 memory.pressure_level      #設置內存壓力的通知事件,配合cgroup.event_control一起使用
 memory.swappiness          #設置和顯示當前的swappiness
 memory.move_charge_at_immigrate #設置當進程移動到其他cgroup中時,它所占用的內存是否也隨着移動過去
 memory.oom_control         #設置/顯示oom controls相關的配置
 memory.numa_stat           #顯示numa相關的內存

cpuacct

cpuacct.usage      			#所有cpu核的累加使用時間(nanoseconds)  
cpuacct.usage_percpu 	    #針對多核,輸出的是每個CPU的使用時間(nanoseconds)  
cpuacct.stat       			#輸出系統(system/kernel mode)耗時和用戶(user mode)耗時 , 單位為USER_HZ。 

Storage Driver

aufs(UnionFS)

  • 容器啟動速度很快
  • 存儲空間利用很高效
  • 內存的利用很高效

讀寫:寫時復制
刪除:whiteout 屏蔽

Docker 鏡像的各層的全部內容都存儲在/var/lib/docker/aufs/diff/<image-id>文件夾下,每個文件夾下包含了該鏡像層的全部文件和目錄,文件以各層的 UUID 命名。
正在運行的容器的文件系統被掛載在/var/lib/docker/aufs/mnt/<container-id>文件夾下,這就是 AUFS 的聯合掛載點,在這里的文件夾下,你可以看到容器文件系統的所有文件。如果容器沒有在運行,它的掛載目錄仍然存在,不過是個空文件夾。
容器的元數據各種配置文件被放在/var/lib/docker/containers/<container-id>文件夾下,無論容器是運行還是停止都會有一個文件夾。如果容器正在運行,其對應的文件夾下會有一個 log 文件。
容器的只讀層存儲在/var/lib/docker/aufs/diff/<container-id>目錄下,對容器的所有修改都會保存在這個文件夾下,即便容器停止,這個文件夾也不會刪除。也就是說,容器重啟后並不會丟失原先的更改。
容器中鏡像層的信息存儲在/var/lib/docker/aufs/layers/<container-id>文件中。文件中從上至下依次記錄了容器使用的各鏡像層。

性能表現

  • 在容器密度比較告的場景下,AUFS 是非常好的選擇,因為AUFS的容器間共享鏡像層的特性使其磁盤利用率很高,容器的啟動時間很短
  • AUFS 中容器之間的共享使對系統頁緩存的利用率很高
  • AUFS 的寫時復制策略會帶來很高的性能開銷,因為 AUFS 對文件的第一次更改需要將整個文件復制帶讀寫層,當容器層數很多或文件所在目錄很深時尤其明顯

device mapper

device mapper工作在塊層次上而不是文件層次上,這意味着它的寫時復制策略不需要拷貝整個文件。
在device mapper中,對容器的寫操作由需要時分配策略完成。更新已有數據由寫時復制策略完成,這些操作都在塊的層次上完成,每個塊的大小為64KB。

需要時分配(allocate-on-demand)

每當容器中的進程需要向容器寫入數據時,device mapper就從資源池中分配一些數據塊並將其映射到容器。當容器頻繁進行小數據的寫操作時,這種機制非常影響影響性能。

寫時復制(copy-on-write)

device mapper的寫時復制策略以64KB作為粒度,意味着無論是對32KB的文件還是對1GB大小的文件的修改都僅復制64KB大小的文件。這相對於在文件層面進行的讀操作具有很明顯的性能優勢。但是,如果容器頻繁對小於64KB的文件進行改寫,device mapper的性能是低於aufs的。

overlayfs(UnionFS)

OverlayFS與AUFS相似,也是一種聯合文件系統(union filesystem),與AUFS相比,OverlayFS:

  • 設計更簡單
  • 被加入Linux3.18版本內核
  • 可能更快

OverlayFS 將一個 Linux 主機中的兩個目錄組合起來,一個在上,一個在下,對外提供統一的視圖。這兩個目錄就是層layer,將兩個層組合在一起的技術被成為聯合掛載union mount。在OverlayFS中,上層的目錄被稱作upperdir,下層的目錄被稱作lowerdir,對外提供的統一視圖被稱作merged

OverlayFS 僅有兩層,也就是說鏡像中的每一層並不對應 OverlayFS 中的層,而是鏡像中的每一層對應/var/lib/docker/overlay中的一個文件夾,文件夾以該層的 UUID 命名。然后使用硬連接將下面層的文件引用到上層。這在一定程度上節省了磁盤空間。這樣 OverlayFS中 的lowerdir就對應鏡像層的最上層,並且是只讀的。在創建鏡像時,Docker 會新建一個文件夾作為OverlayFS的upperdir,它是可寫的。

讀寫:第一次修改時,文件不在container layer(upperdir)中,overlay driver 調用copy-up操作將文件從lowerdir讀到upperdir中,然后對文件的副本做出修改。
overlay的copy-up操作工作在文件層面, 對文件的修改需要將整個文件拷貝到upperdir中。

  • copy-up操作僅發生在文件第一次被修改時,此后對文件的讀寫都直接在upperdir中進行
  • overlayfs中僅有兩層,這使得文件的查找效率很高(相對於aufs)。
    刪除:whiteout 覆蓋

參考

https://yq.aliyun.com/articles/54483
https://segmentfault.com/a/1190000008323952
https://blog.csdn.net/vchy_zhao/article/details/70238690


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM