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

五分钟搞定Docker底层原理

时间:2023-03-17 21:52:01 科技观察

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