mesos容器
概述
mesos容器的支持采用插件式结构,如图:
见https://github.com/apache/mesos/blob/master/docs/containerizer-internals.md
- 在每个isolator上调用prepare
- 使用Launcher来fork executor,fork出的子进程直到被isolated之前一直被阻塞
- 调用isolate来隔离executor,参数是每个isolator的pid
- 获取executor
- 执行executor
容器镜像的支持
见https://github.com/apache/mesos/blob/master/docs/container-image.md
层次关系如下:
镜像provisioner提供相关支持,其负责pulling,caching及准备容器的根文件系统。并且将运行时的配置从容器映像中提取出来传递给相应的isolator。
容器映像有几种规格:
provisioner后端
后端将一级文件系统层集合堆栈组成成一个根文件系统。当前支持以下后端:
Copy
将所有层拷贝到目标根目录以创建一个根文件系统
Bind
这个用于单层在大映像(多个GB)。对于小的映像(10-100个MB)Copy后端可能就足够了。Bind是零拷贝所有很快。
但有两个限制:
- 只支持单层。
- 文件系统只读。
Overlay
AUFS
使用mesos容器
用户如果想使用Mesos统一容器的功能,有几个Agent参数是很重要的。
--isolation
:主要配置当前Mesos Agent所使用的isolator,例如如果通过Mesos Containerizier来使用Docker容器的话,必须配置docker/runtime作为isolator,否 则Agent无法启动。--image_providers
:配置当前Agent的镜像提供这,现在只支持APPC和DOCKER。--appc_simple_discovery_uri_prefix
:配置APPC的镜像前缀,该参数在“后续工作”有介绍。--docker_registry
:配置Docker的registry,现在支持Docker Hub,Local Registry和本地路径。
启动master:$ sudo sbin/mesos-master --work_dir=/tmp/mesos/master
启动agent:
$ sudo GLOG_v=1 sbin/mesos-agent \
--master=<MASTER_IP>:5050 \
--isolation=docker/runtime,filesystem/linux \
--work_dir=/tmp/mesos/agent \
--image_providers=docker \
--executor_environment_variables="{}"
使用命令行启动docker容器,注意--shell=false
是通知mesos使用docker映像中的缺省entrypoint和cmd
$ sudo bin/mesos-execute \
--master=<MASTER_IP>:5050 \
--name=test \
--docker_image=library/redis \
--shell=false
验证redis已经运行:
$ sudo docker run -ti --net=host redis redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379>
Executor与容器映像的相关
mesos的所有task是由executor启动的。对于某个框架(如aurora)中的通用executor来说,要求它所有的依赖关系在所有的容器映像中都满足可能并不容易。
为此,我们提供了一种解决方案,允许executor运行在主机文件系统(无容器映像)。另外,它可以定义一个volume,其源为一个Image。mesos容器将在volume中部署image,并将其mount在sandbox目录。executor可以执行pivot_root或chroot以进入容器根文件系统。
MesosContainerizer::create
- 150-182:process,cgroups,disk标志已经过时,提示用户并转换标志
- 184-194:如果启动时有network/标志,则加上network/cni
- 199-204:创建ContainerLogger对象,若失败,则返回错误
- 207-241:launcher设置成一个lambda函数,函数的功能是:
- 209-219:若命令行参数标志设置了launcher,则调用LinuxLauncher::create或者PosixLauncher::create并返回
- 222-224:这是命令行未指定launcher的情况了,若LinuxLauncher可用,则调用LinuxLauncher::create否则调用PosixLauncher::create并返回
- 243-245:若launcher失败,则返回错误
- 247-250:调用Provisioner::create创建Provisioner对象,失败则返回出错信息
- 271-330:初始化一个hash映射表creators,key为标明不同isolator的字符串,value为创建isolator的函数,见isolator
- 332-338:创建字符串向量isolations,解析命令行中指定及隐含的isolator
- 340:声明一个Isolator向量isolators
- 342-365:对isolations向量中定义的每一个字符串isolation:
- 343-350:声明一个lambda函数isolator,功能是若creators映射表中包含isolation字符串,则返回creators映射表中该项对应的isolator对象创建函数;否则返回
ModuleManager::create<Isolator>(isolation)
- 352-355:确保isolator函数正确创建,否则返回错误
- 360-361:若isolation中包含"filesystem/",将该isolator插入到isolators向量的最前面,确保它被第一个调用
- 362-364:否则,将该isolator插入到isolators向量末尾
- 343-350:声明一个lambda函数isolator,功能是若creators映射表中包含isolation字符串,则返回creators映射表中该项对应的isolator对象创建函数;否则返回
- 367-374:创建并返回一个MesosContainerizer对象
MesosContainerizer::MesosContainerizer
378-396:代码很简单,创建新的MesosContainerizer对象,初始化,并启动它的内部进程
MesosContainerizer::MesosContainerizer(
const Flags& flags,
bool local,
Fetcher* fetcher,
const Owned<ContainerLogger>& logger,
const Owned<Launcher>& launcher,
const Owned<Provisioner>& provisioner,
const vector<Owned<Isolator>>& isolators)
: process(new MesosContainerizerProcess(
flags,
local,
fetcher,
logger,
launcher,
provisioner,
isolators))
{
spawn(process.get());
}
另外,399-404还有另一种构造函数,不知什么时候调用:
MesosContainerizer::MesosContainerizer(
const Owned<MesosContainerizerProcess>& _process)
: process(_process)
{
spawn(process.get());
}
MesosContainerizer::launch
MesosContainerizer中多个函数都是通过libprocess模块中的dispatch,最终调用MesosContainerizerProcess中的对应函数,并原样传递参数
这些函数包括:
- launch
- update
- usage
- status
- wait
- destroy
- containers
- recover
MesosContainerizerProcess中定义了containers_,是hash表,containerID和Container组成。
MesosContainerizerProcess::launch
参数:
- containerId
- taskInfo:可能为None(),因为在Framework::launchExecutor()中调用slave->containerizer->launch时有两种情况,其中一种是没有taskInfo的
- _executorInfo
- directory
- user
- slaveId
- slavePid
- checkpoint
流程:
- 754-756:确保本对象的containers_中包含了containerId
- 758-762:若taskInfo存在,且有container但其类型不为MESOS,则返回失败
- 766-771:得到executorInfo,若它有container但其类型不为MESOS,则返回失败
- 775-779:。。。。。。。。
- 785-796:创建一个新的Container对象container,并设置目录,状态为PROVISIONING,资源,ID,launchInfos
- 805-819:若executorInfo中未设置container(对于不是执行容器的,就不会设置container),则:
- 调用prepare
- 成功后再调用launch,并且传递给launch的provisionInfo参数是None()
- 完成后函数返回
- 823-833:查看是否有容器镜像
- 835-836:若没有容器镜像,则调用_launch(_launch中会先调用provision),并函数返回。在这里没有容器镜像很奇怪???????
- 847-851:创建provision异步调用provisioning = provisioner->provision,并加入container->provisionInfos队列中。这里的provisioner->provision是准备容器镜像,参见provision
- 853-864:当provisioning完成,则调用MesosContainerizerProcess::_launch
MesosContainerizerProcess::_launch
参数:
- containerId
- taskInfo
- executorInfo
- directory
- user
- slaveId
- slavePid
- checkpoint
- provisionInfo
流程:
- 879-898:各种正确性判断,container状态必须为PROVISIONING
907-927:对于ContainerInfo::volumes定义的镜像也要做provision
- 循环检查_executorInfo->container()中的每个volume(在ContainerInfo::volumes也可以定义image,所以这里要再处理image):
- 必须有image volume->has_image()
- 调用provisioner->provision(containerId, image)
931-951:先做prepare,prepare返回一组ContainerLaunchInfo,完成后调用对返回的这组ContainerLaunchInfo中每一个调用__launch
MesosContainerizerProcess::__launch
参数:
- containerId
- taskInfo
- executorInfo
- directory
- user
- slaveId
- slavePid
- checkpoint
- provisionInfo
- launchInfos
流程:
- 1095-1103:各种正确性判断,状态必须为PREPARING
- 1106-1112:准备executor的环境变量
- 1115-1118:准备executor的根文件系统
- 1123-1161:准备环境变量、工作目录 、executor要执行的命令
- 1170-1178:继续设置环境变量
- 1186:对launchInfos中的每一个launchInfo:
- 1187-1189:若launchInfo无内容,跳到下一次循环
- 1193-1195:从launchInfo->pre_exec_commands()中每一个command,放到preExecCommands变量中
- 1198-1203:若launchInfo有相关环境设置,也放在环境变量中
- 1205-1207:若launchInfo有名字空间,也放在namespaces中
- 1210-1212:设置命令:executorLaunchCommand
- 1215-1218:若有provisionInfo,命令中加入rootfs选项(有相应的容器镜像,才有provisionInfo,见847行和844行)
- 1220:调用logger->prepare(logger定义在containerizer.hpp第284行,类型是mesos::slave::ContainerLogger)
- 1221-1350:完成prepare后,调用lambda函数,该函数执行以下操作:
- 1227-1231:创建操作系统管道pipes
- 1236:设置launch命令
- 1238:若executor没有rootfs,意味着与主机共享文件系统
- 1242-1247:若有工作目录,输出警告
- 1249:设置工作目录
- 1250-1254:否则,设置工作目录为参数指定目录或sandbox目录
- 1269-1270:设置launchFlags的根文件系统和用户名
- 1274-1275:设置launchFlags的读写管道
- 1282:设置launchFlags的preExecCommands
- 1288-1290:设置启动命令参数,程序名固定为MESOS_CONTAINERIZER,值为"mesos-containerizer",这个命令对应的源代码在src/slave/containerizer/mesos/main.cpp。argv[1]值为"launch"(launch.cpp 53行)
- 1292-1303:调用launcher->fork创建子进程(launcher是MesosContainerizerProcess的私有变量,在初始化时设置,可以是linuxlauncher或者posixlauncher
- 1308:得到fork子进程的pid
- 1311-1331:若有checkpoint,则执行相关动作。。。。
- 1335-1337:。。。。。。。。。
- 1339-1349:执行isolate,再执行fetch,再执行exec。。。。。
MesosContainerizerProcess::prepare
参数:
- containerId
- taskInfo
- executorInfo
- directory
- user
- provisionInfo
流程:
- 990-1001:判断container如果被删除,则返回失败;判断container状态必须是PROVISIONING
- 1003:将container状态改为PREPARING
- 1006-1025:初始化containerConfig,设置目录、executor、taskInfo、user、容器镜像等信息,尤其注意1022-1023将从docker manifest中得到的信息都拷贝到containerConfig
- 1030-1031:构建一个异步的ContainerLaunchInfo列表
- 1033-1040:对isolators(是MesosContainerizerProcess对象中的私有变量)中的每个isolator:
- 1035-1039:调用_prepare,得到新的ContainerLaunchInfo列表收集到列表中
- 1042:返回列表
_prepare
- 971:调用isolator->prepare
- 972:将此次的ContainerLaunchInfo放入列表最后,得到新的列表
针对docker的prepare
src/slave/containerizer/mesos/isolators/docker/runtime.cpp
DockerRuntimeIsolatorProcess::prepare
参数:
- containerId
- containerConfig
准备各种环境变量、要执行的命令等。
MesosContainerizerProcess::exec
- 1400-1408:检查容器状态
- 1412-1420:写管道,直到写成功为止,启动MesosContainerizerLaunch对象,见MesosContainerizerLaunch::execute
- 1422:容器状态改为RUNNING
MesosContainerizerProcess::destroy
参数:
- containerId
流程:
- 1598-1613:有多种可能调用本函数,因此需要判断本容器ID是否还存在
- 1615:获得容器对象container
- 1617-1620:若容器状态是DESTROYING,则返回
- 1624-1642:若容器状态是PROVISIONING,将状态改为DESTROYING,并等待provision完成后调用
____destroy
并返回 - 1644-1663:若容器状态是PREPARING,将状态改为DESTROYING,对容器的launchInfos调用
___destroy
并返回 - 1665-1677:若容器状态是ISOLATING,将状态改为DESTROYING,对容器的isolation调用
_destroy
并返回 - 1680-1682:若容器状态是FETCHING,调用fetcher->kill(containerId)
- 1684:将状态改为DESTROYING,调用
_destroy
并返回
其他destroy时的主要动作有:
MesosContainerizerProcess::____destroy
中会调用provisioner->destroy(containerId)MesosContainerizerProcess::_____destroy
中会设置。。。。。。
一个执行使用mesos引擎执行docker镜像容器的例子
sudo mesos/mesos-1.0.1/build/src/mesos-execute \
--master=192.168.10.34:5050 \
--name=test \
--docker_image=ubuntu:14.04 \
--containerizer=mesos \
--command="dd if=/dev/zero of=yhw bs=1024 count=1" \
--shell=true
- slaveID 190e0cc6-594c-4bfe-b9cb-5b88dd3cfa09-S0
- 创建了framework 190e0cc6-594c-4bfe-b9cb-5b88dd3cfa09-0000
- 容器ID 589e83d2-c707-493a-bd7a-ff4d2c9357eb
容器镜像最上层目录: slaveworkdir/provisioner/containers/589e83d2-c707-493a-bd7a-ff4d2c9357eb/backends/aufs/rootfses/c78b3ef2-d680-40a7-84b6-4416f159ee15
slaveworkdir/provisioner/containers/ContainerID/backends/aufs/rootfses/UUID
使用AUFS选项mount目录:
dirs=/home/yhw/work/swcontainer/slaveworkdir/provisioner/containers/589e83d2-c707-493a-bd7a-ff4d2c9357eb/backends/aufs/scratch/c78b3ef2-d680-40a7-84b6-4416f159ee15/workdir:/tmp/mesos/store/docker/layers/9bc9537638433df5e03e4327bb57c9aa9f1372f9985928d7562a857e242b377d/rootfs:/tmp/mesos/store/docker/layers/3436fb2d153cec3ec1981b7f49bc69d88705b5864e95fdf17a13b316347da00b/rootfs:/tmp/mesos/store/docker/layers/2aaf3127c72c32cb81fe7085062eb83dc3727edd9d6fd2e02e5d47aba89b4cd8/rootfs:/tmp/mesos/store/docker/layers/460a0b713cac353ba041c303e786d6a068f515e5362f14efcf211cc7c243556f/rootfs:/tmp/mesos/store/docker/layers/39cdc7007d14204df14774895ef95342980fca2774808ebec5dfb6efa08c0e66/rootfs
第一层是创建的临时目录,可写;后面的以/tmp/mesos/store开头的目录是ubuntu:14.04镜像所在的本地目录,每个目录代表镜像的一层;这些目录都将mount到容器的根目录:/home/yhw/work/swcontainer/slaveworkdir/provisioner/containers/589e83d2-c707-493a-bd7a-ff4d2c9357eb/backends/aufs/rootfses/c78b3ef2-d680-40a7-84b6-4416f159ee15
所以,容器的根目录是slaveworkdir/provisioner/containers/ContainerID/backends/aufs/rootfses
看起来,只是mount了根目录,未执行容器的命令????
无法执行交互式的命令??通过容器启动redis服务是可以的。