容器兩大核心技術資源隔離、資源限制


我們只要提起容器技術就都會想到Docker,Docker是原dotCloud公司的項目,Docker項目出現了一個簡單不起眼的技術叫容器鏡像,而Docker項目的出現解決了應用打包這個原容器技術的中的難題,這就是為什么Docker項目剛剛開源不久,就帶領dotCloud公司在PaaS領域脫穎而出。而dotCloud公司在2013年底改名為Docker公司,而Docker也成為了容器的代理名詞。

docker安裝

# step 1: 安裝必要的一些系統工具
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# Step 2: 添加軟件源信息
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# Step 3: 更新並安裝 Docker-CE
sudo yum makecache fast
sudo yum -y install docker-ce
# Step 4: 開啟Docker服務
sudo service docker start

# 注意:
# 官方軟件源默認啟用了最新的軟件,您可以通過編輯軟件源的方式獲取各個版本的軟件包。例如官方並沒有將測試版本的軟件源置為可用,你可以通過以下方式開啟。同理可以開啟各種測試版本等。
# vim /etc/yum.repos.d/docker-ce.repo
#   將 [docker-ce-test] 下方的 enabled=0 修改為 enabled=1
#
# 安裝指定版本的Docker-CE:
# Step 1: 安裝指定版本的docker-ce-selinux
# yum install https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-selinux-17.03.2.ce-1.el7.centos.noarch.rpm
# Step 2: 查找Docker-CE的版本:
# yum list docker-ce.x86_64 --showduplicates | sort -r
#   Loading mirror speeds from cached hostfile
#   Loaded plugins: branch, fastestmirror, langpacks
#   docker-ce.x86_64            17.03.1.ce-1.el7.centos            docker-ce-stable
#   docker-ce.x86_64            17.03.1.ce-1.el7.centos            @docker-ce-stable
#   docker-ce.x86_64            17.03.0.ce-1.el7.centos            docker-ce-stable
#   Available Packages
# Step 3: 安裝指定版本的Docker-CE: (VERSION 例如上面的 17.03.0.ce.1-1.el7.centos)
# sudo yum -y install docker-ce-[VERSION]

認識容器技術

容器的核心技術就是通過約束和修改進程的動態表現,對於Docker等大數容器技術來說,都是通過Cgroup技術是用來制造約束的主要手段,而Namespace技術則是用來修改進程試圖的主要方法。

Namespace 技術

Namespace技術其實只是Linux創建新進程的一個可選參數。在Linux創建線程的系統調用是clone(),例如:

int pid = clone(main_function,...

極客時間版權所有: https://time.geekbang.org/column/article/14642

int pid = clone(main_function,...

極客時間版權所有: https://time.geekbang.org/column/article/14642

int pid = clone(main_function, stack_size, SIGCHLD, NULL);

而用clone()創建新進程的時候,就可以在參數中指定CLONE_NEWPID參數,例如:

int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL);

這時候,我們可以看到一個全新的進程空間,在這個進程空間里,它的PID是1,但是在宿主機的真實進程空間里,這個進程的PID還是真實數值,這就是Namespace的“障眼法”。而除了我們剛剛用到的PID Namespace,Linux還提供了Mount、UTS、IPC、Network 和User 這些Namespace。這就是Linux容器的基本實現原理了。

Docker聽起來很高大上,實際上是容器進程時,指定了一組Namespace參數,這樣容器內只能看到當前Namespace所限定的資源、文件、設備、狀態等。而宿主機相關資源是看不到的。所以說容器其實是一種特殊的進程而已。

我們通過下面的指令驗證一下

$ docker run -it busybox /bin/sh 
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
8c5a7da1afbc: Pull complete 
Digest: sha256:cb63aa0641a885f54de20f61d152187419e8f6b159ed11a251a09d115fdff9bd
Status: Downloaded newer image for busybox:latest
/ # ps 
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/sh
    7 root      0:00 ps
/ # 

上面指令的意思就是我們通過busybox鏡像啟動一個容器 並執行/bin/sh命令,我們在容器里執行一下ps指令,可以看到在Docker里最開始執行的/bin/sh,就是這個容器內的1號進程,而這個容器里一共只有兩個進程運行,這意味着這兩個進程已經被Docker隔離在與宿主機不同的世界里。

Cgroup 技術

Linux Cgroups是Linux內核中用來為進程設置資源限制的重要功能,但是我們為什么要做資源限制呢?我們通過Namespace創建的容器通過障眼法的把PID在容器看到的是1號進程,但是在宿主機上的實際進程是100號,但是100號進程與宿主機其他所有進程是平等競爭的關系。這就意味着容器里的1號進程可以把所有宿主機資源吃光,也可以被宿主機上其他其他進程占用。顯然這樣的設計是不合理的。所以我們通過Cgroup來限制進程對資源的使用情況進行限制,主要作用就是限制一個進程組能夠使用的資源上線,例如:CPU、內存、磁盤、網絡帶寬等。下面我們通過一組實例來驗證一下限制功能。

在Linux中,Cgroup給用戶暴露出來的操作接口是文件系統,既它以文件和目錄的方式組織操作系統 /sys/fs/cgroup 路徑下。通mount -t cgroup來顯示出來

mount -t cgroup 
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)

