当前位置: 首页 > 科技观察

5分钟搞懂Docker底层原理!

时间:2023-03-11 21:41:55 科技观察

曾经有个同学给我打个比方:宿主机就像一个大房子,docker把它分成了N个小分区。在这些小隔断之间,有独立的卫生间、小床、电视……麻雀虽小,五脏六腑一应俱全。这个比喻很贴切。Linux提供了非常完善的隔离机制,让各个隔间之间互不影响。即使隔壁房间春意盎然,我的小房间同样冷清,丝毫不影响我。Docker能够实现这些功能,依赖于chroot、namespace、cgroup这三种老技术。在本文中,我们先来谈谈命名空间。毕竟隔离是容器的第一要素。Linux内核提供了多达8种类型的命名空间。在这些独立的Namespaces中,资源互不影响,隔离措施非常好。1.8种类型让我们来看看Linux支持哪些Namespaces。可以使用unshare命令观察这些细节。在终端执行manunshare,就会出现这些Namespaces的介绍。Mount(mnt)隔离挂载点ProcessID(pid)隔离进程IDNetwork(net)隔离网络设备、端口号等InterprocessCommunication(ipc)隔离SystemVIPC和POSIX消息队列UTSNamespace(uts)隔离主机名称和域名UserNamespace(用户)隔离用户和用户组。另外Linux4.6和5.6版本增加了cgroups和time两种隔离,一共8种。Controlgroup(cgroup)Namespace隔离Cgroups根目录(4.6版本新增)TimeNamespace隔离系统时间(5.6版本新增)2.1例子通过unshare命令可以快速建立一些孤立的例子。让我们以最简单直观的pid命名空间来看一下它的实际效果。众所周知,Linux进程号为1,称为systemd进程。但是在Docker中,我们只能通过执行ps命令看到一个非常小的进程列表。执行如下命令进入隔离环境,以bash为根进程:unshare--pid--fork--mount-proc/bin/bash效果如图。可以看到我们的bash变成了1号进程,这里看不到宿主机等隔离环境的进程信息。先在隔离环境下执行sleep1000。再打开一个终端,在宿主机上执行pstree,我们就会看到这个隔离环境的进度信息。接下来在宿主机上,将sleep对应的进程的命名空间信息与宿主机的命名空间信息进行比较。可以看出它们的pid命名空间对应的是不同的值。下面给出其他命名空间的实验命令,大家可以实际操作一下。3.尝试unshare--mount--fork/bin/bash创建挂载命名空间,在每个不同的环境使用不同的挂载目录。unshare--uts--fork/bin/bashuts可以用来隔离主机名,让每个命名空间都有一个独立的主机名,可以通过hostname命令修改。unshare--ipc--fork/bin/bashIPCNamespace主要用来隔离进程间通信。Linux进程间通信包括管道、信号、消息、共享内存、信号量、套接字等,使用IPC命名空间意味着所有这些跨命名空间的通信方式都将失效!然而,这正是我们所希望的。unshare--user-r/bin/bash用户命名空间很容易理解。我们可以在一个Namespace中创建一个xjjdog账号,也可以在另一个Namespace中创建一个xjjdog账号,两者互不影响。unshare--net--fork/bin/bashnet命名空间,这个很有用。可用于隔离网络设备、IP地址、端口等信息。End可以看到,通过各种Namespace,Linux可以精细的隔离各种资源。Docker本身也是一个新瓶装旧酒的玩具。Docker的创新之处在于它增加了一个中央仓库,封装了很多简单易用的命令。你可能会发现,到目前为止,我们还没有隔离CPU和内存的资源使用,也没有相应的Namespace来解决这些问题。资源限制的功能是通过使用Cgroups进行quota配置来完成的,与Namespace无关。我们会在后面的文章中介绍Cgroups技术。最后附上一张Docker的生命周期图。来源(http://docker-saigon.github.io/post/Docker-Internals/)。随着Docker的发展,应用工具链已经非常成熟,很多同学已经很熟悉了。如果你对容器技术很感兴趣,不如看看底层原理。这样无论谷歌自己推容器还是继续使用docker,都可以很快掌握。