大飞哥的博客

借书满架,偃仰啸歌,冥然兀坐,万籁有声

0%

docker实战:原理篇

容器的本质:特殊的进程

进程是程序和其运行所需要的计算机环境的总和,是计算机进行资源分配和调度的独立单位。 而容器则是一种特殊的进程,它被内核隔离在独立的命名空间下,享有独立的网络、磁盘、文件系统,并且被限制了执行所需要的资源(如cpu 内存等)。

容器同宿主机上其他进程一样, 同其他进程共享宿主机的内核,并接受内核的调度。

容器与虚拟机的区别,如下图所示:

图左画出了虚拟机的工作原理。Hypervisor通过硬件虚拟化功能,模拟出了运行一个操作系统需要的各种硬件,比如 CPU、内存、I/O 设备等等。然后,它在这些虚拟的硬件上安装了一个新的操作系统,即 Guest OS。

图右中并不存在一个Hypervisor层模拟各个硬件,它仅仅只是对容器进程的运行环境进行了限制,但仍然使用了宿主机的内核。

因此此图描述的不够严谨,系统中不存在真实运行的各个容器进程,这只不过是障眼法。

更严谨的应该如下图:

此图中,容器进程直接运行在宿主机上,被宿主机内核管理,docker仅仅起到旁路辅助和管理工作。

隔离和限制:Namespace和Cgroup

隔离

docker使用 Linux Namespace将容器进程进行隔离,容器享有独立的进程空间,因此在容器内部使用ps查看,会发现运行的进程id为1,而宿主机的其他资源不再可见。

docker 使用linux内核提供的namespace进行隔离,相比虚拟机,拥有着启动速度快高性能的优点。

但也有其缺点,那就是隔离的不够彻底,有如下问题:

  1. 由于共享内核,无法在window宿主机上运行linux容器、或者在低版本linux宿主机上运行高版本linux容器
  2. 某些资源是全局资源,无法被namespace, 如时间。 若在一个容器内对时间进行修改, 则其他容器及宿主机其他进程也会生效。

限制

docker使用Linux Cgroup对容器进程进行资源限制,限制的资源包括:cpu、内存、磁盘、网络带宽等。

因为容器也是进程,只有对容器进行资源限制,才能避免容器占用过多宿主机资源,从而影响其他容器、宿主机其他进程的正常工作。

容器镜像原理:rootfs

通过上面的描述,我们可以对容器有一个准确的定义:容器是一种使用namespace和cgroup进行隔离和限制的进程。

那容器内访问的文件系统是如何工作的呢?

答: 通过Mount Namespace将文件系统挂载为容器进程的根文件系统。

docker 运行的核心原理如下:

  1. 启用 Linux Namespace配置
  2. 设置指定的Cgroup
  3. 切换进程的根目录。

需要注意的是ootfs 只是一个操作系统所包含的文件、配置和目录,并不包括操作系统内核。在 Linux 操作系统中,这两部分是分开存放的,操作系统只有在开机启动时才会加载指定版本的内核镜像。

正是由于 rootfs 的存在,容器才有了一个杀手锏: 一致性。

容器本质是进程,进程的本质是程序及其运行环境的组合,这里的运行环境不单单只java版本、类库版本等,还包括操作系统版本等。

而rootfs将除linux内核外所有依赖环境进行打包,从而保证了软件开发、测试、部署、交付全流程的一致性。也因此docker改变了软件开发和交付的流程。