深度解析Containers--系統架構

什麼是 Containers?

隨着Kubernetes,Docker Compose,Mesos OS,Consul等出現,容器是這些雲計算時代的頭條新聞。html

要真正瞭解容器的架構組合,您須要首先了解如下幾點:linux

  1. Linux Kernel User & System Space
  2. Syscalls and Capabilities
  3. Cgroups
  4. Namespaces
  5. EIAF (Everything Is A File), a description of the Unix based Filesystem

儘管Mac內核符合POSIX且基於OpenBSD,可是這5件事對於真正瞭解容器的工做原理以及爲何須要Linux VM在Windows和Mac上運行容器很重要。docker

爲何我要這樣開始?

我將深刻探討有關容器的文章,重點是Docker,Dockerfiles和諸如docker build -t之類的命令。至關小的部分仍會在後面的部分中講述,可是它們如何工做的基礎是我今天介紹的內容。ubuntu

所以,我採用了不一樣的方法,直接研究了使容器正常工做的因素,以及容器的外觀和功能。安全

讓咱們從瞭解Linux內核系統和用戶空間入手,以深刻了解容器的實際做用。bash

Linux 內核空間

在Linux中,咱們一般有兩個運行應用程序的空間,即內核系統空間和用戶空間。一般,在默認的內核配置下,用戶空間佔用0–3GB空間,而內核空間佔用3-4GB空間。網絡

內核空間是咱們爲運行內核的低級應用程序提供系統內存的位置。用戶空間是咱們用戶進程運行和執行的環境。架構

c-01.jpg

這兩個內存空間被稱爲「 Rings」的微調權限層隔開。這些環定義了在能夠授予某些操做以前須要知足應用程序要求的特權或特權的程度。app

c-02.jpg

這些環並非Linux特有的,而是在操做系統中定義明確的佈局,儘管每一個級別的功能區域都是根據操做系統所運行的CPU架構分配的。爲了在用戶空間和內核空間之間切換,咱們經過系統調用(簡稱爲syscall)應用操做。工具

這使用可從用戶空間應用程序訪問的已定義內核功能來請求訪問內核級功能。下圖完美地說明了如何定義此順序。

c-03.jpg

每當應用程序向內核級功能發出請求時,都會發送一箇中斷,通知處理器中止正在執行的操做並處理該特定請求,若是能夠簡化理解,則能夠將其視爲上下文切換。若是用戶空間應用程序具備相關權限,則能夠在內核空間中進行上下文切換,在上下文切換啓動後,用戶空間應用程序將等待響應,並經過適當的中斷處理程序在內核空間中執行所需的程序/功能。

tmp\_buf = mmap(file, len); # mmap here is from a C library\# This is called a memory map and it's a C function  
\# It allocates a certain amount of memory for a task, file etc.  
\# Since memory is a kernel space resource, a syscall is made to the mmap syscall in the linux kernel to make this request possible

c-04.jpg

SysCalls 和 Capabilities

系統調用又名syscall是一個API,它容許一小部份內核功能公開給用戶級應用程序。真正強調的一小部分是告知任何閱讀者,系統調用是有限的,而且通用於特定目的。它們在每一個操做系統上都不相同,而且在訪問的定義和訪問方式上也有所不一樣。

c-07.jpg

追溯到先前的mmap示例,該接口未在列表中列出,由於它只是一小部分,可在此處得到linux中syscall的完整列表。

有時,咱們有一組要組合在一塊兒的系統調用,咱們使用名爲Capabilities的Linux內核功能來實現。這些是預約義的特權集,正在運行的程序能夠訪問這些特權或受其限制。
經過將相關調用分組爲可當即授予或拒絕的已定義特權,功能進一步加強了系統調用。這甚至防止了根級應用程序利用保留的權限來利用受限的內核空間。

有幾種linux功能,之後將在大多數文章中訪問它們,以瞭解它們如何使用SecComp等配置文件與容器進行集成,更具體地說是使用AppArmor,SELinux等LSM(Linux安全模塊)進行集成,可是您能夠在此處的手冊頁中引用列表。

Cgroups

控制組(一般稱爲cgroup)是Linux內核容許將流程組織爲分層的功能,而後能夠限制其使用各類類型資源的組並進行監控。內核的cgroup接口經過 僞文件系統,稱爲cgroupfs。分組在 核心cgroup內核代碼,而資源跟蹤和限制是 在一組每一個資源類型的子系統(內存,CPU, 等等)。

