Docker、Mesos和Marathon剖析以及入门实战

本文讲的是Docker、Mesos和Marathon剖析以及入门实战【编者的话】国外广为流传的一个比喻是:在传统服务模式下,可以想象服务器就是IT的宠物(Pets),给它们取名字,并精心抚养长大,当它们生病了,你得为他它们治病。而在新形态的应用服务模型中,虚拟机被看做是农场中的公牛,名字通常都是编号,当他们生病了,你就杀掉他,用一头新牛代替。 未来的应用架构应该像对待农场中的公牛一样:对基础架构的“保养”、保护基础架构的各种功能,比起云计算型应用模式可能会逐渐变得越来越不那么重要。最后作者用比较简洁抽象的方式构建了基于Marathon、Mesos的奶牛模式使用场景。
Docker、Mesos和Marathon剖析以及入门实战

关于宠物和奶牛模式

宠物和奶牛并不是一个新比喻,对素食主义者先说一声抱歉,这种比喻并不是我,而是熊们(bears)总是重复这个比喻。

一般来说,通过SSH进入一台设备并配置,然后给她一个可爱的或者博学的名字----这是宠物模式。如果不幸她死了,病了,或者闪亮红色外表变黑了你会很伤心;

奶牛模式,代表着另外一种批量方式,例如你可以给许多机柜中的某一台设备命名cow_with_big_ram_and_ssd_00003,如果某一个服务死机了,一个替代会自动部署好并且启动。

这种类比可以存在于在云或者公司数据中心中。

现在,许多人们倾向认为奶牛模式更加适合需求。但是事实上,跟大多数人认为相左或者很多人不愿意承认,许多有数据中心或者云平台的商家,里面都是宠物,这是真的,或许他们是虚拟化的,他们仍然是宠物模式的。

深入“非常重要的”服务内部

正如我刚才宣称几乎所有公司仍然在运行许多『宠物』,这是因为sysops(译者注:系统管理员)认为某些服务“非常重要”或者“太核心”。在某些技术超前的公司,这些服务限于Bind、DHCP、Haproxy、ZoopKeeper、etcd;略带讽刺色彩的,在像OpenStack、Hadoop、namenodes等复杂控制框架中,Chef/Puppet服务也被这样认为。如此种种。。。

在Factual,我得承认,我们也有很多类似的情况,这也是为什么我会花很多业余时间来调查我们的倾向,从我们的sysops和工程师团队找到某些原因。从根源上,这种诱惑,或者说陷阱,来自于认为:这些服务如此“核心”, 以至于不能去相信不成熟的带有争议的抽象软件层;同时这些服务如此“重要”,以至于不能与其它耗用RAM、CPU或者IO资源的服务放在同一台设备中。其结局就是变成很多宠物,每个宠物都是一个单点故障,而且系统变得很复杂:最佳情况是记不得每台机器是干什么的;最坏情况是一团混乱。

我们要做的第一件事情就是打破这种复杂性,我们需要为“非宠物化的核心服务”(pet-free core services)设置一些基本规则:
  • 仅把绝对需要的放入“核心服务”
  • 自动部署(相对于需要SSH,敲命令部署模式)
  • 在很多“轻量级设备(beefier machines)”中运行更多服务
  • 跟主机名和物理机无关
  • 跟每种服务RAM和CPU限制隔离
  • 核心服务必须是冗余的

LXC容器,资源管理器和容器管理战争

关于server和DevOps正在进行一场解构性的竞赛,从这点上来说,我认为,目前说“Docker是容器的最佳选择”是安全的。不管是否同意以上说法,大多数人已经开始尝试Docker了,至少目前Docker很火,在大多数场景下适用、实用、独特;因此把服务Docker化会感到安全,而CoreOS Kerfuffles看起来短期内不会改变这种状况。

资源管理的竞争更复杂一些。Hadoop生态环境都已经转移到Yarn上。Yarn不太适合非Hadoop化的环境(non-hadoop-things),而对于传统Hadoop环境(2U设备带12块硬盘)非常有效,尽管不是专用目的,其有效率可以达到将近100%。尽管场景不太一样,但是Hadoop基本会将Mesos或者Kubernetes运行在Yarn上以便更好利用设备资源。

仍然有很多其它服务不需要运行在Hadoop环境上,我喜欢选择Mesos来管理他们。关于这点,我持开放的态度,等待各种批评。但是为什么我要选在Mesos?因为Mesos使用了一种直接的,基于成熟高可用组件ZooKeeper的安装方式,它有大量的用户,成熟的文档,而且我喜欢amplab---尽管这并不是最重要的原因,我后面会解释。

