首先明确一个道理,docker容器本身是没有价值的,有价值的是容器的编排技术

因为需要对打包好的容器进行相关的编排,所以业界才爆发了一场关于容器编排的战争,战争的最后-是以Kubernetes和CNCF社区胜利结束

这也是为何要了解K8S的原因,而在这之前,我们先了解Docker技术

容器本身是一种沙盒,顾名思义沙盒是一个像是集装箱一样,将应用装起来的技术,这样,应用和应用之间,就不会互相干扰,而且可以方便的将应用进行快速部署

那么如何对应用之间进行隔离呢?就是这个边界是如何实现的呢?

我们假设是编写了一个计算加法的小程序,这个程序需要输入来自一个文件,计算完成后输出到另一个文件中

计算机中只认识0和1,无论用什么语言编写,都是二进制的运行的

然后二进制的程序就可以在计算机上运行了

这个程序会将输入的数据加载到内存中,然后执行程序中加法的指令,这一步需要利用CPU,和CPU的寄存器,然后内存堆栈中保存了对应的命令和变量,和各种各样的I/O设备来显示打开的文件

在上面说的运行中涉及的环境的总和,集合起来就是我们今天要说的进程

容器的核心功能,就是约束和修改进程的动态表现,从而创造出一个”边界”

Docker等Linxu容器技术中利用了两个概念,Cgroups技术来制造环境约束,Namespace来修改进程所能看到的视图

Ggroups和Namespace这两个概念很抽象,但是如何理解呢?

我们拿着一个Linxu系统来看下,我们首先创建一个容器

我们使用创建一个容器的指令

docker run -it busybox /bin/sh

docker run启动了一个容器,it参数告诉Docker容器启动之后,需要分配给我们文本的输入和输出环境,TTY,和容器的标准输入有关,这样我们就可以和Docker容器进行交互了,其中主要在Docker中运行的程序就是 /bin/sh

然后我们在这个环境中执行一下ps命令,会发现

图片

这个容器中,只能看到一共两个进程在运行,前面说的/bin/sh,和我们已经执行的ps,都被Docker隔离在了一个和宿主机完全不同的世界中

本来,当我们宿主机上运行了一个/bin/sh的程序,操作系统会给其分配一个进程编号PID,这个编号是进程的唯一标识

当我们利用Docker在/bin/sh程序运行在一个容器当中时候,Docker会在这个PID生成时候施一个障眼法,让其看不到其他的PID,让其认为自己就是天字第一号进程

这个技术,就是Linux中的Namespace的机制,而Namespace使用起来很有意思,其实就是Linux在创建进程的一个可选参数,在Linux系统中创建线程的系统调用是clone()函数

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还是原来的

多次调用,clone函数,会创建多个PID Namespace,每个Namespace里面的应用进程,都会认为自己是当前容器的1号进程,看不到宿主机中真正的进程空间,也看不到其他PID Namespace的具体情况

Linux中还有一些其他的Namespcae,诸如 Mount/UTS/IPC

比如 Mount Namespace,可以让隔离进程看到当前的Namespace的挂载点信息,Network Namespcae,可以看到当前Namespace的网络设备和配置

这就是容器的基本的实现原理

Docker容器就是在创建容器进程的时候,指定了这个进程启动时候的一组Namespace参数,这样容器就只能看到当前Namespace所限制的资源,文件,设备,状态,配置

本质上,还是一个特殊的进程

接下来,我们看一下虚拟机和容器的对比

图片

虚拟机中,存在着一个名为Hypervisor的软件,可以将不同的硬件虚拟化,模拟一个系统所需要的各种硬件,CPU 内存 IO设备,并安装一个新的操作系统,GUEST OS

这样,应用进程可以运行在这个虚拟的机器中,能看到的自然只有Guest OS的文件和目录,和这个虚拟机的虚拟设备,保证了隔离

而容器没有这一层,只有个简单的Docker Engine软件

这就是Docker项目被称为轻量级化的虚拟机技术

Docker并没有脱离整体的系统,而是在启动的时候,加上了不同的Namesapce的参数罢了

但是Docker内的应用,会感觉自己运行在一个独立的环境中,在各自的容器之中,但是只是障眼法罢了

1.上面的图中,容器和虚拟机对比的图,有什么不妥吗

2.Dokcer项目启动的时候,会启动哪些Namespace?

对于一个容器,里面集成了jdk netstat ping等命令,但是里面是运行一个Java进程的,那么是如何运行的?

容器的单进程意思不是指只能运行一个进程,而是只有一个进程是可控的

1.对于容器,应该在APP外面,包裹上一层namespaces

容器应该是在进程运行的外面,包裹上了Namespaces和Cgroup,来做到了容器化的

2,对于PID UTS network user mount IPC cgroup

发表评论

邮箱地址不会被公开。 必填项已用*标注