白話Docker(NameSpace)

Docker容器無疑是當(dāng)下最火的技術(shù)了。Docker通過鏡像明確解決的是應(yīng)用打包困難的問題。

docker

但是容器本身是沒有什么價值的,有價值的是容器編排技術(shù)。
容器本身就像一個沙盒一樣,將應(yīng)用程序打包,讓應(yīng)用程序在沙盒中運行,而沙盒中的應(yīng)用程序也能感知到沙盒的邊界,被限制在沙盒之中。
Namespace就是修改進(jìn)程視圖的的方法,通過約束和修改進(jìn)程的動態(tài)表現(xiàn),從而為其創(chuàng)造一個“邊界”。
Namespace提供了MOUNT,UTS ,IPC,PID,NETWORK,USER的視圖隔離。

PID Namespace
[root@localhost ~]# docker run -it busybox /bin/sh
/ # ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/sh
    7 root      0:00 ps aux

可以看到容器內(nèi)部的1號進(jìn)程是/bin/sh 。而容器內(nèi)一共就只有兩個進(jìn)程。在容器中執(zhí)行一條語句。

/ # sleep 100000
在容器中 再 docker exec -it xxx /bin/sh 進(jìn)入查看其pid 為 38
/ # ps aux|grep sleep
   38 root      0:00 sleep 100000

而再宿主機(jī)上也有一個sleep 100000 的進(jìn)程,其pid 為 5181
[root@localhost ~]# ps aux|grep sleep
root       5181  0.0  0.0   1284     4 pts/1    S+   22:23   0:00 sleep 100000

這就是Namespace技術(shù)。
其實這種技術(shù)很早就有了,Linux系統(tǒng)在創(chuàng)建線程的系統(tǒng)調(diào)用 clone() 中指定 CLONE_NEWPID 參數(shù)。

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

這就是Linux容器中最底層的實現(xiàn)了。
有了PID Namespace ,可以讓進(jìn)程覺得自己是 1號進(jìn)程。有了Mount Namespace,會讓進(jìn)程只能看到自己的掛載的目錄和文件。有了Network Namespace,會讓進(jìn)程只能看到Namespace里的網(wǎng)絡(luò)設(shè)備。
所以說,其實Namespace只是障眼法而已

這樣的障眼法提供了Linux Namespace的隔離性。但是這種隔離性其實還有很多不足之處。
  • 容器只是宿主機(jī)上的一種特殊的進(jìn)程,那么多個容器之間使用的還是同一個宿主機(jī)的內(nèi)核。(低版本內(nèi)核的Linux是無法運行高版本內(nèi)核的Linux容器的,同樣Win的內(nèi)核也運行不了Linux容器)
  • 雖說已經(jīng)有了很多Namespace。但是時間是不能被Namespace化的,容器中調(diào)用了settimeofday()的系統(tǒng)調(diào)用,那么宿主機(jī)也會被更改。(盡管有seccomp技術(shù),對容器中的系統(tǒng)調(diào)用有過濾,但是這會拖累容器性能,而且一般也不知道有多少這種坑的系統(tǒng)調(diào)用要被限制)

文件系統(tǒng)的Namespace

進(jìn)到容器后,可以看到容器內(nèi)部有 / ,也有 /etc 等等。其實之前提到了,docker 是方便開發(fā)者一次打包多地部署的困難點的,但是最容易忽視的是應(yīng)用程序最大的依賴不是 jvm或者是 程序庫,最大的依賴應(yīng)該是操作系統(tǒng)本身。如果能將整個操作系統(tǒng)都打包才是真正解決了打包的困難。

這里可能想到了 有Mount Namespace 呀。有了它,容器的應(yīng)用程序里面理應(yīng)看到的是一份完全獨立的文件系統(tǒng)。這樣就可以在容器中操作容器內(nèi)的目錄(如 /tmp)。而不影響宿主機(jī)本身。

下面有一段小程序,在創(chuàng)建子進(jìn)程時,開啟指定的Namespace。

#define _GNU_SOURCE
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#define STACK_SIZE (1024 * 1024)
static char container_stack[STACK_SIZE];
char* const container_args[] = {
  "/bin/bash",
  NULL
};

int container_main(void* arg)
{
  printf("Container - inside the container!\n");
  execv(container_args[0], container_args);
  printf("Something's wrong!\n");
  return 1;
}

int main()
{
  printf("Parent - start a container!\n");
  int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWNS | SIGCHLD , NULL);
  waitpid(container_pid, NULL, 0);
  printf("Parent - container stopped!\n");
  return 0;
}

這段代碼的功能時在main函數(shù)中,通過clone() 系統(tǒng)調(diào)用創(chuàng)建一個新的子進(jìn)程,并聲明為它啟用Mount Namespace 。而這個子進(jìn)程執(zhí)行的是一個 shell。這個shell運行在 Mount Namespace 隔離環(huán)境中。

$ ls /tmp

但是執(zhí)行后發(fā)現(xiàn)還是宿主機(jī)的tmp。
其實不難回答,光啟用 Namespace 還不行。因為進(jìn)入容器之后需要重新掛載一次。

int container_main(void* arg)
{
  printf("Container - inside the container!\n");
  // 如果你的機(jī)器的根目錄的掛載類型是 shared,那必須先重新掛載根目錄
  // mount("", "/", NULL, MS_PRIVATE, "");
  mount("none", "/tmp", "tmpfs", 0, "");
  execv(container_args[0], container_args);
  printf("Something's wrong!\n");
  return 1;
}

這時再執(zhí)行 ls /tmp 。發(fā)現(xiàn) /tmp 為空了。
這就是重新掛載了 /tmp 。
和其他的Namespace 不一樣,Mount Namespace 想要生效,必須是伴隨著掛載操作才能生效的
而在 Linux中,有一個 chroot 的命令。就是改變進(jìn)程的根目錄到指定的目錄。
而這個掛載在容器根目錄上,用來為容器提供隔離后執(zhí)行環(huán)境的文件系統(tǒng),就是所謂的“容器鏡像”,也被稱作“rootfs(根文件系統(tǒng))”
所以對docker來講。最核心的原理就是為待創(chuàng)建的用戶進(jìn)程

  1. 啟用Linux Namespace配置
  2. 設(shè)置指定的 Cgroups 參數(shù)
  3. 切換進(jìn)程的根目錄(Change root)

還是需要明確一下。
rootfs 只是一個操作系統(tǒng)所包含的文件,配置和目錄,并不包含操作系統(tǒng)的內(nèi)核。內(nèi)核參數(shù)是一個全局變量,一處修改,到處生效。

由于rootfs 里打包的不只是應(yīng)用,而是整個操作系統(tǒng)的文件和目錄,也就意味著,應(yīng)用以及它運行所需要的所有依賴,都被封裝在了一起。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容