接上一篇《体验docker+mesos+marathon》。
像mysql,redis这种存储系统都会在磁盘上存储数据,如果利用marathon部署,那么每次重启容器就会销毁,并且容器内的数据也随之消失,我们称这种应用为有状态的应用,需要借助marathon的本地数据卷技术实现。
简单原理
marathon在webui上支持可视化的配置本地数据卷,而本地数据卷能力本身是mesos来支撑的,它的原理并不复杂:mesos在某agent所在宿主机上创建一个数据目录,并在启动容器的时候挂载到容器中。
当容器退出后,数据目录仍旧保存在宿主机上,下次再启动该app的时候marathon与mesos会合作将这个app的容器再次部署到原先的宿主机上,而不是其他机器,这是因为该app使用的数据卷(volumes)是基于宿主机的,不能随便移动,因此mesos+marathon能做到的就是将容器放到数据卷所在的机器,并且永远这样做。
工作原理
按照上一篇博客的部署,是无法直接使用数据卷的,需要修改配置,这主要是因为mesos的数据卷功能是基于Reservation(资源保留)机制来控制访问的,而Reservation(资源保留)又要求Authentication(认证)+Authorization(授权)后才能使用。
Authentication认证
简单的说,mesos-master对连接到其上的组件都支持基于帐号+密码的认证,主要是指framework(例如marathon)和mesos-agent,这样的目的当然是出于安全。
在mesos里,帐号称作Principals,密码称作Secrets,在mesos-master启动的时候可以配置一个帐号密码列表给它,没那么复杂。
默认mesos-master不要求认证,可以以任何Principals登录,我们也就不费劲去给mesos-master配置密码了,如果你感兴趣可以看这个文档。
Authorization授权
当你以一个Principals登录成功后,mesos-master会基于ACLs进行操作授权,简单的说:你的帐号能否执行任务,能否分配数据卷,能否注册一个framework,都是要授权的,否则mesos-master不会理你的请求。
ACLs是基于Principals帐号为基准,进行权限配置的。
在mesos-master启动的时候可以配置一个授权文件给它,关键是理解ACLs文件怎么编写,官方文档看这里,我只讲怎么快速理解。
先下载一个官方示例文件,授予所有用户所有权限:
1 |
wget http://mesos.apache.org/documentation/latest/examples/acls_template.json |
首先是全局的一个配置项,它的作用是当请求无法与任何一条ACL规则匹配的时候,是否允许其执行:
“permissive”: false
为false则表示不允许继续执行,为true则表示允许执行。
其次就是每一个权限项了,每个权限项下面是一个数组,可以存在多个配置,其中每一个配置都在表达下面这样的含义:
以”register_frameworks注册框架”这个权限项为例,
1 2 3 4 5 6 7 8 9 10 |
"register_frameworks": [ { "principals": { "type": "ANY" }, "roles": { "type": "ANY" } } ], |
这个数组内只包含一项,我们看这一项:其中principals内可以配置value或者type,其中value可以是字符串或者字符串数组,它表名value指定的这些用户应该执行这条规则;如果配置type,那么ANY表示任何人都应该执行这条规则,NONE表示没有人可以执行这条规则。
而除了principals之外的key值,是与权限项相关的,每一种都不一样,可以跳转上面的官方文档看一下列表,在下面的例子中用到的register_frameworks权限项的key值叫做roles,其目的是限制principals可否以某role角色来注册framework。
注意:ACLs匹配时遇到第一个匹配项就会终止匹配,因此规则的出现顺序很重要。另外,要理解NONE的意思需要结合permissive来看,具体看个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
{ "register_frameworks": [ { "principals": { "values": ["foo"] }, "roles": { "values": ["analytics"] } }, { "principals": { "type": "NONE" }, "roles": { "values": ["analytics"] } } ] } |
- 第一个规则表示:foo用户可以使用analytics这个role来注册framework。
- 第二个规则表示:没有任何用户可以使用analytics这个role来注册framework。
- 全局permissive:默认为true,没有匹配任何规则的请求将被授权。
这样写意味着什么呢?
- foo用户以role=analytics注册framework的请求,会被第一个规则命中,授权成功。
- owen用户以role=analytics注册framework的请求,不命中第一个规则,但是命中第二个规则:没有人可以以role=analytics注册framework,因此被拒绝。
- owen用户以role=other注册framework的请求,不命中第一个规则,也不命中第二个规则,因此授权成功。
理解了ACLs,废话就不多说了,因为permissive默认为true并且mesos-master启动时没有指定任何ACLs配置,因此所有的principals以任何role来注册framework都将授权,不仅如此其他所有配置项都一样被默认授权,无需显式的配置。
Reservation资源保留
mesos以role为单位,对集群的资源进行划分,以相同role注册到mesos-master的framework可以共享资源池,而这个资源池是可以通过mesos-agent启动时通过命令行参数为具体role进行资源预留的:比如启动mesos-agent时指定owen用户可以享受本机的5个cpu和10G内存,剩余的资源可以分配给任何其他role。
默认我们启动mesos-agent是没有配置资源预留的,也就是没有把资源按role划分成池子,因此默认mesos-agent上的所有资源都可以被任何framework以任何role占用。当然,除了cpu和mem这种资源外,我们要用到的Persistent Volumes持久数据卷也是其中之一。
framework和meos之间通过遵循一种Reservation资源占用的协议来分配与管理数据卷,简单来理解:framework以某principals以及role注册framework到mesos-master后,当mesos-master offer一些资源给framework时,framework可以通过reservation创建数据卷在某个agent上,此后在该agent上启动容器可以挂载访问这个数据卷。当容器宕机或者重启时,mesos会把这种被占用的资源发给原先的framework,这样原先的framework可以让app重新在原agent上加载,这样就达到了依靠本地持久数据卷实现有状态服务的目的。
官方文档可以参考这里。
开始部署
真正要使用持久数据卷并不麻烦,只需要修改marathon的启动参数,给它指定一个principals和一个role即可,默认mesos-master是不会验证密码以及role是否合法,我们只是给mesos-master必要的标识,这样才使用reservation资源保留机制来使用持久数据卷。
1 2 3 4 5 6 7 |
[root@localhost marathon]# cat start_all.sh #!/bin/bash ps aux|grep marathon|grep -v grep|awk '{print $2}' |xargs -n1 kill -9 sleep 1 HOSTNAME=`ifconfig enp0s3 | grep "inet" |grep netmask|awk '{print $2}'` nohup /root/marathon/marathon1/bin/start --mesos_authentication_principal=marathon --mesos_role=marathon-framework --hostname=$HOSTNAME --http_port=8080 --master zk://localhost:2181,localhost:2182,localhost:2183/mesos/master --zk zk://localhost:2181,localhost:2182,localhost:2183/marathon >/dev/null 2>&1 & nohup /root/marathon/marathon2/bin/start --mesos_authentication_principal=marathon --mesos_role=marathon-framework --hostname=$HOSTNAME --http_port=8081 --master zk://localhost:2181,localhost:2182,localhost:2183/mesos/master --zk zk://localhost:2181,localhost:2182,localhost:2183/marathon >/dev/null 2>&1 & |
在上一篇博客的脚本基础上,添加了2个参数:
1 |
--mesos_authentication_principal=marathon --mesos_role=marathon-framework |
principal和role可以随便起名,确保不要和mesos集群上其他的framework冲突即可,此后重启marathon进入webui配置一个有状态的app吧。
创建centos的docker app
假设我要创建的是一个mysql服务,因此只需要配置1个实例,并且希望marathon能持久化mysql的数据,即便其部署所在的机器宕机也不要为我自动的迁移到其他机器,所以需要用到数据卷。
我直接用了centos镜像,后面我需要登录到这个容器内去看一下数据卷的情况。
这里,我做了2个事情:
- 创建一个mesos的持久数据卷,命名目录为my_volumes,大小为100MB。
- 让docker容器把这个my_volumes目录映射到容器的/var/lib/mysql目录,这样mysql向/var/lib/mysql写入的数据就会持久化在my_volumes这个数据卷里了。
最后创建app,可以看到这样的配置以及数据卷:
大概是什么原理呢?其实,mesos-agent在启动一个容器时是会为它准备一个沙箱环境的,简单的理解就是在宿主机上创建一个独一无二目录,并在其中放置一些容器相关的数据,其中数据卷目录就在其中。
我们在宿主机上找出volumes-app对应的mesos-docker-executor进程,它的参数表明了这一切:
1 2 3 4 |
[root@localhost marathon]# ps aux|grep mesos|grep volumes-app root 10216 0.5 3.5 809084 66652 ? Ssl 15:27 0:04 mesos-docker-executor --container=mesos-cb3b9bc3-9d3b-449b-8bf9-f29f2a8e171a-S0.027f9c37-fd61-44be-8ea2-a24c83db95da --docker=docker --docker_socket=/var/run/docker.sock --help=false --initialize_driver_logging=true --launcher_dir=/usr/local/libexec/mesos --logbufsecs=0 --logging_level=INFO --mapped_directory=/mnt/mesos/sandbox --quiet=false --sandbox_directory=/root/mesos/agent1/slaves/cb3b9bc3-9d3b-449b-8bf9-f29f2a8e171a-S0/frameworks/0b5532ac-6b06-4231-9c73-35ea41fae403-0000/executors/volumes-app.65319332-ef62-11e6-b51b-02425dc10031/runs/027f9c37-fd61-44be-8ea2-a24c83db95da --stop_timeout=0ns root 10226 0.0 0.5 118404 9580 ? Sl 15:27 0:00 docker -H unix:///var/run/docker.sock run --cpu-shares 102 --memory 33554432 -e MARATHON_APP_VERSION=2017-02-10T07:27:36.351Z -e HOST=172.18.9.75 -e MARATHON_APP_RESOURCE_CPUS=0.1 -e MARATHON_APP_RESOURCE_GPUS=0 -e MARATHON_APP_DOCKER_IMAGE=centos -e MESOS_TASK_ID=volumes-app.65319332-ef62-11e6-b51b-02425dc10031 -e PORT=31101 -e MARATHON_APP_RESOURCE_MEM=32.0 -e PORTS=31101 -e MARATHON_APP_RESOURCE_DISK=0.0 -e MARATHON_APP_LABELS= -e PORT_31101=31101 -e MARATHON_APP_ID=/volumes-app -e PORT0=31101 -e MESOS_SANDBOX=/mnt/mesos/sandbox -e MESOS_CONTAINER_NAME=mesos-cb3b9bc3-9d3b-449b-8bf9-f29f2a8e171a-S0.027f9c37-fd61-44be-8ea2-a24c83db95da -v /root/mesos/agent1/slaves/cb3b9bc3-9d3b-449b-8bf9-f29f2a8e171a-S0/frameworks/0b5532ac-6b06-4231-9c73-35ea41fae403-0000/executors/volumes-app.65319332-ef62-11e6-b51b-02425dc10031/runs/027f9c37-fd61-44be-8ea2-a24c83db95da/my_volumes:/var/lib/mysql:rw -v /root/mesos/agent1/slaves/cb3b9bc3-9d3b-449b-8bf9-f29f2a8e171a-S0/frameworks/0b5532ac-6b06-4231-9c73-35ea41fae403-0000/executors/volumes-app.65319332-ef62-11e6-b51b-02425dc10031/runs/027f9c37-fd61-44be-8ea2-a24c83db95da:/mnt/mesos/sandbox --net bridge -p 31101:31101/tcp --entrypoint /bin/sh --name mesos-cb3b9bc3-9d3b-449b-8bf9-f29f2a8e171a-S0.027f9c37-fd61-44be-8ea2-a24c83db95da centos -c while true; do sleep 1; done [root@localhost marathon]# ll /root/mesos/agent1/slaves/cb3b9bc3-9d3b-449b-8bf9-f29f2a8e171a-S0/frameworks/0b5532ac-6b06-4231-9c73-35ea41fae403-0000/executors/volumes-app.65319332-ef62-11e6-b51b-02425dc10031/runs/027f9c37-fd61-44be-8ea2-a24c83db95da |
关注到其中2个选项:
1 2 |
--mapped_directory=/mnt/mesos/sandbox --sandbox_directory=/root/mesos/agent1/slaves/cb3b9bc3-9d3b-449b-8bf9-f29f2a8e171a-S0/frameworks/0b5532ac-6b06-4231-9c73-35ea41fae403-0000/executors/volumes-app.65319332-ef62-11e6-b51b-02425dc10031/runs/027f9c37-fd61-44be-8ea2-a24c83db95da |
容器在宿主机上的沙盒目录为/root/mesos/agent1/slaves/cb3b9bc3-9d3b-449b-8bf9-f29f2a8e171a-S0/frameworks/0b5532ac-6b06-4231-9c73-35ea41fae403-0000/executors/volumes-app.65319332-ef62-11e6-b51b-02425dc10031/runs/027f9c37-fd61-44be-8ea2-a24c83db95da,这个目录映射到容器中/mnt/mesos/sandbox路径。
在宿主机上打开/root/mesos/agent1/slaves/cb3b9bc3-9d3b-449b-8bf9-f29f2a8e171a-S0/frameworks/0b5532ac-6b06-4231-9c73-35ea41fae403-0000/executors/volumes-app.65319332-ef62-11e6-b51b-02425dc10031/runs/027f9c37-fd61-44be-8ea2-a24c83db95da可以看到我们的数据卷目录坐落在其中:
1 2 3 4 5 |
[root@localhost marathon]# ll /root/mesos/agent1/slaves/cb3b9bc3-9d3b-449b-8bf9-f29f2a8e171a-S0/frameworks/0b5532ac-6b06-4231-9c73-35ea41fae403-0000/executors/volumes-app.65319332-ef62-11e6-b51b-02425dc10031/runs/027f9c37-fd61-44be-8ea2-a24c83db95da 总用量 8 drwxr-xr-x. 2 root root 15 2月 10 15:29 my_volumes -rw-r--r--. 1 root root 1541 2月 10 15:27 stderr -rw-r--r--. 1 root root 1315 2月 10 15:27 stdout |
那么容器中又是什么样呢?因为我们的容器是docker容器,所以可以利用docker连接到容器中:
1 2 3 |
[root@localhost marathon]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3dab752cfc59 centos "/bin/sh -c 'while..." 18 minutes ago Up 18 minutes 0.0.0.0:31101->31101/tcp mesos-cb3b9bc3-9d3b-449b-8bf9-f29f2a8e171a-S0.027f9c37-fd61-44be-8ea2-a24c83db95da |
首先docker ps找到这个容器的ID,然后通过docker exec -it 容器ID bash打开一个连到容器的虚拟终端:
1 2 |
[root@localhost marathon]# docker exec -it 3dab752cfc59 bash [root@3dab752cfc59 /]# |
现在我们已经在容器内,我们看一下映射的沙盒目录:
1 2 3 4 5 |
[root@3dab752cfc59 /]# ll /mnt/mesos/sandbox/ total 8 drwxr-xr-x. 2 root root 15 Feb 10 07:29 my_volumes -rw-r--r--. 1 root root 1541 Feb 10 07:27 stderr -rw-r--r--. 1 root root 1315 Feb 10 07:27 stdout |
我们的数据卷果然映射到容器里了,那么这个my_volumes数据卷是否也通过docker的文件映射功能关联到/var/lib/mysql目录呢?
1 2 |
[root@3dab752cfc59 /]#ll /var/lib/mysql// total 0 |
的确存在这个目录,现在我们模拟mysql向/var/lib/mysql中写入一个文件,看看数据卷怎么变化:
1 2 3 |
[root@3dab752cfc59 /]# echo hello > /var/lib/mysql/my.data [root@3dab752cfc59 /]# cat /mnt/mesos/sandbox/my_volumes/my.data hello |
不出所料,两个目录其实早已关联在一起,挂载的都是宿主机上的数据卷目录,可以再看一下宿主机:
1 2 |
[root@localhost marathon]# cat /root/mesos/agent1/slaves/cb3b9bc3-9d3b-449b-8bf9-f29f2a8e171a-S0/frameworks/0b5532ac-6b06-4231-9c73-35ea41fae403-0000/executors/volumes-app.65319332-ef62-11e6-b51b-02425dc10031/runs/027f9c37-fd61-44be-8ea2-a24c83db95da/my_volumes/my.data hello |
在宿主机中数据也出现了,最后我们让volumes-app重启一下,看看之前的数据是否还在。
1 2 3 4 5 6 7 |
[root@localhost marathon]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 43b8fdc4b96d centos "/bin/sh -c 'while..." 10 seconds ago Up 9 seconds 0.0.0.0:31101->31101/tcp mesos-cb3b9bc3-9d3b-449b-8bf9-f29f2a8e171a-S0.4153f04e-d8fb-4c6e-b393-5e4f4a7787cf [root@localhost marathon]# docker exec -it 43b8fdc4b96d bash [root@43b8fdc4b96d /]# cat /var/lib/mysql/my.data hello |
marathon关于持久数据卷的可以看官方文档。
祝玩的愉快。
如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~

1