容器管理领域似乎还是硝烟弥漫,Kubernetes有(a Clintonesque inevitability to it),考虑到现状,尤其是Mesosphere提供了另外一种Mesos框架,我们可以合理推断最终会采用Kubernetes。现在,我会演示并且详细记录基于Marathon的实现方式。

这里我表示再次开放接受批评。。。。

但是,事实确实是这样的,如果你对比一下配置文件,大家看起来几乎是一样的-----JSON文件中配置用什么Docker镜像,多少实例,多少CPU、内存,什么端口,服务,以及一些通用“行话”。如我在资源管理器中所说,这些都无关紧要。。。(开放接受批评。。。)好吧,这里我可能过度简化了,但是我会强调Kubernetes配置、Marathon配置和其它类似配置,我觉得如果我可以了解不同,我就可以挑出最好的一个。如果这样,与其等着其中某一个统治这七个王国,我可以主动挑一个,而且如果一旦发现有问题也可以毫无问题的重选。实际上,这种抽象的美妙之处在于他们可以共存而且你可以随时转向一个更好的。

我的论点是:Docker是许多真实配置和提交代码最终运行的地方,没有其它强有力的竞争者。即使突然出现一个,肯定需要方便办法从Docker移植过去。同时,容器管理领域还需要继续演进,这可以接受,我不会等着,而是会主动先去尝试各种选择,来体会带来的好处。

Docker宠物

在此观点被广泛接受前,我还想指出关于Docker的一件事情。

使用Dockerfile来编译Docker镜像是一种目前唯一可行的方法。如果你连接或者SSH到一个细心雕琢的镜像,最后用‘docker push’来创建她,这是一只宠物,一个Docker宠物,在某些地方,他们还是比较麻烦。手动创建镜像?不是吧?但是如果你不能回退20条命令前的配置,或者只能通过改变代码回到基础OS,你又在让Docker等同于一只宠物了。

意识流的终结(END OF MY STREAM OF CONSCIOUSNESS OPINION-FEST)

好吧,前面都是让我做下面这些事情的推动力。接下来,我要做的就是让所有的核心服务都运行在Docker中,而与机器本身配置没有任何关系。一旦我们有了最小一组核心服务,我们可以用一种易于部署和扩展的方式让所有其他服务运转起来,提供一种完全使用设备资源的能力。

开始搭建集群(Finally Building The Cluster)

我们要搭建的集群包括两部分:核心节点和一系列Mesos从服务节点。为了简化,我尽量在示例配置中避免一些问题,但是如果你用于生产,则不能忽略这些。

另外,一些机器配置命令也用命令行方式直接写出来,在实际中,这些命令需要用PXE boot和ansible/chef/puppet等方式。

在所有节点上

假设你已经安装好了vanilla Ubuntu或者其他你愿意的系统。。。。。

激活swap和内存记账(accouting)

sudo sed -i 's/^GRUB_CMDLINE_LINUX=""/GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"/' /etc/default/grub sudo update-grub

添加Docker repo和最新安装包

echo deb https://get.docker.com/ubuntu docker main > /etc/apt/sources.list.d/docker.list apt-get update apt-get install lxc-docker

在核心节点上

为了安装核心节点,我们选择三台相对比较强劲的硬件设备。需要安装的典型服务包括BIND、DHCP、ZooKeeper、Mesos和Marathon。每个服务都要运行在容器中,每个容器都带有合理容量的内存和CPU,关键点在于每种服务都有各自的image和唯一的配置文件(包含主机名,IP,同种服务通过动态环境变量传递),这种方式给核心服务以冗余性,隔离性,可移植性等重要特性。

在配置过程中,BIND和DHCP服务都采用无状态主服务器模式,而不是基于failover策略的主从模式;另外,每个实例都从nginx服务(从一个Git repo上同步)上获得自己的配置,

ZooKeeper

配置数据卷(data volumes)

在每台节点上,运行如下命令:
mkdir -p /disk/ssd/data/zookeeper mkdir -p /disk/ssd/log/zookeeper  docker run -d -v /disk/ssd/data/zookeeper/data:/data --name zookeeper-data boritzio/docker-base true docker run -d -v /disk/ssd/log/zookeeper:/data-log --name zookeeper-data-log boritzio/docker-base true

