lxc
容器技术jail,vserver,后来为了将容器创建的更易用,已工具的方式使用,就出现了lxc(linux Container),lxc除开vserver,也是最早的真正的将容器技术用简易的工具和模板来极大的简化容器技术使用的方案。所以将自己称为linux Container,简称lxc。
还有一些工具,如:lxc-create,使用这些命令去快速创建一个容器。通常称为一个用户空间。这个用户空间内有一些基础的文件系统和命令程序等,这些可以从宿主机进行复制。但是如果创建的空间运行的系统和宿主机不一样,就不能复制宿主机的文件。
这需要一个template模板,模板其实就是一个脚本,创建了名称空间自动执行脚本后,空间内首先有脚本的执行环境,运行脚本后自动实现安装过程,这个安装就会指向打算创建名称空间内系统发行版所属的仓库,从仓库下载各个程序包,安装,生成一个新的名称空间。这个名称空间就和虚拟机一样被使用。这是一个复杂的过程。
访问到template定义系统发行版的仓库,利用仓库中的程序包下载到本地进行配置安装完成这个过程。
在系统之上应该有根的特权用户空间,在这个子目录上执行一个脚本,可以将一个发行版安装进来,而后chroot。如上图
所有的名称空间都是这么实现。而lxc-create通过这一组工具快速实现了,创建空间,利用template完成内部所需要的文件的安装,同时可完成切换(chroot)。而后就可以使用并行的用户空间,每一个空间和我们所使用的虚拟机几乎一样,有独立系统,主机,ip等等,用户账号等等等,用法和虚拟机一样。 但是仍然有太多的门槛,比如模板定制,理解组件的应用,更重要的是每一个用户空间都是安装生成的,在其中安装一些软件,如redis,mysql,这些应用程序生成的数据迁移到其他机器上,这不太容易。
如果我们想进行规模的批量创建,也是一件难事。尽管lxc极大的简化了一部分容器的使用,相比较比主机虚拟化的复杂程度是没有降低的。而且隔离性也没有虚拟机那么好。好处在与能够让每一个用户空间的进程直接使用宿主机的性能,资源是有一定节约的。对于大批量的使用上,并没有找到很好的突破口,后来就出现了docker。
docker
而docker则是lxc的增强版。docker也不是容器,只是一个易用的前段工具。容器是linux内核之中的技术,docker只是将技术的使用得以简化和普及。
我们知道lxc需要大量创建容器较为困难,要进行复刻一个一样的容器也很难,docker早期的版本中核心便是lxc,也是lxc的二次封装发行版。
在功能上利用lxc做容器管理引擎,在创建用户空间时候,而不用template直接安装,而是事先通过一种镜像技术。将一个操作系统打包成一个镜像,然后将镜像中的文件复制过去,创建成一个虚拟机,基于这个虚拟机启动即可。类似与这种方式,可以尝试着将一个操作系统用户空间所需要用到的所有组件事先准备编排好,而后整体打包成一个文件,这个文件称为镜像文件--image。
这个镜像文件是放在一个集中统一的位置存放,将做小化的系统放置在仓库内。甚至于nginx,基于某类系统,在系统上装好nginx打包成一个镜像,也放在此仓库中。
想启动创建容器就使用docker进行创建删除等,这使用和lxc一样。但再次之上,docker在create创建一个容器的时候,它不会激活模板安装,而是链接到仓库上,下载一个匹配创建容器的镜像拖到本地,基于镜像启动容器。
docker极大的简化了容器使用难度,在启动一个服务的时候,只需要docker run即可。自动链接到互联网上下载下来运行。大多数的镜像在docker仓库中都有。
为了使得docker更易用和管理,docker还支持另外一种方式,在一个用户空间当中,可以尝试运行一组进程或者一个进程。而docker采用了一种更精巧的机制,在一个容器里面只运行一个进程。
比如:需要运行nginx和php,nginx就运行在nginx容器中,php就运行在php容器中,二者使用容器间通讯进行通讯。
而lxc是将一个容器当作一个用户空间使用,类似与虚拟机一样,里面可以运行多个进程。这样以来在管理的时候就会不便。而docker使用这种限制的方式,在一个容器中只运行一个进程的方式。如下图
但是这样一来,调试就会不方便了,但是对于开发者来讲,使用起来则更方便。并且容器是隔离的,docker在使用的时候是从docker镜像仓库下载镜像的方式。如果要进行批量创建容器,只需要在每台运行容器的机器下载运行一次即可。
- 分层构建联合挂载
镜像构建是分层构建联合挂载的机制实现的。
构建一个nginx镜像
基础的alpine纯净的基础镜像,nginx基于alpine构建,而nginx只包含nginx层,底层仍然是alpine。这种方式就是分层构建,一个功能分为一层,迭代一起就形成了统一的视图,组合在一起就成了一个nginx镜像。这样一来就不会显得那么庞大 。
如果要在一个系统上运行三个容器,就需要一个基础镜像(假设为alpine),在分为三个不同的层,分别是nginx,php,mariadb层,将底层镜像alpine分别与nginx,php,mariadb挂载。而底层的镜像都是共享的,每一层的镜像是只读的。如果要运行多个nginx,只需要挂在俩次就可以运行两个容器,如下图:
如何进行增删改?
每一层都是只读的。如果要进行修改,就要在每一层的联合挂载镜像顶层额外附加新层,才可以进行读写,如下图
但是如果要删除文件,事实上是无法删除的,这些也是只读的。删除仅仅只是标记为不可见。如果是修改,就进行写时复制,将层复制一层进行修改,查看使用就使用修改过的层,类似与lvm的快照。
尽管这样迁移起来还是会有问题,容器迁移时候,底层是有数据的,在有状态的情况下,一般可以使用共享存储进行存储。这样的话,容器作为一个进程运行,就算容器宕机,删除,数据是不会丢失,宿主机宕机也不会丢失数据。在启动重新挂载就可以在继续使用。如下图
容器编排
容器的终止和创建并不会对数据产生影响,容器不需要持久,有了生命周期,像一个进程一样运行,从创建开始从停止结束,并且和主机的关系也不密切,可以运行在任何一个主机之上.
这样一来就可以实现这样的功能。
底层主机-> docker。在docker之上在建立一层,由这一层来决定如何调度,cpu空闲或者内存更多等,根据调度法则决定。可能是在其中任何一台主机启动容器。如果这个容器需要持久数据,就分配一个外部的存储空间挂在,并且存储数据。
这个组件可以将容器调度与整个底层的系统环境docker环境之上。
倘若要运行一个nmp,docker本身是不能完成顺序启动的,比如:先启动数据库,在启动php,最后启动nginx,但是在docker本身自己是无法完成的。
在docker之上就可以将这种隶属关系,从属关系,启动关系等等反应在启动关闭的次序逻辑中,这种功能就是容器编排。
这些编排工具有dockermachine+swarm,compose,以及kubernetes,还有mesos+marathon组合
但是在后来docker放弃了lxc,研发了自己的引擎libcontainer替换了lxc。而后标准化后的名称叫runC。此后的文章中所说的容器,如果未做说明,均指docker
参考:https://docs.docker.com/engine/docker-overview/#union-file-systems