什麼是容器:命名空間和cgroups

當我第一次聽到有關容器時,個人第一反應是:這啥玩意?它是一個進程嗎?Docker是什麼?容器就是Docker嗎?救救可憐的孩子吧!
容器這個詞指的並非某種至關精確的事物,一般來講,幾個Linux內核的特性(namespcescgroups)能讓進程之間彼此隔離,而當你使用了這些特性獲得了互相隔離的進程時,你能夠將其稱之爲‘容器’。基本上,這些特性能讓你僞裝擁有了一個相似虛擬機的東西,可是它們根本就不是虛擬機,它們僅僅不過是運行在同一Linux內核中的進程罷了,讓咱們更深刻一點吧。docker

命名空間

好的,先假設咱們想要獲得一個相似虛擬機同樣的東西。有一個特性必定想獲得:個人進程應該跟其餘的進程隔離開,是這樣吧。
Linux提供了這樣的特性:namespaces。這有一堆不一樣的特性:
• 在pid空間中你變成了PID 1,同時你的子進程變成了其餘進程,而全部的其餘程序消失了。
• 在網絡命名空間中你可以運行在任意不重複的端口上
• 在mount命名空間中你可以mount或者umount文件系統,只要不跟主機的文件系統衝突。因此你能夠有徹底不一樣的mount設備集(一般更少)
事實證實建立namespces是至關容易的,你僅僅只須要運行一個叫unshare的程序(以相同名稱的系統調用名命名)如今咱們建立一個新的PID命名空間,同時在裏面運行bash。安全

$ sudo unshare --fork --pid --mount-proc bash

發生了什麼?ruby

root@kiwi:~# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0  28372  4148 pts/6    S    23:01   0:00 bash
root         2  0.0  0.0  44432  3836 pts/6    R+   23:01   0:00 ps aux

Wow,簡直就像創造了一整個世界,這裏僅僅只有兩個進程在運行:bash和ps,太酷了,這些都很容易。
值得注意的是,若是從常規PID namespace的視角去看,我能看到新的PID namespce的進程:bash

root     14121  0.0  0.0  33264  4044 pts/6    S+   23:09   0:00 htop

這個進程的id是14121(常規namespace),而在新的PID namespace中它的進程id是3,因此它們是同一件事物的兩個視角,僅僅是其中一個受到了更多的限制。網絡

進入另外一個程序的命名空間

你一樣能夠進入另外一個正在運行的程序的namespace,要作到這件事你只需使用一個叫nsenter的命令,我想這就是docker exec運行的原理,可能吧。性能

cgroups:資源限制

好的,咱們已經經過與舊世界不一樣的新進程和套接字建立了一個新的魔幻世界, that's cool! 若是我想限制一個程序使用多少內存或CPU,該怎麼辦?很幸運。在2007年,有人爲咱們創建了cgroup,它們就像你用nice命令處理進程同樣,可是比nice命令多了一大堆的特性,咱們來建立一個cgroup,先使用它來限制內存ui

$ sudo cgcreate -a bork -g memory:mycoolgrou

來看看裏面有什麼spa

$ ls -l /sys/fs/cgroup/memory/mycoolgroup/
-rw-r--r-- 1 bork root 0 Okt 10 23:16 memory.kmem.limit_in_bytes
-rw-r--r-- 1 bork root 0 Okt 10 23:14 memory.kmem.max_usage_in_bytes

哦,要設置最大使用內存(單位:byte),好吧,來嘗試設置一下,10M對任何人來講應該夠用了code

$ sudo echo 10000000 >  /sys/fs/cgroup/memory/mycoolgroup/memory.limit_in_bytes

太棒了,來嘗試使用下個人cgroup!進程

$ sudo cgexec  -g memory:mycoolgroup bash

我跑了一堆命令它們都運行的很好,直到我嘗試編譯一個rust程序:) :) :)

$ root@kiwi:~/work/ruby-stacktrace# cargo build
error: Could not execute process `rustc -vV` (never executed)

Caused by:
  Cannot allocate memory (os error 12)

太精彩了,終於成功地限制了程序的內存。

seccomp-bpf

好了,最後一個特性。若是要隔離進程,除了要限制它們的內存和CPU使用率以外,還可能要限制它們能夠運行的系統調用!例如網絡訪問權限,這可能有助於提升安全性!咱們喜歡安全。seccomp-bpf,這是Linux內核的一個功能,能夠爲進程篩選哪些系統調用可使用。

什麼是容器?

好的,既然你已經看到了這兩個特性,你可能會想:「Wow,是的,我能夠圍繞全部這些特性構建一堆腳本,而且有一些很棒的東西!」它將是真正的輕量級應用,而且個人進程將彼此隔離,Wow!有人過去也是這麼認爲的,他們構建了一個使用這些特性的叫作「 Docker容器」的東西。這就是Docker的所有!固然,現在Docker具備不少功能,但大多都是以這些基本的Linux內核特性爲藍本構建起來的。
image.png