每个节点上启动ZooKeeper
#this just assigns the zookeeper node id based on our numbering scheme with is machine1x0 -> x+1 MACHINE_NUMBER=`hostname | perl -nle '$_ =~ /(\d+)$/; print (($1+10-100)/10)'` docker run -e ZK_SERVER_ID=$MACHINE_NUMBER --restart=on-failure:10 --name zookeeper -p 2181:2181 -p 2888:2888 -p 3888:3888 -e HOSTNAME=`hostname` -e HOSTS=ops100,ops110,ops120 -m 2g --volumes-from zookeeper-data --volumes-from zookeeper-data-log boritzio/docker-zookeeper

Mesos master

配置数据卷(data volumes)
mkdir -p /disk/ssd/data/mesos/workdir docker run -d -v /disk/ssd/data/mesos/workdir:/workdir --name mesos-workdir boritzio/docker-base true

启动Mesos master
docker run --restart=on-failure:10 --name mesos-master -p 5050:5050 -m 1g -e MESOS_ZK=zk://ops100:2181,ops110:2181,ops120:2181/mesos -e MESOS_CLUSTER=factual-mesosphere -e MESOS_WORK_DIR=/workdir -e MESOS_LOG_DIR=/var/log/mesos/ -e MESOS_QUORUM=2 -e HOSTNAME=`hostname` -e IP=`hostname -i` --volumes-from mesos-workdir boritzio/docker-mesos-master

Marathon

启动Marathon
#use host network for now... docker run --restart=on-failure:10 --net host --name marathon -m 1g -e MARATHON_MASTER=zk://ops100:2181,ops110:2181,ops120:2181/mesos -e MARATHON_ZK=zk://ops100:2181,ops110:2181,ops120:2181/marathon -e HOSTNAME=`hostname` boritzio/docker-marathon

从(slave)节点上
这是我们的“奶牛”设备。实际工作中,需要对他们分配合适的机柜和规则。

添加Mesosphere repo和最新安装包

echo "deb http://repos.mesosphere.io/ubuntu/ trusty main" > /etc/apt/sources.list.d/mesosphere.list apt-key adv --keyserver keyserver.ubuntu.com --recv E56151BF apt-get update && apt-get -y install mesos

set up slave

确保ZooKeeper和Mesos master在slave设备上没有运行:
sudo stop zookeeper echo manual | sudo tee /etc/init/zookeeper.override  sudo stop mesos-master echo manual | sudo tee /etc/init/mesos-master.override

拷贝 ZooKeeper config并设置本地IP地址:
echo "zk://ops100:2181,ops110:2181,ops120:2181/mesos" > /etc/mesos/zk  HOST_IP=`hostname -i` echo $HOST_IP > /etc/mesos-slave/ip  #add docker to the list of containerizers echo 'docker,mesos' > /etc/mesos-slave/containerizers  #this gives it time to pull a large container echo '5mins' > /etc/mesos-slave/executor_registration_timeout  #this gives the mesos slave access to the main storage device (/disk/ssd/) mkdir -p /disk/ssd/mesos-slave-workdir echo '/disk/ssd/mesos-slave-workdir' > /etc/mesos-slave/work_dir  #ok, now we start start mesos-slave

HAPROXY代理
为了使得系统对下层节点真正透明,需要运行一台负载均服务。Marathon中内置一个简单脚本,它会从marathon api中拉(pull)下服务状况,更新HAproxy配置,这点很棒,但是因为marathon的工作模式,每个可访问服务都被分配一个对外的“端口号(service port)”,这些端口号都是HAproxy配置对外发布的。那么问题是,所有服务都想通过80端口发布自己的服务,因此另外一个proxy需要放置在marathon配置的HAproxy之前。
Docker、Mesos和Marathon剖析以及入门实战

为服务和主节点设置简称(ALIASES )
Mesos Master,Marathon和Chronos都有webUI和RESTFul API接口,但是他们运行的多主机方案有些许不同。某些情况下,像Marathon和Chronos,和任何slave主机通讯将被proxy到主服务器;而对于Mesos主服务器,slave服务器上的web应用将会被重定向到主服务器。

期望用户去了解哪台服务器是主服务器,这肯定是不好的用户体验。因此,我们会提供一个可负载均衡的代理服务器,提供简称服务,例如:mesos.mydomain.com,marathon.mydomain.com,或者chronnos.mydomain.com

Haproxy for mesos master

首先我们把mesos.mydomain.cn的DNS指向到Haproxy节点,然后把所有mesos-master节点加到最后。现在有一个技巧,我们想Haproxy只代理发到制定主节点上的请求,为了做到这一点,所有非master节点将会对健康检查请求返回失败。这个方式保证对新选举出来的主服务器,一样可以提供一致性,保证指向最新的master服务器。

