概述回顾:
- 容器技术的兴起源于 PaaS 技术的普及;
- Docker 公司发布的 Docker 项目具有里程碑式的意义;
- Docker 项目通过“容器镜像”,解决了应用打包这个根本性难题。
容器本身没有价值,有价值的是“容器编排”。
容器,到底是怎么一回事。容器是一种沙盒技术。沙盒就是能够像一个集装箱一样,把应用“装”起来的技术。这样,应用与应用之间,就因为有了边界而不至于相互干扰;而被装进集装箱的应用,也可以被方便地搬来搬去,这就是 PaaS 最理想的状态。
边界”的实现手段“程序”被执行起来,它就从磁盘上的二进制文件,变成了计算机内存中的数据、寄存器里的值、堆栈中的指令、被打开的文件,以及各种设备的状态信息的一个集合。一个程序运行起来后的计算机执行环境的总和,就是进程。
- 对于进程,静态表现就是程序,待在磁盘上;而运行起来的动态表现,就是计算机里的数据和状态的总和。
- 容器技术的核心功能,就是通过约束和修改进程的动态表现,从而为其创造出一个“边界”。
对于Docker 等大多数 Linux 容器来说,Cgroups 技术是用来制造约束的主要手段,而 Namespace 技术则是用来修改进程视图的主要方法。
| <br /> $ docker run -it busybox /bin/sh<br />/ # ps<br />PID USER TIME COMMAND<br /> 1 root 0:00 /bin/sh<br /> 10 root 0:00 ps<br />
-it 参数告诉了 Docker 项目在启动容器后,需要给我们分配一个文本输入 / 输出环境,也就是 TTY。
这条指令翻译成人类的语言就是:请帮我启动一个容器,在容器里执行 /bin/sh,并且给我分配一个命令行终端跟这个容器交互。
这样,Mac 变成了一个宿主机,而一个运行着 /bin/sh 的容器,就跑在了这个宿主机里面。
ps 中可以看到执行的 /bin/sh,就是这个容器内部的第 1 号进程(PID=1),此时 /bin/sh 和 ps,已经被 Docker 隔离在了一个跟宿主机完全不同的世界当中。
假设 /bin/sh 在宿主机(Mac)上分配的进程编号为 PID=100。
要通过 Docker 把这个 /bin/sh 运行在一个容器当中。这时,Docker 就会给他施一个“障眼法”,让他永远看不到前面的 99 个进程,更看不到 1 号进程。这样,他就会错误地以为自己就是 1 号进程。
这种机制,其实就是对被隔离应用的进程空间做了手脚,使得进程只能看到重新计算过的进程编号,比如 PID=1。可实际上,他们在宿主机的操作系统里,还是原来的第 100 号进程。
这种技术,就是 Linux 里面的 Namespace 机制。Namespace 其实只是 Linux 创建新进程的一个可选参数。
Linux 中创建线程的系统调用是 clone(),
<br />int pid = clone(main_function, stack_size, SIGCHLD, NULL); <br />
这个系统调用创建一个新的进程,且返回它的进程号 pid。
严格说,clone()是线程操作,但linux 的线程是用进程实现的。
可以参数中指定 CLONE_NEWPID,<br />int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL); <br />
这时,新创建的这个进程将会“看到”一个全新的进程空间,在这个进程空间里,它的 PID 是 1。之所以说“看到”,是因为这只是一个“障眼法”,在宿主机真实的进程空间里,这个进程的 PID 还是真实的数值,比如 100。
多次调用 clone(),就会创建多个 PID Namespace,而每个 Namespace 里的应用进程,都会认为自己是当前容器里的第 1 号进程,它们既看不到宿主机里真正的进程空间,也看不到其他 PID Namespace 里的具体情况。
除了刚刚用到的 PID Namespace,Linux 操作系统还提供了 Mount、UTS、IPC、Network 和 User 这些 Namespace,用来对各种不同的进程上下文进行“障眼法”操作。
比如,Mount Namespace,用于让被隔离进程只看到当前 Namespace 里的挂载点信息;Network Namespace,用于让被隔离进程看到当前 Namespace 里的网络设备和配置。
这就是 Linux 容器最基本的实现原理了。
Docker 容器实际上是在创建容器进程时,指定了这个进程所需要启用的一组 Namespace 参数。这样,容器就只能“看”到当前 Namespace 所限定的资源、文件、设备、状态,或者配置。而对于宿主机以及其他不相关的程序,它就完全看不到了。
容器,其实是一种特殊的进程而已。
|
| —- |
容器和虚拟机的区别。(Docker Engine 应该在侧面,起管理作用)
- 不应该把 Docker Engine 或者任何容器管理工具放在跟 Hypervisor 相同的位置,因为它们并不像 Hypervisor 那样对应用进程的隔离环境负责,也不会创建任何实体的“容器”,真正对隔离环境负责的是宿主机操作系统本身。应该把 Docker 画在跟应用同级别并且靠边的位置。这意味着,用户运行在容器里的应用进程,跟宿主机上的其他进程一样,都由宿主机操作系统统一管理,只不过这些被隔离的进程拥有额外设置过的 Namespace 参数。而 Docker 项目在这里扮演的角色,更多的是旁路式的辅助和管理工作。

- Hypervisor 软件是虚拟机最主要的部分。它通过硬件虚拟化功能,模拟出了运行一个操作系统需要的各种硬件,比如 CPU、内存、I/O 设备等等。然后,它在这些虚拟的硬件上安装了一个新的操作系统,即 Guest OS。
- Docker 成为轻量虚拟化技术并不正确。跟真实存在的虚拟机不同,并没有一个真正的 Docker 容器运行在宿主机里面。Docker 帮助用户启动的,还是原来的应用进程,只不过在创建这些进程时,Docker 为它们加上了各种各样的 Namespace 参数。
