Docker原理

jasmine 于 2022-02-04 发布

1、概括

Docker 的实现主要依赖 Linux的三大技术:Linux 命名空间、控制组 和 UnionFS

2、Linux 命名空间

命名空间(namespaces)是 Linux 为我们提供的用于分离进程树、网络接口、 挂载点以及进程间通信等资源的方法。在日常使用 Linux 或者 macOS 时, 我们并没有运行多个完全分离的服务器的需要,但是如果我们在服务器上启动了多个服务, 这些服务其实会相互影响的,每一个服务都能看到其他服务的进程,也可以访问宿主机器上的任意文件, 这是很多时候我们都不愿意看到的,我们更希望运行在同一台机器上的不同服务能做到完全隔离, 就像运行在多台不同的机器上一样。

Linux提供的命名空间机制包含clone_newcgroup、clone_newipc、clone_newnet、clone_newns、clone_newpid、clone_newuser、clone_newuts。

对于进程的隔离采用的是clone_newpid来实现的。

从主机的进程来看,1->29407->2554->5006,这其实是存在一个一颗进程树的 进程树 通过Linux的命名空间clone_newpid创建新进程,在底层的setNamespaces方法中传入进程、用户、网络等,创建新docker容器时把对应的隔离参数传递进去,从而实现了与宿主机、与各个容器的进程、用户、网络隔离。

类比: 这其实就和小区里不同楼层不同房间住着不同的业主是一个道理,早期在房子修建的时候, 开发商提供了不同栋的不同楼层的不同房间,业主们通过购房拥有了不同房间的入住权, 与每栋每楼层每房间都是独立的业主。

2.1、 网络

Docker 的容器通过 Linux 的命名空间创建了与宿主机隔离的网络命名空间

每一个使用 docker run 启动的容器其实都具有单独的网络命名空间, Docker 为我们提供了四种不同的网络模式,Host、Container、None 和 Bridge 模式。

3、CGroups 控制组

通过CGroups实现docker创建的 命名空间 对宿主机器的物理资源控制,比如当前空间占用多少CPU,多少内存等

每一个CGroup都可以为容器进行资源的分配,通过修改对应的参数就可以修改资源。下面这些参数是CGroups的子系统 对于docker来说,是通过参数调用子系统实现对资源的分配与控制,我们只需要关注如何配置参数即可,底层的大牛们早已写好,不用重复造轮子了哈。

比如对于CPU的控制,在docker中使用cpu-shares参数指定容器所使用的CPU份额值(默认1024)

类比: 这就和房子装修是一个道理,整个房子买下来后,整体的面积已经固定, 我们可以去设计不同卧室的面积,比如整个房子100平米可用面积, 卧室空间默认是20平米,那么主卧参数100,次卧参数50,就表明了主卧面积是次卧的一倍, 主卧20平米,次卧10平米。

4、联合文件系统UnionFS(union file system)

把多个目录联合放在同一个目录下,而这些目录的物理位置是分开的。 在docker的镜像设计中,用户制作镜像的每一步操作就是多增加一个目录(docker中称之为层layer), 这个java程序1和java程序2所在的容器就引用相同的操作系统层、java环境层, 再结合应用程序层,启动docker容器时通过UnionFS把相关的层全放在一个目录里, 作为容器的根文件系统,而容器的启动就是可写层,来对docker镜像进行操作。

执行 docker run 命令的时候,就会在镜像的最上层添加一个可写的层,也就是容器层

容器和镜像的区别就像是对象和类信息一样的关系,一个镜像可以run多个容器

类比: 这种感觉就像修房子一样,一个房子里的20层里住着不同的业主, 他们有不同的装修风格、家电配置(这是最上层),但第二层(第1到19层住着一样的业主)、 第三层(一楼有一样的公共设施、环境)、最底层(相同的地基)都是一样的。