这里的技巧是,当查看/master/state.json,主服务器可能有不同的响应,我们查询字符串‘elected time’,这个只从主服务器上返回。
backend mesos   mode http   balance roundrobin   option httpclose   option forwardfor   option httpchk /master/state.json   http-check expect string elected_time   timeout check 10s   server ops100 10.20.6.123:5050 check inter 10s fall 1 rise 3   server ops110 10.20.40.203:5050 check inter 10s fall 1 rise 3   server ops120 10.20.51.2:5050 check inter 10s fall 1 rise 3

以上结果返回两个失败节点和一个健康节点。

Our First Services

在保证我们有足够的基础平台基础上,可以运行剩下的服务。现在主服务起来后,剩下的服务都可以通过现在的框架进行管理。说明一下这点,我们实际上会再Marathon之上运行基于Docker上的Chronos。不仅仅是因为这是说明这点的正确方式,也是正确的运行方式。
LAUNCH SCRIPT
可以通过marathon gem或者只是做一个简单的脚本,例如:
#!/bin/bash  if [ "$#" -ne 1 ]; then         echo "script takes json file as an argument"     exit 1; fi  curl -X POST -H "Content-Type: application/json" marathon.mycompany.com/v2/apps -d@"$@"

启动若干服务器后,marathon UI看起来是这样的:
Docker、Mesos和Marathon剖析以及入门实战

CHRONOS
Chronos本质上是cron-on-mesos,这是一个用来运行基于容器定时任务的Mesos框架,我们将会提供基于Marathon的几个实例。
我们可以用json配置来描述服务。
{   "id": "chronos",   "container": {     "type": "DOCKER",     "docker": {       "image": "boritzio/docker-chronos",       "network": "HOST",       "parameters": [         { "key": "env", "value": "MESOS_ZK=zk://ops100:2181,ops110:2181,ops120:2181/mesos" },         { "key": "env", "value": "CHRONOS_ZK=ops100:2181,ops110:2181,ops120:2181" }       ]     }   },   "instances": 3,   "cpus": 1,   "mem": 1024,   "ports": [4400] 
}
然后我们把json配置贴到marathon API服务器上,
~/launch.sh chronos.json

显示如下:
Docker、Mesos和Marathon剖析以及入门实战

Launch Away!

结果就是这样了。以上方法给我们一个好的思路,针对“太核心”服务,不需要太多妥协,帮助我们设置一个相对“非宠物式环境(pet-free environment)”。当你熟悉这种方法后,有时候尽管临时服务会比较慢,但是从全局看,对所有服务都提供一种更好的环境,特别是当硬盘损坏时。
Gratuitous Promotion-y Stuff
如果你读了所有内容,而且对你看到的有很强的想法,并且想帮助我们提供更加自动和优化devops,可以看看如下链接:包括 : http://www.factual.com/jobs/ow ... neer.
我很少使用tweet,但是大家可以联系我@shimanovsky.

所有代码

在以下连接中我包括了所有自动创建的Dockerfile和Marathon服务配置,希望能够帮助大家了解这篇文章中省略的内容
CORE SERVICES

ZooKeeper

https://github.com/bfs/docker-zookeeper

Mesos Master

https://github.com/bfs/docker-mesos-master

Marathon

https://github.com/bfs/docker-marathon
RUN THESE ON MARATHON

Chronos

https://github.com/bfs/docker-chronos

一些使用Marathon的应用配置

Ruby Web App (Rails or Sinatra) From Github

以下是配置步骤,用来从Github获取代码部署为ruby web应用。我们用它来启动几个内部Sinatra应用。
Docker: https://github.com/bfs/docker-github-rubyapp
Marathon Config: https://gist.github.com/bfs/b34b7e09b0a2360e60e1

Postgresql with Postgis

以下是带Postgisde Postgresql服务,可以用Marathon启动 Docker: https://github.com/bfs/docker-postgis
Marathon Config: https://gist.github.com/bfs/be77416a19bec481b584
–Boris Shimanovsky, VP of Engineering
Discuss this post on Hacker News.
Tweet
Categories: Data, Engineering and Product

原文链接:Docker, Mesos, Marathon, and the End of Pets(翻译:杨峰)

原文发布时间为:2015-07-06
本文作者:hokingyang
本文来自云栖社区合作伙伴DockerOne,了解相关信息可以关注DockerOne。
原文标题:Docker、Mesos和Marathon剖析以及入门实战
上一篇:这可能是市面上最好用的iOS云真机


下一篇:Android 实时视频采集—Cameara预览采集