1.基础知识:进程
前情提要(docker 通过镜像技术,解决了应用打包的根本性难题)
2.容器本身没有价值,有价值的是"容器编排"
3.容器
容器其实是一种沙盒技术,就像集装箱一样,把应用装起来的技术
应用于应用之间,有了边界而不至于互相干扰
被装进集装箱的应用,可以方便搬来搬去
4.程序,进程
什么是程序?什么是进程?
输入数据保存在文件中,数据被加载到内存待命,操作系统又读取计算加法的指令,需要cpu完成加法操作。而cpu与内存协作进行加法运算,使用寄存器存放数值,内存堆栈保存执行的命令和变量,计算及还有被打开的文件,以及各种IO设备不断调整自己的状态
5.边界
容器和核心功能,通过约束和修改进程的动态表现,从而创造出一个边界
cgroups技术用来制造约束的主要手段,namespace技术用来修改进程视图的主要方法
6.docker run
拉起一个docker,并运行/bin/sh
$ docker run -it busybox /bin/sh
/ #
执行一下ps命令
/ # ps
PID USER TIME COMMAND
1 root 0:00 /bin/sh
10 root 0:00 ps
/bin/sh 为1号进程,容器里只有2个进程在运行,前面执行的/bin/sh 以及ps,已经被docker隔离在一个跟宿主机完全不同的世界中去了
7.进程映射
宿主机上运行/bin/sh 程序,操作系统分配PID=100的进程,/bin/sh就是PID=100的进程,而1号员工就是比尔盖茨
现在docker把/bin/sh运行在一个容器中,docker给第100号的进程一个“障眼法”,让他永远看不到前面99个员工,更看不到比尔盖茨,这样,他就会错误的认为自己就是公司的第一号员工
说白了:对应用的进程空间做了手脚,使得进程只能看到重新计算过的进程编号,PID=1,实际上在宿主机的操作系统里,还是原来100号的进程
使用的就是linux里面的namespace机制。
8.namespace 命名空间
namespace命名空间,其实只是linux创建进程的一个可选参数。例如fork函数中的系统调用clone
int pid = clone(main_function, stack_size, SIGCHLD, NULL);
系统调用为我们创建一个新的进程,并返回进程pid
clone方法的参数扩展指定CLONE_NEWPID 会怎样
int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL);
这个用的就是PID Namespace
这个新进程将会看到一个权限的进程空间,进程空间中,它的PID是1,因为“障眼法”原因,宿主机真实的进程空间里,这个进程的pid还是真实的数值,比如100.
执行多次,就有多个PID Namespace,每个namespace里的应用进程,都会认为自己是容器里的1号进程。他们看不到宿主机的进程空间,也看不到其他pid namespace里的情况,
9.其他namespace
Mount,UTS,IPC,Network和User这些Namespace
用来对各种不同进程上下文进行障眼法操作
10.Mount Namespace
让被隔离进程只能看到当前namespace里的挂载信息
11.Network Namespace
让被隔离进程看到当前Namespace里的网络设备和配置
12.概括
以上就是linux容器最基本的实现原理
容器只是一种特殊的进程而已
13.总结
左边是虚拟机工作原理,hypervisor是虚拟机最主要部分,通过硬件虚拟化功能,模拟出了各种硬件,比如cpu,内存,io设备。并且它在这些虚拟硬件上安装了新的操作系统Guset OS
全虚拟化的概念,用户看到的是Guset OS的文件和目录,以及虚拟出来的硬件设备
右边通过Docker Engine的软件替代了Hypervisor。没有docker容器运行在宿主机里面,docker帮助用户启动的还是原来的应用进程,知不是创建这些进程时,docker给他们加上了各种各样的namespace参数
然后进程就会认为自己是1号进程,只能看到各自的Mount Namespace目录和文件,只能访问Network namespace里面的网络设备,仿佛在一个容器里,与世隔绝
其实本质都是障眼法罢了。