一旦程序被执行起来,它就从磁盘上的二进制文件,变成了计算机内存中的数据,寄存器里的值,堆栈中的指令,被打开的文件,以及各种设备的状态信息的一个集合。这样一个程序运行起来后的计算机执行环境的总和,可以称为线程。
容器技术的核心功能,就是通过约束和修改进程的动态表现,为其创造出一个边界。
对于Docker等大多数容器来说,Cgroup技术是用来制造约束的主要手段,而namespace技术是用来修改进程视图的主要方法。
docker run -it busybox /bin/sh
指令内容就是帮我启动一个容器,在容器里执行/bin/sh,并分配一个命令行终端跟这个容器交互。
//运行ps命令会发现,这个容器中只有 两个进程
ps
PID USER TIME COMMAND
1 root 0:00 /bin/sh
10 root 0:00 ps
其实这是对被隔离应用的进程空间做了操作,是这些进程得到 重新计算过的进程编号,PID =1, 实际上在宿主的机器中,还是原有的第100号线程。
这种技术,是Linux里面的namespace机制中的, 一个可选参数。
int pid = clone(main_function,stack_size,SIGCHLD,NULL);
这个系统调用就会为我们创建一个新的进程,并返回它的进程号pid
其中我们可以在参数中指定CLONE——NEWPID参数
int pid = clone(main_function,stack_size,CLONE_NEWPID | SIGCHLD,NULL);
这时,新创建的这个进程将会看到一个全新的进程空间,在这个进程空间里,它的PID是1.
除了PID Namespace,linux系统还提供了Mount,UTS,IPC, Network 和User这些Namespace。
其中Mount用于隔离进程中的挂载点信息,Network用于隔离进程里的网络设备和配置
这,就是 Linux 容器最基本的实现原理了。 所以,Docker容器,其实就是创建容器进程时,制定了这个进程所需要启用的一组Namespace参数,这样 容器就只能看到当前Namespace所限定的资源, 文件,设备,状态,或者配置。
容器,可以说是一种特殊的进程
容器与虚拟机的对比
Hypervisor的软件是虚拟机的最主要部分,通过硬件虚拟化功能,模拟出了运行一个操作系统的各种硬件,比如CPU,内存,I/O设备,并在这些虚拟的硬件上安装一个新操作系统Guest OS
Docker engine启动的还是原来的应用进程,只不过各自职能访问各自的Namespace里的网络设备,仿佛运行在一个个容器之中