在初次接触容器(Container)时,很多教程都会通过类比虚拟机来介绍容器,因为容器和虚拟机一样,为你的程序提供了一个隔离的,可复现的运行环境。
但本质上,容器依然只是一个进程,只不过我们利用各种手段为这个进程创造了出了形如虚拟机的效果。
在进入容器后,我们可以看到一个完整的 linux rootfs,这时利用 chroot 技术实现的,首先在一个目录中将需要的 rootfs 文件都准备好(包括程序运行需要的各种 lib),然后在容器进程运行时通过 chroot 让容器在这个我们准备的 rootfs 目录下运行。
这样,容器进程读取使用 rootfs 下的配置、库时就可以读取到我们指定的内容。
将这个 rootfs 目录保存下来,就可以为程序提供一个可复现的 rootfs 运行环境。而这个 rootfs 的保存便利用了 Linux UnionFS 技术。
利用 rootfs 构建了容器进程的运行时环境后,还可以通过 linux namespace 隔离容器使用到的内核资源,毕竟容器本质上依然是运行在内核上的一个进程,根据需要,可以使容器进程的网络、PID 等内核资源和其他进程隔开。
这样,容器在自己的 namespace 中可以直接监听 80 端口,不会遇到冲突。
在隔离了容器使用到的内核资源后,还可以通过 Cgroups 技术限制容器可以使用的 CPU 和 MEM 资源。
通过 FS、Namespace 和 Cgroups,我们便为容器进程提供了一个类似虚拟机的环境,但需要注意的是,这样的隔离是不彻底的,容器本质上还是运行在宿主机上,因此容器进程可能影响到宿主机上的其他进程,同时宿主机的内核版本也现在了容器进程可以使用的内核能力。
root@iZ2vc0m61b6rmsa0f79k6eZ:~# docker run -dit --name httpd -p 8080:80 httpd:2.4 # httpd namespace root@iZ2vc0m61b6rmsa0f79k6eZ:~# lsns | grep httpd 4026532202 mnt 4 4251 root httpd -DFOREGROUND 4026532203 uts 4 4251 root httpd -DFOREGROUND 4026532204 ipc 4 4251 root httpd -DFOREGROUND 4026532205 pid 4 4251 root httpd -DFOREGROUND 4026532207 net 4 4251 root httpd -DFOREGROUND # httpd rootfs, path get by docker inspect httpd root@iZ2vc0m61b6rmsa0f79k6eZ:~# ls /var/lib/docker/overlay2/a97bc7582d362c3fe1f179b73d7e3dc65dc8f47cc08b9667a62f9b305c05c9e2/merged bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var