理解容器

容器,这个名称真是恰如其分,就是把一个程序放在一个和外界隔离的环境中运行。
Linux容器的实现,依赖于Linux Namespace。啥事Linux Namespace呢,lwn上有一个系列文章作了介绍: https://lwn.net/Articles/531114/。 简单地说,Linux Namespace 是一种把全局的系统资源隔离的手段,这些全局的系统资源包括网络、主机名称、文件系统、进程ID等等。在一个特定的名称空间中只能看到该空间中的这些全局资源。
使用容器技术之后,发布一个应用程序和不使用容器技术有什么区别呢。区别就在于你可以把程序依赖的整个环境(甚至依赖的整个操作系统)打包,然后发布。这样,在部署的时候,只要把这个包解压,然后以容器的方式运行这个程序就可以了(当然,要把文件系统的根目录设置为这个压缩包解压后的内容所在的目录)。也就是说,由于容器技术提供的隔离性,这个程序运行起来的时候看到的环境,感觉就和在开发机器上是一样的,起码文件系统看起来是一样的,其他的方面虽然和开发时不一样(比如进程数很少,而且应用进程可能就是1号进程,实际系统1号进程应该是init进程)但这些资源是部署的系统上其他部分隔离的,不会影响这个应用的运行。
有一篇文章,用不到100行代码实现了一个简单的以容器方式启动程序的功能: https://zserge.com/posts/containers/, 文章中的完整示例代码地址是 https://gist.github.com/zserge/4ce3c1ca837b96d58cc5bdcf8befb80e
既然容器技术只是在运行时将程序隔离,那就意味着这个应用程序如果不隔离,应该也是能在这个系统上运行的。那很多人可能跟我一样,有这个疑问:一台Linux机器(就假定是Ubuntu的吧)只要装了docker, 可以运行任何其他发行版的Linux镜像,比如CentOS, RedHat, Alpine等等等等。难道,这些系统都是兼容的吗?我们平时安装一个普通的应用程序,还要选择和我们的操作系统对应的版本,怎么这些镜像运行起来就完全不需要考虑操作系统的版本呢?StackOverfloww上也有人问了这个问题: https://stackoverflow.com/questions/25444099/why-docker-has-ability-to-run-different-linux-distribution
这里的关键就在于,这些Linux系统的内核是相同的。容器和宿主在运行时公用的就是内核部分,有一副图,很好的描述了容器运行时的状态(虽然这个图是windows文档上的,但是描述的原理和linux是一样的,图片地址:https://docs.microsoft.com/en-us/virtualization/windowscontainers/about/media/container-diagram.svg ):

也就是说,容器里的可执行文件,只要是linux可识别的可执行文件格式,并且文件中的CPU指令的格式符合当前系统所在的CPU的规范(x86的可执行文件当然没法直接在arm的CPU上运行),并且调用的系统调用符合Linux kernel的规范,那这个文件就是可以在任何linux系统上运行的。所以,windows上的程序是没法再linux容器中运行的,因为内核不同。由此,也可以知道,容器技术今天能如此广泛的使用,和Linux系统在服务器操作系统领域统治级的地位是密不可分的。
再看看我们平时安装的一些普通的应用程序,之所以需要考虑操作系统的版本,是因为其依赖的不仅仅是内核的系统调用接口,还依赖于操作系统本身提供的各种工具、系统库以及第三方库等等。而我们制作一个应用程序镜像时,也会把这些依赖打包到镜像中。在运行的时候,这些被依赖的程序最终依赖的系统调用则是由宿主机提供的。

posted on 2021-04-29 19:10  等待未知  阅读(71)  评论(0编辑  收藏  举报

导航