当我第一次听到有关容器时,我的第一反应是:这啥玩意?它是一个进程吗?Docker是什么?容器就是Docker吗?救救可怜的孩子吧!
容器这个词指的并不是某种相当精确的事物,通常来说,几个Linux内核的特性(namespcescgroups)能让进程之间彼此隔离,而当你使用了这些特性得到了互相隔离的进程时,你可以将其称之为‘容器’。基本上,这些特性能让你假装拥有了一个类似虚拟机的东西,但是它们根本就不是虚拟机,它们仅仅不过是运行在同一Linux内核中的进程罢了,让我们更深入一点吧。

命名空间

好的,先假设我们想要得到一个类似虚拟机一样的东西。有一个特性一定想得到:我的进程应该跟其他的进程隔离开,是这样吧。
Linux提供了这样的特性:namespaces。这有一堆不同的特性:
• 在pid空间中你变成了PID 1,同时你的子进程变成了其他进程,而所有的其他程序消失了。
• 在网络命名空间中你能够运行在任意不重复的端口上
• 在mount命名空间中你能够mount或者umount文件系统,只要不跟主机的文件系统冲突。所以你可以有完全不同的mount设备集(通常更少)
事实证明创建namespces是相当容易的,你仅仅只需要运行一个叫unshare的程序(以相同名称的系统调用名命名)现在我们创建一个新的PID命名空间,同时在里面运行bash。

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

发生了什么?

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的进程:

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,先使用它来限制内存

$ sudo cgcreate -a bork -g memory:mycoolgrou

来看看里面有什么

$ 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对任何人来说应该够用了

$ 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


EngineerLeo
598 声望38 粉丝

专注于云原生、AI等相关技术