一. 簡介
開篇,先給出一個結(jié)論:容器是一個“單進(jìn)程”模型。一個正在運(yùn)行的 Docker 容器,其實(shí)就是一個啟用了多個 Linux Namespace 的應(yīng)用進(jìn)程,而這個進(jìn)程能夠使用的資源量,則受 Cgroups 配置的限制。
關(guān)于Namespace和Cgroups這倆功能的聯(lián)合使用,實(shí)現(xiàn)了Docker所謂的 偽“虛擬化”。
二. Namespace
Namespace是Linux內(nèi)核的功能之一,也是Linux上容器的基本方面。另一方面,Namespace提供了一層隔離。Docker使用各種Namespace來提供容器所需的隔離,以便保持可移植性并避免影響主機(jī)系統(tǒng)的其余部分。容器的每個方面都在單獨(dú)的Namespace中運(yùn)行,并且對其的訪問僅限于該Namespace。
2.1 clone()函數(shù)
Namespace 的使用方式也特別:它其實(shí)只是 Linux 創(chuàng)建新進(jìn)程的一個可選參數(shù)。
在 Linux 系統(tǒng)中創(chuàng)建線程的系統(tǒng)調(diào)用是 clone(),比如:
int pid = clone(main_function, stack_size, SIGCHLD, NULL);
這個系統(tǒng)調(diào)用就會為我們創(chuàng)建一個新的進(jìn)程,并且返回它的進(jìn)程號 pid。而當(dāng)我們用 clone() 系統(tǒng)調(diào)用創(chuàng)建一個新進(jìn)程時,就可以在參數(shù)中指定 CLONE_NEWPID參數(shù),比如:
int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL);
2.2 原理
例如上面案例,新創(chuàng)建的這個進(jìn)程將會“看到”一個全新的進(jìn)程空間,在這個進(jìn)程空間里,它的 PID 是 1。之所以說“看到”,是因?yàn)檫@只是一個“障眼法”,在宿主機(jī)真實(shí)的進(jìn)程空間里,這個進(jìn)程的 PID 還是真實(shí)的數(shù)值,比如 100。
2.3 Namespace分類
Namespace類型如下:
- Process ID
- Mount
- IPC (Interprocess communication)
- User (currently experimental support for)
- Network
2.4 小結(jié)
實(shí)際上在創(chuàng)建容器進(jìn)程時,Docker指定了這個進(jìn)程所需要啟用的一組 Namespace 參數(shù)。這樣,容器就只能“看”到當(dāng)前 Namespace 所限定的資源、文件、設(shè)備、狀態(tài),或者配置。而對于宿主機(jī)以及其他不相關(guān)的程序,它就完全看不到了。
三. Cgroups
Linux Cgroups的全稱是 Linux Control Group。它最主要的作用,就是限制一個進(jìn)程組能夠使用的資源上限,包括 CPU、內(nèi)存、磁盤、網(wǎng)絡(luò)帶寬等等,Cgroups 還能夠?qū)M(jìn)程進(jìn)行優(yōu)先級設(shè)置、審計,以及將進(jìn)程掛起和恢復(fù)等操作。
3.1 查看cgroup文件
在 Linux 中,Cgroups 給用戶暴露出來的操作接口是文件系統(tǒng),即它以文件和目錄的方式組織在操作系統(tǒng)的 /sys/fs/cgroup路徑下。
我們可以通過如下指令查看
mount -t cgroup
在 /sys/fs/cgroup下面有很多諸如cpuset、cpu、 memory這樣的子目錄,也叫子系統(tǒng)。這些都是當(dāng)前機(jī)器當(dāng)前可以被 Cgroups 進(jìn)行限制的資源種類。
3.2 限制資源
在子系統(tǒng)對應(yīng)的資源種類下,我們就可以看到該類資源具體可以被限制的方法。
- 查看配置文件
對 CPU 子系統(tǒng)來說,使用如下指令查看對應(yīng)的配置文件:
ls /sys/fs/cgroup/cpu
(由于暫無對應(yīng)展示系統(tǒng),所以此處是引用自網(wǎng)上指令結(jié)果)我們會查看到這些文件:
cgroup.clone_children cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_releasecgroup.procs cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks
目標(biāo)參數(shù)
關(guān)于上面內(nèi)容,cfs_period 和 cfs_quota 這兩個參數(shù)需要組合使用,可以用來限制進(jìn)程在長度為 cfs_period 的一段時間內(nèi),只能被分配到總量為 cfs_quota 的 CPU 時間。配置限制參數(shù)
我們已經(jīng)找到了目標(biāo)配置,此刻我們可以向?qū)?yīng)的配置文件寫入限制參數(shù)即可。
指令如下:
echo 30000 > /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us
在每 100 ms 的時間里,被該控制組限制的進(jìn)程只能使用 30 ms 的 CPU 時間,也就是說這個進(jìn)程只能使用到 30% 的 CPU 帶寬。
- 配置tasks
我們把被限制的進(jìn)程的 PID(task-id) 寫入 container 組里的 tasks 文件,上面的設(shè)置就會對該進(jìn)程生效了:
echo task-id > /sys/fs/cgroup/cpu/container/tasks
task-id就是我們填寫我們被限制的進(jìn)程號。
Cgroup在容器空間內(nèi)提供資源限制和報告功能。它們允許對哪些主機(jī)資源分配給容器以及何時分配容器進(jìn)行精細(xì)控制。
3.3 Cgroups類型
常見的Cgroups管理的資源類型如下:
- CPU
- Memory
- Network Bandwidth
- Disk
- Priority
3.4 小結(jié)
Linux Cgroups就是一個子系統(tǒng)目錄加上一組資源限制文件的組合。它們只需要在每個子系統(tǒng)下面,為每個容器創(chuàng)建一個控制組(即創(chuàng)建一個新目錄),然后在啟動容器進(jìn)程之后,把這個進(jìn)程的PID填寫到對應(yīng)控制組的tasks文件中就可以了。
四. 總結(jié)
容器,其實(shí)是一種特殊的進(jìn)程而已。所以,Docker其實(shí)沒有那么神話,也沒有那么的高門檻。對比虛擬機(jī),“敏捷”和“高性能”是容器最大的優(yōu)勢。
本文關(guān)于Namespace和Cgroups的講解非常粗淺,Linux相關(guān)基礎(chǔ)還是非常深的,終于明白Linux為啥這么優(yōu)秀。
換句話說,容器本身沒有價值,有價值的是“容器編排”,這將是后面文章關(guān)于Kubernetes的開始。
最后,歡迎關(guān)注我的博客:https://blog.wyatt.plus
Reference
https://medium.com/@kasunmaduraeng/docker-namespace-and-cgroups-dece27c209c7
https://coolshell.cn/articles/17010.html