背景简介
Mesos现在支持的容器化技术用得比较多的主要有两个,一个是Mesos Containerizer技术,一个是Docker Containerizer技术。Mesos Containerizer主要是利用操作系统本身的一些特性例如cgroup,namespace等来实现对container的隔离;Docker Containerizer主要是通过Mesos Agent调用Docker API来容器进行管理。
但是现在对多种容器化技术进行管理存在一些问题:
如果在Mesos维护多种容器化技术,那么当为容器管理添加新功能时,需要对不同的容器化技术进行改动,将这些功能在不同的容器化技术中做实现。起码目前来说,需要在Mesos Containerizer和Docker Containerizer分别实现。
Docker Containerizer主要通过调用Docker API来实现对Docker容器的管理,但是Docker API给Mesos定制的机会就很有限了,尤其是对于容器运行时的定制,例如一些Entrypoint,Cmd,Env等等,所有的功能都需要依赖于Docker的API;而Mesos Containerizer可以让用户自己定制一些Mesos Isolator(隔离器)来实现自己对容器隔离的一些需求,例如对网络,存储等的一些需求,都可以通过Mesos Isolator自己去定制化。
Docker Containerizer需要依赖于Docker Daemon,如果Docker Daemon挂掉重启后,所有的Docker Containerizer不能恢复到以前的状态。Mesos需要保证即使用户的Docker Daemon挂掉了,用户还是可以通过Docker镜像创建Docker Container。
Docker在大规模的时候,不是很稳定,Mesos曾经发现一个bug,发现有些container不能被正常的停掉,后来经过调研发现,原因是服务器的Docker Contaier太多了,导致docker daemon处理不过来,没反应了。但是这种情况碰到的其实不是太多,因为现在国内大多数的客户其实规模不是很大。
现在容器的spec很多,包括Docker,AppC,OCI等等。未来也许这些不同的spec会统一,但是现在格式很多,用户用起来不是很方便。如果目前对不同的spec都做不同的容器化技术实现的话,未来会更难维护。
其实个人感觉还有一个原因是Docker社区不够开放,Docker现在能够提供为客户提供足够多的Offer,包括公有云形式的Docker Cloud,也有私有云模式的Docker Data Center,其它开源软件很难再从Docker获利。
基于以上原因,Mesos在0.28引入了一个新的功能,叫做统一的容器管理技术,主要是对当前的Mesos Containerizer做了一些改进,使Mesos Containerizer能够对不同spec的容器进行管理,包括Docker,AppC和OCI,到目前为止,已经完成了对Docker和AppC的支持,未来会完成对OCI的支持。至于现有的Docker Containerizer,在短期内应该还会被Mesos社区继续维护,但是应该不会再有大的改动。
原理解析
上图是Mesos Containerizer的总体架构图,黄色部分为为了实现Mesos统一容器管理加入的一些新的模块,主要是针对Docker和AppC的两种不同的spec加入了不同的Provision模块。
Launcher的主要功能是启动mesos executor来执行用户的作业。Provision模块的主要功能是为Docker和AppC的容器创建root文件系统。Isolator主要是对Mesos Containerizer的容器做一些配置工作,例如一些动态配置,Mesos Agent重启后的一些recovery工作,容器销毁时的一些清理工作,获取一些容器运行时的动态信息等等。
在容器创建的时候,Mesos Containerizer会在Isolator对容器进行配置前,帮助容器把root文件系统创建好。在容器被销毁的时候,Mesos Containerizer会在所有的Isolator做完清理工作后,删除容器的root文件系统。
Provisioner简介
DockerProvisioner和MesosProvisioner的实现原理基本相同,主要包括如下几个步骤:
获取Docker或者AppC镜像,现在支持两种方式:本地和远端。Mesos Agent可以从本地或者远端通过URI来获取镜像。获取镜像只有在镜像第一次被使用的时候需要从本地或者远端获取,获取完成后,就会存放在本地的缓存中,以后所有使用该镜像的容器会从cache去获取镜像,提升了容器的创建速度。把容器存放在本地缓存有个问题,就是如果远端的镜像更新后,因为本地已经将以前的镜像缓存了,所以新创建的容器不能使用已经更新的远端镜像。Mesos现在正在解决这个问题(https://issues.apache.org/jira/browse/MESOS-4886),为Mesos Image Protobuf加入一个“强制获取镜像”的标记,framework的开发者如果需要强制获取镜像来更新本地的缓存,只需要使用该标记就可以从远端再次获取镜像,来更新本地的缓存。
通过获取的Docker或者AppC镜像为容器创建root文件系统。现在Mesos主要支持三种通过镜像文件创建文件系统的方式:
Copy Backend:这是最简单的方式,同时也是Mesos Agent默认的rootfs创建方式。Copy Backend主要时把镜像文件拷贝到创建容器的root路径,来创建该容器的root文件系统。Copy Backend的缺点是这种方式只适合于比较小的镜像文件,例如10到100M的镜像文件。如果镜像比较大的时候,使用Copy Backend会对IO的要求比较高。
Bind Backend:Bind Backend主要是为单层的大镜像文件设计的,例如单层5G的镜像文件。Bind Backend很快的原因是它只需要对镜像做一个Bind操作,基本上不需要任何的IO。但是Bind Backend也有一些缺点,例如它支持单层的镜像文件,并且Bind Backend的文件系统是只读的,用户需要为Bind Backend的容器去mount一些可以读写的Volume来实现读写的操作,这个可以借助Mesos Agent对外部存储的支持(详细点击)。
Overlay Backend:Overlay Backend主要是为了解决前面两种Backend的不足:Copy Backend对IO要求高,Bind Backend只能处理单层的镜像。关于Overlay的具体介绍,可以参考这里。Overlay Backend也有两个局限,第一个是Overlay Backend只支持多层的镜像,不支持单层的镜像。第二个是Overlay Backend的文件系统也是只读的,需要借助于外部存储来实现容器的读写操作。但是Mesos在计划对这两个局限做些改进,及让Overlay Backend同时支持单层和多层镜像,同时rootfs也可写。这个问题现在正在解决,具体参考这里。
对于容器的多种文件系统的创建方式,Mesos长期的计划是实现一种灵活的后端选取方式:由Mesos Agent根据镜像的格式,大小,操作系统的配置来选择合适的系统创建方式。例如,如果镜像很大,那么Mesos Agent会选择Bind Backend或者overlay Backend来加速容器的root文件系统的创建速度;如果镜像不是很大,那么Mesos Agent会选择Copy Backend等等。
Isolator改进
Mesos统一容器技术的一个主要目的是可以实现对容器的定制和一些运行时的配置,所以Mesos统一容器也新引入了一些isolator来对容器进行管理。最主要的有三个Isolator。
Docker Runtime Isolator
Docker Runtime Isolator主要是为了支持docker镜像的一些运行时配置信息,例如Entrypoint, Cmd. Env, WorkingDir等等。举个例子,如果用户在运行framework的Task的时候,如果Task不是一个shell命令,这个时候Docker Runtime Isolator就会使用Entrypoint或者Cmd来运行用户作业。关于Docker Runtime Isolator的详细介绍,可以参考这里。
CNI Isolator
在没有引入CNI之前,Mesos Containerizer对Docker容器的网络默认用的都是host模式。CNI Isolator主要是为了利用了AppC的CNI的一些命令来对容器网络进行配置,例如可以通过一些网络配置文件调用CNI的一些命令,例如bridge,flannel,host-local等来对容器的网络进行配置。用户在使用这个功能的时候,需要指定CNI的配置文件路径和CNI命令的路径,保证Mesos Agent在使用CNI Isolator的时候,能够根据配置文件调用CNI命令来对容器网络进行配置。这个项目的主体部分已经完成,具体可以参考这里和这里。
Docker Volume Isolator
这个isolator的主要作用是能够让Mesos通过Docker Volume Driver API使用外部存储,集成完成后,Mesos可以利用Docker Volume Driver所支持的所有外部存储资源,对用户的一些作业运行结果等进行存储。这个项目分两个阶段,第一阶段是利用EMC开发的一个dvdcli,通过dvdcli来获取外部存储的挂载点,所以用户在使用这个功能的时候,需要在agent启动的时候指定dvdcli的路径,以便Mesos Agent调用dvdcli获取容器的挂载点。第二阶段是摆脱对dvdcli的依赖,将dvdcli的逻辑作为Mesos的一个C++库,Docker Volume Isolator可以直接通过调用这个C++库来获取挂载点。该项目第一阶段目前已经完成,用户可以通过安装dvdcli来使用这个功能。具体可以参考这里和这里。
统一容器管理技术的优势
Mesos统一容器管理技术的优势主要是解决了“背景简介”中的一些问题:
通过一种容器化技术来管理所有不同spec的容器,例如Docker,AppC等,简化了Mesos的开发和维护工作。
摆脱了对Docker Daemon的依赖,如果使用Mesos Containerizer,即使Docker Daemon挂掉了,用户依然可以通过Mesos Containerizer创建Docker容器。
Mesos Containerizer可以让用户自己定制一些Mesos Isolator(隔离器)来实现自己对容器隔离的一些需求,例如对网络,存储等的一些需求,都可以通过Mesos Isolator自己去定制化。
后续工作
AppC 改进
AppC现在没有类似于Docker的Runtime Isolator,这就导致使用AppC镜像的时候,不能使用Appc的一些运行时配置,例如 environment variables, exec, working directory等等。这个问题正在改进,具体参考这里。
另外一个问题是AppC的镜像发现机制。现在AppC只支持很简单的镜像发现机制。用户在启动Mesos Agent的时候,需要通过参数appc_simple_discovery_uri_prefix来指定AppC的镜像的发现机制。例如用户可以使用http://, https://,hdfs://:9000/user/abc/cde,file:///tmp/appc/等等,默认值是http://,然后Mesos Agent会在这个URI后添加镜像名字来补齐该URI,镜像名字的格式为{name}-{version}-{os}-{arch}.{ext}。举个例子,某用户的appc_simple_discovery_uri_prefix配置为file:///tmp/appc/,然后用户在启动Task的时候,指定的AppC镜像为ubuntu,用户的os为Linux,arch为amd64,那么最终Mesos Agent就会从file:///tmp/appc/ubuntu-latest-linux-amd64.aci来查找AppC镜像。现在AppC不支持meta的镜像发现模式,已经有JIRA在跟踪这个问题,具体参考这里和这里。
OCI支持
目前Mesos Containerizer对统一容器管理只完成了Docker和部分的AppC的支持,对OCI的支持还没开始,一个主要的原因是OCI的标准现在还没有最终定下来,所以这块对Mesos优先级还不是很高。Mesos现在已经有JIRA在跟踪这个问题,详细。
Mesos Container CLI
现在Mesos没有类似于“docker ps”,“docker inspect”等的命令来查看所有容器的状态,未来Mesos打算引入类似的命令来帮助用户很方便的通过mesos命令查看系统中所有Mesos Container的状态等等。
测试步骤
因为统一容器管理技术的所有功能都是在Mesos Agent 实现的,并且所有功能都是通过参数来控制,现在主要介绍一些配置和参数和Agent的启动测试命令。
配置参数
用户如果想使用Mesos统一容器的功能,有几个Agent参数是很重要的。
1. –isolation:主要配置当前Mesos Agent所使用的isolator,例如如果通过Mesos Containerizier来使用Docker容器的话,必须配置docker/runtime作为isolator,否则Agent无法启动。
2. –image_providers:配置当前Agent的镜像提供这,现在只支持APPC和DOCKER。
3. –appc_simple_discovery_uri_prefix:配置APPC的镜像前缀,该参数在“后续工作”有介绍。
4. –docker_registry:配置Docker的registry,现在支持Docker Hub,Local Registry和本地路径。
Docker测试
为了加速测试,我采用的是本地镜像的测试方法。首先把一些Docker镜像存储在本地,可以通过命令“docker save”来将镜像存储到本地,以busybox为例,通过命令“docker save -o busybox:latest.tar busybox”可以将busybox镜像存储到本地。
root@mesos002:~# ls /root/reglocal
alpine.tar busybox:latest.tar ubuntu:14.04.tar
Mesos Agent启动命令:
GLOG_v=1 ./bin/mesos-slave.sh --master=192.168.56.12:5050 --isolation=docker/runtime,filesystem/linux --image_providers=docker --launcher=linux --executor_environment_variables="{}" --docker_registry=/root/reglocal
测试使用的是Mesos自带的测试命令:
./src/mesos-execute --master=192.168.56.12:5050 --name=test_mesos --docker_image=busybox:latest --containerizer=mesos --command="sleep 10"
I0404 01:08:42.160414 14128 scheduler.cpp:172] Version: 0.29.0
Subscribed with ID '3327bb81-f2a0-400a-8411-79910af7b343-0001
task test_mesos submitted to agent 030ca997-9310-48bb-973f-d53136022537-S0
Received status update TASK_RUNNING for task test_mesos
Received status update TASK_FINISHED for task test_mesos
在命令运行的时候,可以通过查看Mesos Agent日志来了解Mesos Agent的工作流程,从Mesos Agent此时的日志,可以看到Mesos Agent是如何获取镜像,如何创建root文件系统等等。
AppC测试
同样为了加速测试,我采用的是本地镜像的测试方法。首先把一些AppC镜像存储在本地。创建AppC镜像的方式很多,最简单的是通过命令docker2aci来将一个Docker镜像转换为一个AppC镜像,具体参考这里。
root@mesos002:~# ls /root/appclocal/
ubuntu-latest-linux-amd64.aci ubuntu-latest.aci ubuntu2-latest-linux-amd64.aci
Mesos Agent启动命令:
GLOG_v=1 ./bin/mesos-slave.sh --master=192.168.56.12:5050 --executor_registration_timeout=5mins --containerizers=mesos --isolation=filesystem/linux --image_providers=APPC --appc_simple_discovery_uri_prefix=/root/appclocal/
测试使用的是Mesos自带的测试命令:
./src/mesos-execute --master=192.168.56.12:5050 --command="/bin/echo ello ubuntu;" --name=test --appc_image=ubuntu
I0404 01:12:35.006664 14223 scheduler.cpp:172] Version: 0.29.0
Subscribed with ID '3327bb81-f2a0-400a-8411-79910af7b343-0002
task test submitted to agent 030ca997-9310-48bb-973f-d53136022537-S0
Received status update TASK_RUNNING for task test
Received status update TASK_FINISHED for task test