簡單來講,cgroup控制着咱們可使用的功能。它們的功能列表以下所示:

  • 資源限制:能夠將組配置爲不超過指定的內存限制或使用的處理器數量不超過時望的數量,或者限制爲特定的外圍設備。
  • 優先級:能夠將一個或多個組配置爲利用更少或更多的CPU或磁盤I / O吞吐量。
  • 記賬:監視和衡量組的資源使用狀況。
  • 控制:能夠凍結或中止並從新啓動進程組。

Cgroup經過使用子系統/控制器來運行,這些子系統/控制器能夠修改進程的運行時環境。在v1和v2兩個版本中有多個控制器可用。

在v1控制器領域,咱們具備如下優點:

  • blkio-該子系統設置了對塊設備(例如物理驅動器(磁盤,固態或USB))的輸入/輸出訪問的限制。
  • cpu-該子系統使用調度程序向cgroup任務提供對CPU的訪問。
  • cpuacct —此子系統生成有關cgroup中任務所使用的CPU資源的自動報告。
  • cpuset-此子系統將單個CPU(在多核系統上)和內存節點分配給cgroup中的任務。
  • devices-該子系統容許或拒絕cgroup中的任務訪問設備。
  • freezer-該子系統掛起或恢復cgroup中的任務。
  • memory-該子系統設置cgroup中任務對內存使用的限制,並自動生成有關這些任務使用的內存資源的報告。
  • net_cls —該子系統使用類標識符(classid)標記網絡數據包,該類標識符容許Linux流量控制器(tc)識別源自特定cgroup任務的數據包。
  • net_prio-該子系統提供了一種動態設置每一個網絡接口的網絡流量優先級的方法。
  • ns —名稱空間子系統。
  • perf_event —此子系統標識任務的cgroup成員身份,可用於性能分析。
  • hugetlb-支持限制cgroup使用大頁面。
  • pids-此控制器容許限制進程數量 能夠在cgroup(及其後代)中建立。
  • rdma — RDMA(遠程DMA)控制器容許限制每一個cgroup使用RDMA / IB專用資源。

對於v2控制器空間,因爲未實現某些控制組,所以咱們具備v1的某些功能,linux系統能夠同時使用這兩個功能,可是v2系統更緊湊,cgroup更少。

  • io —這是版本1 blkio控制器的後繼產品。
  • memory—這是版本1內存控制器的後繼產品。
  • pids —與版本1 pids控制器相同。
  • perf_event —與版本1的perf_event控制器相同。
  • rdma —與版本1 rdma控制器相同。
  • cpu —這是版本1 cpu和cpuacct控制器的後繼產品。

您會注意到,它在功能方面與版本1控制器相同。每一個cgroup提供限制一個或多個資源的功能。有關此問題的庫和工具將在之後的部分中進行從新介紹。

Namespaces

命名空間使容器相信它們存在於徹底隔離的環境中,而不是在主宿主系統中。更具體地說,容器內的進程將自身視爲系統內惟一的進程。

您能夠認爲它在盒子裏,而在盒子裏,您認爲本身是盒子的主人,可是您只是在實際上擁有兩個盒子的另外一我的的盒子裏玩夢境。因爲具備此功能,所以能夠在容器中運行容器,儘管稍後會涉及到一些問題。

對於名稱空間功能,它嵌入在Linux組成部分中。

c-05.jpg

這些名稱空間提供了不一樣的功能。

  • IPC —隔離進程間通訊,這個大詞意味着進程能夠沿着通道或管道在彼此之間共享消息,就像流水經過管道同樣。沒有名稱空間,就像咱們的主要管道同樣,一個容器(進程)可使用同一管道將數據提供給其餘進程。對於命名空間,該管道是惟一的,而且僅限於namespace中的某些進程。在linux中,這是使用/dev/shm(共享內存)或/dev/mqueue(消息隊列)塊文件從主機共享的。
  • Network-負責隔離IP地址,接口,網絡請求,端口等。
  • Mount—限制在主機上使用卷和外部數據掛載。名稱空間中的進程正在其本身的本機文件系統中運行。
  • PID —隔離進程運行時,對主機上的進程與名稱空間中的進程之間進行純粹的限制。所以,主機上的bash實例與容器中的實例不一樣。這是一種獨特的功能,它使咱們能夠在主機自己之外的容器中運行應用程序。
  • User—限制容器用戶的UID(UserID)和GID(Group ID)分配。因爲容器沒法從主機讀取信息,所以這能夠有效地保護主機。
  • UTS —用於設置或獲取主機名,很是簡單。

全部這些名稱空間都是使用unshare系統調用實現的,以隔離資源。

Linux FileSystem

在Linux中首先要注意的是,全部內容都是一個文件。我不騙你,從存儲設備,串行設備等全部/dev/\*一直到/proc/fileystems中的文件系統列表,一直到主機上運行的cgroup。不一樣文件系統之間的大多數交互都是由虛擬文件系統驅動程序(VFS)處理的,但這是另外一個的主題。

c-08.jpg

由於全部內容都是文件,因此我能夠從字面上 cat以查看受支持的配置。

如前所述,容器是進程。咱們都瞭解了容器和VM之間的區別的方式是,容器共享主機的內核及其某些資源。這裏的主要提示是資源,容器使用不一樣的根文件系統開始本身的操做,容器(提示:它們是進程)開始使用的實際文件系統是鏡像。

鏡像是一個Linux文件系統,大部分通過壓縮,而後使用一些COW(寫時複製)文件系統(例如AUFS,device-mapper,Btrfs,XFS等)從中執行。

對於安裝了docker的用戶,您能夠運行如下命令以查看docker鏡像的內部結構(不是容器,容器是進程,正在運行的鏡像等。)

mkdir rootfs && \
docker export $(docker create ubuntu:18.04) | tar -C rootfs -xvf -

c-09.jpg

主要的linux文件系統很是特殊,由於您會注意到vmlinuzinitrd.img,我稍後會再提到。

c-10.jpg

在這裏,咱們注意到咱們沒有在主文件系統上看到的initrdvmlinuz文件,這是由於這兩個文件是內核文件。

InitRD— Init Ram Disk

初始RAM磁盤(initrd)是在實際根文件系統可用以前安裝的初始根文件系統。 initrd綁定到內核,並做爲內核引導過程的一部分進行加載。而後,內核將此initrd掛載爲兩階段引導過程的一部分,以加載模塊以使實際文件系統可用並得到真實的根文件系統。

VMLinuz —Virtual Memory LINUx gZip

vmlinuz是Linux內核可執行文件的名稱。 vmlinuz是壓縮的Linux內核,它可以將操做系統加載到內存中,從而使計算機可用並能夠運行應用程序。

在linux上,您可能會遇到vmlinux或vmlinuz。它們相同,但其中之一被壓縮。

vmlinuz =VirtualMemoryLINUx gZip = Compressed Linux kernel Executable

vmlinux =VirtualMemoryLINUX = Non-compressed Linux Kernel Executable

vmlinuz和initrd文件都在引導時使用。

如今,這是主要緣由,在容器文件系統或鏡像中沒有這兩個文件。

容器使用主機內核!

不須要啓動序列便可獲取內核,容器中應用程序的全部可能請求都是經過主機調用經過主機調用發出的,該調用經過rings, capabilities, seccomp, LSMs等強制執行,一直返回到全部普通的linux程序。

這裏的主要思想是容器只使用徹底不一樣的文件系統,可是它們共享相同的Linux內核。對於那些稍微瞭解linux的人來講,咱們知道咱們能夠將chroot轉換爲外部linux文件系統,並在其中進行操做,就好像文件系統已啓動同樣,前提是來自主機的全部必要文件都經過綁定安裝在該文件夾中。

c-11.jpg

若是您已經讀了該文章的某些部分,您會發現容器相似chroot,只不過與名稱空間,cgroup和許多其餘很酷的功能打包在一塊兒,以使應用程序沙箱在同一主機上儘量安全。

Summary

容器是在命名空間內執行的運行時進程,該命名空間由cgroup和各類其餘LSM和安全功能管理,以確保在運行時徹底隔離進程。容器中的這些過程以及諸如Docker之類的容器運行時尤爲是自動化的,它簡化了不少討論的事情,可是我所解釋的主要基礎層仍然是相同的。

相關文章
相關標籤/搜索