可以看到在/sys/fs/cgroup下面有cpu、memory、blkio等這樣的子目錄,這都是能被Cgroup進行資源限制的資源類型,而這些子目錄下就是這些類型的限制方法,例如:對CPU子目錄來說,我們可以看到如下幾個配置文件

$ ls  /sys/fs/cgroup/cpu
cgroup.clone_children  cpuacct.usage         cpuacct.usage_percpu_sys   cpuacct.usage_user  cpu.rt_period_us   cpu.stat
cgroup.procs           cpuacct.usage_all     cpuacct.usage_percpu_user  cpu.cfs_period_us   cpu.rt_runtime_us  notify_on_release
cpuacct.stat           cpuacct.usage_percpu  cpuacct.usage_sys          cpu.cfs_quota_us    cpu.shares         tasks

我們可以用cpu.cfs_quota_us和cpu.rt_period_us來配合使用限制CPU使用情況,可以用來限制進程在長度為cpu.rt_period的一段時間,只能被分配到總量為cpu.cfs_quota的CPU時間。我們通過下面例子展示。首先我們需要在對應的子目錄下創建一個目錄,我們進入/sys/fs/cgroup/cpu,執行如下指令:

 

$  cd /sys/fs/cgroup/cpu
$  mkdir container 
$  ls container/
cgroup.clone_children  cpuacct.usage         cpuacct.usage_percpu_sys   cpuacct.usage_user  cpu.rt_period_us   cpu.stat
cgroup.procs           cpuacct.usage_all     cpuacct.usage_percpu_user  cpu.cfs_period_us   cpu.rt_runtime_us  notify_on_release
cpuacct.stat           cpuacct.usage_percpu  cpuacct.usage_sys          cpu.cfs_quota_us    cpu.shares         tasks

 

我們可以看到在創建的container目錄下會自動生成該cpu子目錄下的資源限制文件。

下面我們執行一個死循環腳本,讓他把CPU資源吃到100%,根據輸出,我們可以看到這個腳本的PID是17436

$ while : ; do : ; done &
[1] 17436

通過top命令查看cpu資源使用情況

$ top
....
%Cpu13 :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
.....

我們看一下container目錄下的cpu.cfs_quota_us和cpu.rt_period_us的值

$  cd container/
$  cat cpu.cfs_quota_us 
-1
$  cat cpu.cfs_period_us 
100000

接下來,我們可以通過修改這些文件的內容來設置限制

極客時間版權所有: https://time.geekbang.org/column/article/14653

 

給用戶暴露出來的操作接口是文件系統,即它以文件和目錄的方式...

極客時間版權所有: https://time.geekbang.org/column/article/14653

接下來我們通過修改這兩個文件的內容來設置CPU限制。

container目錄下的cpu.cfs_quota_us文件中寫入20ms (20000 us)

 

$  echo 20000 > cpu.cfs_quota_us 

 

上述命令意味着在每100ms的時間里,被該控制組限制的進程只能使用20ms的CPU時間,也就是說這個進程只能使用到20% 的CPU帶寬。

接下來,我們把被限制的進程的PID寫入container目錄下tasks文件,上面設置就對該PID生效。

$  echo 17436 > /sys/fs/cgroup/cpu/container/tasks 

我們用top指令看一下

$  top
....
%Cpu13 : 20.3 us,  0.0 sy,  0.0 ni, 79.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
....

可以看到CPU資源講到20%

除了CPU子系統外,Cgroup對其他子系統都有資源限制的方法,例如:

  • blkio 為塊設備設置I/O限制,一般用戶磁盤等設備
  • cpuset 為進程分配單獨的CPU核和對應的內存節點
  • memory 為進程設定內存使用限制

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM