天天看點

Docker底層namespace與cgroup

Docker是使用容器container的平台,容器其實隻是一個隔離的程序,除此之外啥都沒有。這個程序包含一些封裝特性,以便和主機還有其他的容器隔離開。一個容器依賴最多的是它的檔案系統也就是image,image提供了容器運作的一切包括 code or binary, runtimes, dependencies, and 其他 filesystem 需要的對象。

容器在Linux上本地運作,并與其他容器共享主機的核心。它運作一個獨立的程序,占用的記憶體不比其他的filesystem多,是以它是輕量級的。相比之下,虛拟機(VM)運作一個成熟的“guest”作業系統,通過hypervisor對主機資源進行虛拟通路。一般來說,vm會産生大量開銷,超出應用程式邏輯所消耗的開銷。

Docker底層namespace與cgroup
Docker底層namespace與cgroup

容器本質上是把系統中為同一個業務目标服務的相關程序合成一組,放在一個叫做namespace的空間中,同一個namespace中的程序能夠互相通信,但看不見其他namespace中的程序。每個namespace可以擁有自己獨立的主機名、程序ID系統、IPC、網絡、檔案系統、使用者等等資源。在某種程度上,實作了一個簡單的虛拟:讓一個主機上可以同時運作多個互不感覺的系統。

Docker底層namespace與cgroup

此外,為了限制namespace對實體資源的使用,對程序能使用的CPU、記憶體等資源需要做一定的限制。這就是Cgroup技術,Cgroup是Control group的意思。比如我們常說的4c4g的容器,實際上是限制這個容器namespace中所用的程序,最多能夠使用4核的計算資源和4GB的記憶體。

簡而言之,Linux核心提供namespace完成隔離,Cgroup完成資源限制。namespace+Cgroup構成了容器的底層技術(rootfs是容器檔案系統層技術)。

namespace

一個namespace把一些全局系統資源封裝成一個抽象體,該抽象體對于本namespace中的程序來說有它們自己的隔離的全局資源執行個體。改變這些全局資源對于該namespace中的程序是可見的,而對其他程序來說是不可見的。

Linux 提供以下幾種 namespaces:

Namespace   Constant                           Isolates
  -  IPC            CLONE_NEWIPC            System V IPC, POSIX message queues
  -  Network     CLONE_NEWNET           Network devices, stacks, ports, etc.
  -  Mount        CLONE_NEWNS             Mount points
  -  PID            CLONE_NEWPID            Process IDs
  -  User          CLONE_NEWUSER         User and group IDs
  -  UTS          CLONE_NEWUTS           Hostname and NIS domain name      

為了在分布式的環境下進行通信和定位,容器必然需要一個獨立的IP、端口、路由等等,自然就想到了網絡的隔離。同時,你的容器還需要一個獨立的主機名以便在網絡中辨別自己。想到網絡,順其自然就想到通信,也就想到了程序間通信的隔離。可能你也想到了權限的問題,對使用者和使用者組的隔離就實作了使用者權限的隔離。最後,運作在容器中的應用需要有自己的PID,自然也需要與主控端中的PID進行隔離。

cgroups

Cgroups是control groups的縮寫,最初由google的工程師提出,後來被整合進Linux核心。Cgroups是Linux核心提供的一種可以限制、記錄、隔離程序組(process groups)所使用的實體資源(如:CPU、記憶體、IO等)的機制。對開發者來說,cgroups 有如下四個有趣的特點:

  • cgroups 的 API 以一個僞檔案系統的方式實作,即使用者可以通過檔案操作實作 cgroups 的組織管理。
  • cgroups 的組織管理操作單元可以細粒度到線程級别,使用者态代碼也可以針對系統配置設定的資源建立和銷毀 cgroups,進而實作資源再配置設定和管理。
  • 所有資源管理的功能都以“subsystem(子系統)”的方式實作,接口統一。
  • 子程序建立之初與其父程序處于同一個 cgroups 的控制組。

本質上來說,cgroups 是核心附加在程式上的一系列鈎子(hooks),通過程式運作時對資源的排程觸發相應的鈎子以達到資源追蹤和限制的目的。實作 cgroups 的主要目的是為不同使用者層面的資源管理,提供一個統一化的接口。從單個程序的資源控制到作業系統層面的虛拟化。Cgroups 提供了以下四大功能:

  • 資源限制(Resource Limitation):cgroups 可以對程序組使用的資源總額進行限制。如設定應用運作時使用記憶體的上限,一旦超過這個配額就發出 OOM(Out of Memory)。
  • 優先級配置設定(Prioritization):通過配置設定的 CPU 時間片數量及硬碟 IO 帶寬大小,實際上就相當于控制了程序運作的優先級。
  • 資源統計(Accounting):cgroups 可以統計系統的資源使用量,如 CPU 使用時長、記憶體用量等等,這個功能非常适用于計費。
  • 程序控制(Control):cgroups 可以對程序組執行挂起、恢複等操作。

    Docker正是使用cgroup進行資源劃分,每個容器都作為一個程序運作起來,每個業務容器都會有一個基礎的pause容器也就是POD作為基礎容器。pause容器提供了劃分namespace的内容,并連通同一POD下的所有容器,共享網絡資源。檢視容器的PID,對應/proc/pid/下是該容器的運作資源。

資源限制

Cgroup是一種資源控制機制,它将作業系統中的所有程序以組為機關劃分,所有程序組以層級結構進行組織。cgroup為每個程序組都指定一組通路資源的行為,這些行為限制了該組程序對資源的通路。

Cgroup 子系統:

1、blkio:設定限制每個塊裝置的輸入輸出控制;

2、cpu:使用排程程式為 cgroup 任務提供 cpu 的通路;

3、cpuacct:産生 cgroup 任務的 cpu 資源報告;

4、cpuset:如果是多核心的 cpu,這個子系統會為 cgroup 任務配置設定單獨的 cpu 和記憶體;

5、devices:允許或拒絕 cgroup 任務對裝置的通路;

6、freezer:暫停和恢複 cgroup 任務;

7、memory:設定每個 cgroup 的記憶體限制以及産生記憶體資源報告;

8、net_cls:标記每個網絡包以供 cgroup 友善使用;

9、ns:命名空間子系統;

10、perf_event:增加了對每個 cgroup 的監測跟蹤能力,可以監測屬于某個特定的 cgroup 的所有線程及運作在特定 CPU 上的線程。

CPU控制

Cgroup對程序組使用CPU的限制是通過cpu和cpuset兩個子系統來完成的。cpu子系統主要限制程序的時間片大小,cpuset子系統可為程序指定cpu和記憶體節點。

記憶體控制

cgroup對記憶體的控制通過memory子系統完成,其控制作用主要展現在對記憶體使用量的限制,同時為目前cgroup生成一份記憶體使用情況報告。

在具體實作的過程中,cgroup通過核心中的resource counter機制實作記憶體的限制。resource counter相當于一個通用的資源計數器,在核心中通過res_counter結構來描述。該結構可用于記錄某類資源的目前使用量、最大使用量以及上限等資訊。

塊I/O控制

Cgroup中通過blkio子系統完成對塊裝置I/O的控制。具體的控制主要通過blkio.weight檔案在使用者态設定目前程序組通路塊I/O的權重,也就是控制程序組占有I/O的時間。

blkio子系統對塊I/O的控制代碼主要分布在I/O排程算法中,目前核心中預設的排程算法為CFQ(完全公平隊列),該算法與程序排程算法CFS比較類似。

cgroup子系統圖

Docker底層namespace與cgroup

繼續閱讀