深入理解Docker和K8S
Docker 是大型架構的必備技能,也是云原生核心。Docker 容器化作為一種輕量級的虛擬化技術,其核心思想:將應用程序及其所有依賴項打包在一起,形成一個可移植的單元。
容器的本質是進程:
容器是在 Linux 宿主機上運行的一個進程,
- 容器的鏡像中定義了容器啟動時運行的程序。
- 在啟動時,被設置了新的 NameSpace、IPC、Network、PID、Mount、UTS,所以容器所能看到的進程,網絡、磁盤掛載,都與宿主機不同。
通過 Linux 提供的三大核心機制實現:
1.Namespace:實現資源隔離Namespace是Linux內核提供的資源隔離機制,為容器創建獨立的系統資源視圖,包括:PID Namespace:隔離進程ID,容器內進程只能看到本容器進程。Network Namespace:隔離網絡棧,容器擁有獨立的網絡接口和IP。Mount Namespace:隔離文件系統掛載點,容器有獨立文件系統視圖。User Namespace:隔離用戶和組ID,提升安全性。IPC、UTS等 Namespace:隔離進程間通信、主機名等資源。通過Namespace,Docker容器實現進程、網絡、文件系統等多維度的隔離,保證容器間互不干擾。
2.Cgroups:資源限制與配額Cgroups是Linux內核的資源管理機制,用于限制和監控容器的資源使用,包括CPU、內存、磁盤I/O和網絡帶寬。它保證容器不會超出分配資源,防止資源爭搶和系統過載。Cgroups支持資源優先級管理和統計監控,是Docker實現資源控制的基礎。
3.UnionFS:鏡像的分層文件系統UnionFS(聯合文件系統)允許將多個只讀鏡像層疊加,形成一個統一的文件系統視圖。每個鏡像層存儲相對于上一層的增量變化,支持鏡像層的共享和復用。容器啟動時,在鏡像層之上添加可寫層,實現寫時復制(Copy-on-Write),保證鏡像層只讀且容器的文件變更隔離。
NameSpace 限制了容器能看到的世界:
Linux NameSpace:默認情況下,子進程會復制父進程的 NameSpace。
Cgroup 限制容器能夠使用的資源:
Cgroup 能夠對進程使用系統資源進行限制,以 CPU 資源、Memory 資源為例。
CPU資源:
1、限制容器的 CPU 資源使用:cpu.cfs_period_us
調度周期(默認為 10000 us)、cpu.cfs_quota_us=-1
不限制CPU使用份額、cpu_shares
CPU分配比例(多個容器競爭CPU資源時使用)。
2、容器運行后,會創建對應的/sys/fs/cgroup/cpu/docker/<CONTAINER ID>
目錄,用于 CPU 資源的控制組(cgroups)管理。以下是各個文件和目錄的作用解釋:
- cgroup.clone_children: 這個文件影響 clone() 系統調用,用于控制是否在創建新進程時復制父進程的 CPU 控制組設置。
- cgroup.procs: 包含當前 cgroup 中的所有進程 ID (PID)。這個文件可讀可寫,寫入一個 PID 可以將該進程移動到這個 cgroup 中。
- cpuacct.stat: 報告這個 cgroup 中所有進程的 CPU 使用情況,包括用戶態和內核態的使用時間。
- cpuacct.usage: 報告這個 cgroup 中所有進程的總 CPU 使用時間,以納秒為單位。
- cpuacct.usage_all: 顯示每個 CPU 的使用情況,包括用戶態和內核態的使用時間。
- cpuacct.usage_percpu: 顯示每個 CPU 核心的使用時間。
- cpuacct.usage_percpu_sys: 顯示每個 CPU 核心的內核態使用時間。
- cpuacct.usage_percpu_user: 顯示每個 CPU 核心的用戶態使用時間。
- cpuacct.usage_sys: 報告這個 cgroup 中所有進程在內核態下的 CPU 使用時間。
- cpuacct.usage_user: 報告這個 cgroup 中所有進程在用戶態下的 CPU 使用時間。
- cpu.cfs_period_us: 配合 cpu.cfs_quota_us 使用,定義 CPU 帶寬控制的時間周期,以微秒為單位。
- cpu.cfs_quota_us: 定義 cgroup 在 cpu.cfs_period_us 周期內可以使用的 CPU 時間總量,以微秒為單位。通過設置這個值,可以限制 cgroup 的 CPU 使用帶寬。
- cpu.shares: 定義 cgroup 的 CPU 分享數。值越高,cgroup 在競爭 CPU 資源時獲得的優先級越高。
- cpu.stat: 提供一些 CPU 限制的統計信息,比如用戶態和系統態下的等待時間。
- notify_on_release: 控制當 cgroup 的最后一個進程結束時,是否自動刪除該 cgroup。設置為 1 表示啟用通知,設置為 0 表示禁用。
- tasks: 包含當前 cgroup 中的所有線程 ID (TID)。與 cgroup.procs 類似,但包含線程而不是進程。
Memory資源:
1、限制容器的 Memory 資源使用:memory.limit_in_bytes
限制容器可以使用的物理內存的上限、memory.oom_control
容器超過內存上限的策略(默認為kill)
2、容器運行后,會創建對應的/sys/fs/cgroup/memory/docker/<CONTAINER ID>
目錄,用于 Memory 資源的控制組(cgroups)管理。以下是各個文件和目錄的作用解釋:
- cgroup.clone_children: 影響 clone() 系統調用,用于控制是否在創建新進程時復制父進程的內存控制組設置。
- cgroup.event_control: 用于事件控制,當某些條件滿足時,可以觸發用戶空間的事件通知。
- cgroup.procs: 包含當前 cgroup 中的所有進程 ID (PID)。這個文件可讀可寫,寫入一個 PID 可以將該進程移動到這個 cgroup 中。
- memory.failcnt: 記錄內存資源分配失敗的次數。
- memory.force_empty: 觸發內存 cgroup 的強制清空。
- memory.kmem.failcnt: 記錄內核內存分配失敗的次數。
- memory.kmem.limit_in_bytes: 設置內核內存的使用限制,以字節為單位。
- memory.kmem.max_usage_in_bytes: 記錄內核內存的最大使用量,以字節為單位。
- memory.kmem.slabinfo: 顯示內核 slab 分配器的內存使用信息。
- memory.kmem.tcp.failcnt: 記錄 TCP 緩沖相關的內核內存分配失敗的次數。
- memory.kmem.tcp.limit_in_bytes: 設置 TCP 緩沖相關的內核內存的使用限制,以字節為單位。
- memory.kmem.tcp.max_usage_in_bytes: 記錄 TCP 緩沖相關的內核內存的最大使用量,以字節為單位。
- memory.kmem.tcp.usage_in_bytes: 顯示當前 TCP 緩沖相關的內核內存使用量,以字節為單位。
- memory.kmem.usage_in_bytes: 顯示當前內核內存使用量,以字節為單位。
- memory.limit_in_bytes: 設置 cgroup 的內存使用限制,以字節為單位。
- memory.max_usage_in_bytes: 記錄 cgroup 的最大內存使用量,以字節為單位。
- memory.move_charge_at_immigrate: 控制當進程移動到其他 cgroup 時,是否移動其內存使用量。
- memory.numa_stat: 顯示 NUMA 節點相關的內存使用統計信息。
- memory.oom_control: 控制內存不足時的行為。
一旦容器內的進程占用內存超過限制,則可通過設置該字段讓進程kill。 - memory.pressure_level: 用于監控內存壓力水平,可以設置觸發事件通知的閾值。
- memory.soft_limit_in_bytes: 設置內存的軟限制,以字節為單位。超過軟限制不會直接導致 OOM,但系統會嘗試回收內存。
- memory.stat: 包含各種內存使用統計信息,如當前使用量、RSS、緩存等。
- memory.swappiness: 控制 cgroup 的交換傾向程度,值范圍為 0-100。
- memory.usage_in_bytes: 顯示當前內存使用量,以字節為單位。
- memory.use_hierarchy: 控制是否在計算內存使用時考慮子 cgroup。
- notify_on_release: 控制當 cgroup 的最后一個進程結束時,是否自動刪除該 cgroup。設置為 1 表示啟用通知,設置為 0 表示禁用。
- tasks: 包含當前 cgroup 中的所有線程 ID (TID)。與 cgroup.procs 類似,但包含線程而不是進程。
Overlay2文件系統:
overlay2 是一種堆疊文件系統
,基于 Linux 內核的 OverlayFS 技術,依賴并建立在其他文件系統上,并不參與磁盤空間結構的劃分,僅是將底層文件系統中的不同目錄結構進行“合并
”,然后向用戶呈現。
- 上層會覆蓋下層相同的內容,故用戶只能看到和操作 Merge 層,操作的變化會記錄在 Upper 層,Lower 層是只讀的。
- 用戶創建新文件,則upper層會直接創建;刪除文件,則在upper層創建一個“屏蔽”文件,屏蔽(whiteout)掉lower層的同名文件;修改文件內容,執行copy-on-write將lower層文件拷貝到upper層,保留原文件名只在upper層修改文件內容,并屏蔽(whiteout)掉lower層;修改文件名,執行copy-on-write將lower層文件拷貝到upper層,使用新文件名,并在upper層創建一個與原名相同的“屏蔽”文件用來屏蔽(whiteout)掉lower層。
Overlay2 是 Docker 默認使用的聯合文件系統 UFS(Union Filesystem),用于管理容器鏡像的分層存儲和容器運行時文件系統的合并。
Overlay2 是 Docker 的分層存儲引擎,通過聯合掛載實現高效的文件管理。Docker 的 Overlay2 數據默認存儲在 /var/lib/docker/overlay2/
(通過docker inspect <container-ID>
中的GraphDriver字段,查看對應層數據的存儲位置)。當啟動容器時,
- 鏡像層(Lower Dir):所有鏡像層按順序堆疊(如 base-image → apt-get install → copy files)。
- init層:會將宿主機的一些host相關的文件/目錄拷貝到對應的docker層的文件/目錄下,之后這些文件會被掛載給容器。
- 容器層(Upper Dir):鏡像層之上創建的一個可寫層,存儲容器運行時的修改。
- 合并視圖(Merged):將只讀層和可寫層合并,形成容器的完整文件系統。
注意:docker commit時,只會保存 upper 層,不會保存 init 層。
Overlay2 的優點:
- 高效分層存儲:多個容器共享相同的基礎鏡像層,節省空間。
- 寫時復制(CoW):只有修改文件時才復制,減少磁盤 I/O。
- 性能較好:相比 aufs 和 devicemapper,Overlay2 是 Docker 推薦的存儲驅動。