marathon基于本地数据卷实现有状态应用部署

接上一篇《体验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文件怎么编写,官方文档看这里,我只讲怎么快速理解。

先下载一个官方示例文件,授予所有用户所有权限:

首先是全局的一个配置项,它的作用是当请求无法与任何一条ACL规则匹配的时候,是否允许其执行:

“permissive”: false

为false则表示不允许继续执行,为true则表示允许执行。

其次就是每一个权限项了,每个权限项下面是一个数组,可以存在多个配置,其中每一个配置都在表达下面这样的含义:

以”register_frameworks注册框架”这个权限项为例,

这个数组内只包含一项,我们看这一项:其中principals内可以配置value或者type,其中value可以是字符串或者字符串数组,它表名value指定的这些用户应该执行这条规则;如果配置type,那么ANY表示任何人都应该执行这条规则,NONE表示没有人可以执行这条规则。

而除了principals之外的key值,是与权限项相关的,每一种都不一样,可以跳转上面的官方文档看一下列表,在下面的例子中用到的register_frameworks权限项的key值叫做roles,其目的是限制principals可否以某role角色来注册framework。

注意:ACLs匹配时遇到第一个匹配项就会终止匹配,因此规则的出现顺序很重要。另外,要理解NONE的意思需要结合permissive来看,具体看个例子:

  • 第一个规则表示: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资源保留机制来使用持久数据卷。

在上一篇博客的脚本基础上,添加了2个参数:

principal和role可以随便起名,确保不要和mesos集群上其他的framework冲突即可,此后重启marathon进入webui配置一个有状态的app吧。

创建centos的docker app

1

假设我要创建的是一个mysql服务,因此只需要配置1个实例,并且希望marathon能持久化mysql的数据,即便其部署所在的机器宕机也不要为我自动的迁移到其他机器,所以需要用到数据卷。

2

我直接用了centos镜像,后面我需要登录到这个容器内去看一下数据卷的情况。

3

这里,我做了2个事情:

  1. 创建一个mesos的持久数据卷,命名目录为my_volumes,大小为100MB。
  2. 让docker容器把这个my_volumes目录映射到容器的/var/lib/mysql目录,这样mysql向/var/lib/mysql写入的数据就会持久化在my_volumes这个数据卷里了。

最后创建app,可以看到这样的配置以及数据卷:

4

5

大概是什么原理呢?其实,mesos-agent在启动一个容器时是会为它准备一个沙箱环境的,简单的理解就是在宿主机上创建一个独一无二目录,并在其中放置一些容器相关的数据,其中数据卷目录就在其中。

我们在宿主机上找出volumes-app对应的mesos-docker-executor进程,它的参数表明了这一切:

关注到其中2个选项:

容器在宿主机上的沙盒目录为/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可以看到我们的数据卷目录坐落在其中:

那么容器中又是什么样呢?因为我们的容器是docker容器,所以可以利用docker连接到容器中:

首先docker ps找到这个容器的ID,然后通过docker exec -it 容器ID bash打开一个连到容器的虚拟终端:

现在我们已经在容器内,我们看一下映射的沙盒目录:

我们的数据卷果然映射到容器里了,那么这个my_volumes数据卷是否也通过docker的文件映射功能关联到/var/lib/mysql目录呢?

的确存在这个目录,现在我们模拟mysql向/var/lib/mysql中写入一个文件,看看数据卷怎么变化:

不出所料,两个目录其实早已关联在一起,挂载的都是宿主机上的数据卷目录,可以再看一下宿主机:

在宿主机中数据也出现了,最后我们让volumes-app重启一下,看看之前的数据是否还在。

marathon关于持久数据卷的可以看官方文档

祝玩的愉快。

如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~