mesos + marathon集群搭建(2)

本地存储卷

前面示例已经启动了redis镜像,然后为了验证marathon的资源隔离(主要是内存)特性,做了以下尝试:

  1. 将redis容器的内存限制为32M;
  2. 通过脚本循环向redis写入长字符串;
  3. 发现当任务资源监控超过16M的时候,内存占用又会重新清零。

这个过程我们可以知道,将数据写入redis之后,任务监控到redis实例的内存占用在不断增加。然后超过内存限制的一半之后,任务被kill,几秒钟之后marathon重新启动了任务,本地redis客户端重新可用。这里内存超过一半是因为默认redis开启了rdb文件保存(bgsave),redis需要新fork出进程进行rdb文件写入,导致此时虚拟内存翻倍,容器占用的内存超过了cgroup限制,被内核oom kill。我们可以通过内核日志发现一次oom kill的日志。最后marathon虽然重新启动了任务,但是由于docker容器的隔离性,之前写入硬盘的内容(rdb)文件都已经消失,导致内存清零,之前写入的大字符串消失。

如果我们希望redis任务重新启动之后能够保留数据(虽然对于测试场景无效,因为内存不足,如果数据恢复,进程也会立即被内核kill),就需要将容器中的redis工作目录持久化保存。

marathon文档中描述了两种持久化的方式,对于我们来说,最简单的就是使用本地卷进行持久化。本地卷的大致方式是向mesos master申请指定大小的卷,并将该卷和任务容器关联起来(对于docker容器使用volume-from参数关联即可)。

启动redis任务,其中和卷相关的配置为:

"volumes": [
     {
       "containerPath": "/data",
       "hostPath": "redis",
       "mode": "RW"
     },
     {
       "containerPath": "redis",
       "mode": "RW",
       "persistent": {
         "size": 1024
       }
     }
    ]

该配置表示在slave机器上申请名为redis的卷,大小为1024MB,权限为读写。同时设置将主机的redis卷挂载到容器的/data目录中,挂载权限为读写。

提交任务之后,发现使用了本地卷之后的任务一直在unsheduled状态,slave上没有任务分派的数据。查了半天文档也没有好的解释。于是重新按照marathon文档进行了设置,特别关注其中的Prerequisites章节。其中描述了marathon启动参数中必须设置mesos_authentication_principalmesos_role两个参数。但是其中没有太明确描述需要设置什么值。

由于这两个参数主要作为在mesos master执行操作时后的标识,首先先在marathon机器上的/etc/marathon/conf/目录中分别创建mesos_authentication_principal和mesos_role两个文件:

echo 'marathon' > /etc/marathon/conf/mesos_authentication_principal
echo 'marathon' > /etc/marathon/conf/mesos_role

重启marathon服务之后,在任务详情中就可以看见新增的volume标签页。但情况并没有好转,任务长时间处于waiting状态,卷的状态一直为detached。最终在mesos master(leader那台)上找到了一些错误日志:

Dropping RESERVE offer operation from framework … A reserve operation was attempted with no principal, but there is a reserved resource in the request with principal ‘marathon’ set in ReservationInfo

紧接着一条错误:

Dropping CREATE offer operation from framework…Invalid CREATE Operation: Insufficient disk resources

查询了文档之后大概知道,由于principal设置的问题,mesos master没有认可marathon发起的RESERVE指令(既让slave预留一部分资源,这里是硬盘空间),随后由于没有预留足够的硬盘空间,发送的创建指令由于没有剩余空间而失败。

从错误日志基本可以断定是由于principal设置问题导致的,从marathon任务相关文档中,终于了解了mesos master acl相关的配置,,以及这些配置对frameworks的影响。直接抄文档中的acls内容会有问题,因为其中只是指定了run_tasks和register_frameworks两个操作的acl,通过mesos文档,我们可以查阅到mesos master支持的所有acl项。对于我们的需求,需要授权marathon支持reserve_resources操作,最终将acls参数内容更新为:

{
    "run_tasks": [
        {
            "principals": {
                "type": "ANY"
            },
            "users": {
                "type": "ANY"
            }
        }
    ],
    "register_frameworks": [
        {
            "principals": {
                "type": "ANY"
            },
            "roles": {
                "type": "ANY"
            }
        }
    ],
    "reserve_resources": [
        {
            "principals": {
                "type": "ANY"
            },
            "roles": {
                "type": "ANY"
            },
            "resources": {
                "type": "ANY"
            }
        }
    ],
    "unreserve_resources": [
        {
            "principals": {
                "type": "ANY"
            },
            "roles": {
                "type": "ANY"
            },
            "reserver_principals": {
                "type": "ANY"
            }
        }
    ],
    "create_volumes": [
        {
            "principals": {
                "type": "ANY"
            },
            "roles": {
                "type": "ANY"
            }
        }
    ],
    "destroy_volumes": [
        {
            "principals": {
                "type": "ANY"
            },
            "roles": {
                "type": "ANY"
            },
            "creator_principals": {
                "type": "ANY"
            }
        }
    ]
}

这里只是为了能够正常分配,没有做任何访问控制。将上述内容保存到文件(/etc/mesos-acls)然后添加到mesos-master的参数:

echo 'file:///etc/mesos-acls' > /etc/mesos-master/acls

重启所有mesos master,之前一直在waiting状态的任务,已经可以正常申请卷,并启动容器。进入分配到的slave服务器,我们可以看见多了一个挂载点:

/dev/vda1 on /var/lib/mesos/slaves/fb9d0623-c0bf-402e-9288-06206b30ea54-S4/frameworks/487f9562-5998-4cfb-bc92-bbc3a441c69c-0000/executors/redis_single.bd21b767-41b8-11e6-9d7a-024259ae7178/runs/8c9304a1-b960-4aa0-a169-f368a4d77ed9/redis type xfs (rw,relatime,attr2,inode64,noquota)

同时通过docker inspect命令查看redis容器的参数,可以发现其中卷挂载有如下配置:

"Mounts": [
    {
        "Source": "/var/lib/mesos/slaves/fb9d0623-c0bf-402e-9288-06206b30ea54-S4/frameworks/487f9562-5998-4cfb-bc92-bbc3a441c69c-0000/executors/redis_single.bd21b767-41b8-11e6-9d7a-024259ae7178/runs/8c9304a1-b960-4aa0-a169-f368a4d77ed9/redis",
        "Destination": "/data",
        "Mode": "rw",
        "RW": true,
        "Propagation": "rprivate"
    },
    {
        "Source": "/var/lib/mesos/slaves/fb9d0623-c0bf-402e-9288-06206b30ea54-S4/frameworks/487f9562-5998-4cfb-bc92-bbc3a441c69c-0000/executors/redis_single.bd21b767-41b8-11e6-9d7a-024259ae7178/runs/8c9304a1-b960-4aa0-a169-f368a4d77ed9",
        "Destination": "/mnt/mesos/sandbox",
        "Mode": "",
        "RW": true,
        "Propagation": "rprivate"
    }
]

既创建的挂载点已经被挂到容器的指定路径了。

然后我们进行验证:
首先通过redis客户端连接到redis上,然后设置工作路径为我们挂载的路径:

redis-cli -h 1.1.1.1 CONFIG SET dir /data

然后写入数据:

redis-cli -h 1.1.1.1 set a b

为了确保能够正常持久化,执行:

redis-cli -h 1.1.1.1 bgsave

查看挂载卷路径,可以发现已经有dump.rdb文件产生。此时kill掉redis任务,等待marathon重新启动。再次启动之后,通过redis-cli连接进入redis之后,可以看见之前设置的key仍然存在:

> redis-cli -h 1.1.1.1 keys *
1) "a"

然后获取这个key的值:

> redis-cli -h 1.1.1.1 get a
1) "b"

从这个实验可以看出,marathon的本地存储卷可以确保服务重新启动之后原来的数据仍然存在,对于存储类的应用(如redis、mysql等)非常有用。

2 Replies to “mesos + marathon集群搭建(2)”

  1. 你好!我按照你这样设置 marathon 还是waiting状态,在slave,已经看到创建了这个路径
    /var/lib/mesos/volumes/roles/marathon/myadd#data#4c841c60-862f-11e6-8d97-005056a13037

    找不到任何LOG, 求助, QQ515678087

    1. 尝试看下mesos master上有什么分配日志么?平时不上qq,有其他联系方式么?

发表评论

电子邮件地址不会被公开。 必填项已用*标注