容器本身是没有价值的,有价值的是“容器编排”
- 容器中的边界是如何实现的
- 一个小程序是如何运行的?
- 一个小程序的运行,首先要将程序语言翻译成为二进制语言。
- 要给代码提供数据(例如从磁盘中引入二进制文件)
- 数据被加载到内存中待命
- CPU和内存共同工作,并且利用寄存器、内存堆栈、I/O设备等来帮助执行程序
- 什么是进程?
上述这样的一个程序运行起来之后的计算机执行环境的总和,叫做进程。
对于进程来说,其静态表现是一段程序,而其运行起来之后便是计算机离得数据和状态的总和。而容器技术的核心,就是通过约束和修改进程的动态表现,从而创造出一个边界。 - Docker约束
对于Docker等大多数Linux容器来说,Cgroups技术是用来进行约束的主要手段,而Namespace技术则是用来修改进程视图的主要办法。
Docker中做的约束
- 使得容器和宿主机相隔离
-
运行一个容器
//-it参数告诉Docker在启动一个容器之后,分配一个输入输出环境 //这行命令的操作是启动一个容器,在融器里面执行/bin/sh,并且分配一个终端进行交互 $ docker run -it busybox /bin/sh
-
查看容器内进程
在容器中执行ps
操作,我们可以看到容器内容只有个位数的进程在运行。这说明我们执行的ps已经被docker隔离在了一个跟宿主机完全不同的世界中。 -
这是如何做到的?
这种技术使用的是Linux里面的Namespace机制。在Linux中创建新的进程时,使用clone()
进行系统调用,例如:int pid=clone(main_function,stack_size,SIGHLD,NULL);
Linux系统会为我们创建一个新的进程,并且返回它的进程号pid。我们可以在SIGCHLD位置中指定CLONE_NEWPID参数,例如:
int pid=clone(main_function,stack_size,CLONE_NEWPID|SIGHLD,NULL);
这样,这个新创建的进程则会被“障眼法”,只能看到一个全新的进程空间,并且自己的进程号是1。
-
例如3中的障眼法还有很多,这些Linux提供的系统调用为实现Linux容器提供了方法。
容器,只是一种特殊的进程而已
这幅图的左侧是虚拟机的工作原理,右侧是容器。
其实,容器还是运行在宿主机内的一堆进程,只不过是Docker在创建这些进程的时候,帮助用户添加了各种参数而已。真正负责隔离环境的还是宿主机的操作系统本身
容器的隔离和限制
这张图比上一张更加贴切,因为Docker只是起到了跟应用同级别的靠边的位置。
容器 | 虚拟机 |
---|---|
不会因为虚拟化而带来性能损耗 | 虚拟化产生大量性能损耗 |
没有额外的操作系统资源 | 需要另外装操作系统 |
隔离不彻底 | 隔离彻底 |
不可以在windows宿主机上面运行Linux容器 | 可以 |
不可以在低版本的Linux宿主机上面运行高版本容器 | 可以 |
容器的其他缺点:
- Linux内核中,有一些资源没有办法被namespace化,例如时间
- 由于隔离不够彻底,用户使用安全较低
- 每一个进程所占据的资源,需要单独控制
- 容器是一个“单进程”模型,在一个容器中,无法同时运行两个不同的应用
- 在容器中使用
top
命令之后,看到的可能是宿主机的CPU和内存数据,而不是当前容器的数据,这是因为/proc文件系统并不知道Cgroups的限制存在,这会给生产环境造成很大的风险。