Docker容器隔离

对于Docker等大多数Linux容器来说,Namespace技术是用来修改进程视图的主要方法。

示例

通过创建一个容器来展示Linux中对PID资源的隔离

1
2
3
4
5
$ docker run -it busybox /bin/sh
/ # ps
PID USER TIME COMMAND
1 root 0:00 /bin/sh
7 root 0:00 ps

在Docker里最开始执行的/bin/sh是这个容器内部的第1号进程(PID=1),而这个容器里共有两个进程在运行。说明/bin/shps已经被Docker隔离在一个跟宿主机不同的世界中。

原本每当在宿主机上运行一个程序,操作系统都会给它分配一个PID(进程号),比如PID=100。这个编号是进程的唯一标识,当Docker在一个容器中运行程序时,会对被隔离应用的进程空间做处理,使得这些进程只能看到重新计算过的PID。在实际的宿主机操作系统里,它还是原先的进程。

Linux Namespace机制

Linux中的Namespace不止有PID,还提供了Mount、UTS、IPC、Network、User等,用来对进程上下进行处理。比如Mount Namespace用于让被隔离进程只看到当前Namespace里的挂载点信息,Network Namespace用于让被隔离进程只看到当前Namespace里的网络设备和配置。

Linux中Namespace的使用方式其实只是Linux创建新进程的一个可选参数。以上面PID Namespace为例,Linux中创建线程的系统调用是clone(),如int pid = clone(main_function, stack_size, SIGCHLD, NULL),这个系统调用会为我们创建一个新的进程,并返回它的PID。而当用clone()系统调用创建一个新进程时,就可以在参数中指定CLONE_NEWPID参数,比如int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL),新创建的这个进程就会看到全新的一个进程空间。多次执行上面的clone()调用,就会创建多个PID Namespace,每个Namespace里的应用进程都会认为自己是容器里的第1号进程,既看不到宿主机里真正的进程空间,也看不到其他PID Namespace里的具体情况。

缺点

基于Linux Namespace的隔离机制相比于虚拟化技术也有很多不足之处,主要问题是隔离得不彻底。既然容器只是在宿主机上运行的一种特殊进程,多个容器之间使用的就还是同一个宿主机的操作系统内核。尽管可以在容器里通过Mount Namespace单独挂载其他版本的操作系统文件,比如CentOS或者Ubuntu,但这并不能改变共享宿主机内核的事实。意味着如果要在Windows宿主机上运行Linux容器,或者在低版本的Linux宿主机上运行高版本的Linux容器,都是不行的。

其次在Linux内核中有很多资源和对象是不能被Namespace化的,比如时间。这就意味着,如果你的容器中的程序使用settimeofday(2)系统调用修改了时间,那么整个宿主机的时间都会被随之修改。

作者

chengzhy

发布于

2023-10-06

更新于

2023-10-06

许可协议

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×