我們只要提起容器技術就都會想到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 為進程設定內存使用限制