用DCOS和marathon-lb实现服务发现和负载均衡:第一部分

最近在研究使用Mesos,对marathon-lb和mesos-dns等诸多工具,只是停留在知道和会用的阶段,特别是对于基于marathon-lb的HAProxy的应用分组和使用更是一头雾水。现在资料也少,看了官网上的这篇文章觉得讲得还算是全面。兄弟英文水平差,先用Google翻译了一下,然后再梳理整理,同时,加上了一些自己的理解的说明。因为每个人的经历和经验都不同,以下这些东西对于有些人可能很难对于有些人可能很简单,所以不当之处还请大家多多见谅。欢迎讨论和拍砖。


这是服务发现和负载均衡系列的第一部分,共两部分。

Mesosphere Datacenter Operating System (DCOS) 为服务发现和负载均衡提供了有用的工具。其中一个主要的工具就是marathon-lb,这将是本文的重点。

在启动了DCOS集群以后,通过使用Mesos-DNS可以发现所有的task。发现是通过DNS实现的,但是有一些限制,其中包括:
- DNS无法识别服务端口,除非使用SRV查询(SRV记录它是DNS服务器的数据库中支持的一种资源记录的类型,它记录了哪台计算机提供了哪个服务这么一个简单的信息);大多数应用程序都无法使用SRV记录“开箱即用”。
- DNS不具有快速故障转移能力。
- DNS记录有一个TTL(生存时间:time to live),同时Mesos-DNS使用轮询来创建DNS记录; 这可能会导致过时的记录。
- DNS记录不提供任何服务的健康数据。
- 一些应用程序和库不正确地处理多个A记录(handle multiple A records);在某些情况下,查询可能被缓存,并根据需要不正确地重新加载。

注:A记录也称为主机记录,是使用最广泛的DNS记录,A记录的基本作用就是说明一个域名对应的IP是多少,它是域名和IP地址的对应关系,表现形式为:www.xxx.com 192.168.1.1这就是一个A记录!A记录除了进行域名IP对应以外,还有一个高级用法,可以作为低成本的负载均衡的解决方案,比如说:www.xxx.com 可以创建多个A记录,对应多台物理服务器的IP地址,可以实现基本的流量均衡!

为了解决这个问题,我们为Marahon提供一个叫做Marathon Load Balancer的工具,简称marathon-lb.

注:这句话是否意味着:使用Mesos-DNS是有局限,而marathon-lb是可以起到与Mesos-DNS同样作用的,这样的话就不需要使用Mesos-DNS?

marathon-lb是基于HAProxy(一个快速的代理服务器和负载均衡器)的。HAProxy可以为基于TCP和HTTP协议的应用提供代理和负载均衡。支持如SSL,HTTP压缩,健康检查,Lua脚本等功能。marathon-lb会将事件提交至marathon事件总线,同时实时的对HAProxy的配置进行更新和修改。

你可以可以用多种拓扑结构配置marathon-lb。以下是如何使用的marathon-lb的一些例子:

  • 使用marathon-lb做为的边缘负载均衡器(edge load balancer
    LB)和服务发现机制。你可以运行在面向公众的节点marathon-lb路由入口流量。你可以使用的A记录面向公众的节点的IP地址,以供内部或外部DNS记录(根据您的使用情况)。

注:”edge load balancer”,我理解应该是顶级或者入口级的负载均

  • 使用marathon-lb作为内部(internal)LB和服务发现机制,有一个单独的HA负载均衡器作为公共的路由处理。例如,你可以使用预置的外部F5负载均衡器,或者在Amazon
    Web Services的弹性负载均衡。
  • 将marathon-lb严格的作为内部(internal)LB和服务发现机制。
  • 可能还需要使用内(internal)部和外部(external )的LB的组合,为不同的服务提供不同的负载均衡。

在本文中,我们将讨论上述第四个选项,以突出说明marathon-lb的特点。

用DCOS和marathon-lb实现服务发现和负载均衡:第一部分_第1张图片

为了演示marathon-lb,我们将启动一个部署在AWS上的DCOS集群,并运行一个内部和外部负载均衡器。外部负载均衡将用于分发由外部HTTP请求到集群,并且内部的LB将用于内部服务发现和负载平衡。由于我们是在AWS上实现,对外通讯将先做一个ELB配置用来对外暴露“public”代理节点。

如果想跟着一起操作,你可以在AWS上创建自己的集群。合在AWS上使用DCOS社区版Mesosphere不会收取任何费用,但你仍然必须支付的基本情况和相关的AWS费用。

marathon-lb提供可直接安装的包。要安装marathon-lb:

$ dcos package install marathon-lb

注:我是使用mesosphere提供的安装包,在centos7上搭建的mesos环境,然后使用marathon-lb的docker镜像。我觉得阅读本文主要是要了解marathon-lb的使用以及如何规划负载均衡,dcos的安装模式可以忽略。

要验证marathon-lb是否正常工作,根据你搭建的Mesos环境,用Mesos-slave主机的IP,访问http://:9090/haproxy?stats。你会看到这样的统计报表页面:

用DCOS和marathon-lb实现服务发现和负载均衡:第一部分_第2张图片

接下来,我们将建立我们的内部LB。要做到这一点,我们必须先指定marathon-lb中的一些配置选项。创建一个名为options.json包含以下内容:

{
  "marathon-lb":{
    "name":"marathon-lb-internal",
    "haproxy-group":"internal",
    "bind-http-https":false,
    "role":""
  }
}

在这个选项文件,我们需要修改 a)的应用实例的名称,b)HAProxy的组名,同时,我们停用HAProxy端口80和443的HTTP和HTTPS转发(因为它不需要)。

接下来,运行与我们的新选项安装命令:

$ dcos package install --options=options.json marathon-lb

注:在Mesos环境中,可以直接用命令执行,例如:curl -X POST http://mesos-master:8080/v2/apps -d @options.json -H “Content-type: application/json”

现在,我们将有2个负载均衡:一个外部LB和一个内部LB.让我们运行一个示例应用程序来演示功能。下面是我们的nginx的外部实例:

注:
1)以上内容中共安装了两个marathon-lb。第一个是上文中最早安装的,默认安装的marathon-lb,HAPROXY_GROUP值是external的,默认是绑定了80和443端口的。用上面的带options.json参数的命令,又安装了一个marathon-lb,这里面指定HAPROXY_GROUP为internal,同时取消对80和443的绑定。
2)这里的Nginx不是用于负载均衡,这里把Nginx当作一个服务或者一个微服务就行。可能是考虑nginx相对比较小,好配置,所以很多mesos的文章中都是用nginx做示例。

{
  "id": "nginx-external",
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "nginx:1.7.7",
      "network": "BRIDGE",
      "portMappings": [
        { "hostPort": 0, "containerPort": 80, "servicePort": 10000 }
      ],
      "forcePullImage":true
    }
  },
  "instances": 1,
  "cpus": 0.1,
  "mem": 65,
  "healthChecks": [{
      "protocol": "HTTP",
      "path": "/",
      "portIndex": 0,
      "timeoutSeconds": 10,
      "gracePeriodSeconds": 10,
      "intervalSeconds": 2,
      "maxConsecutiveFailures": 10
  }],
  "labels":{
    "HAPROXY_GROUP":"external"
  }
}

您可以通过粘贴上面的JSON到一个文件中(称为发动DCOS这个程序nginx-external.json),并运行:

$ dcos marathon app add nginx-external.json

注:与第一个json说明的运行方式相同,直接用curl来执行。

Application(执行json就会在marathon创建一个application)的定义中,包含了用HAPROXY_GROUP作为Key的特殊标签。这个标签告诉marathon-lb是否对外暴露该应用程序。外部marathon-lb运行时设置–group参数的值为external,这是默认值。你可以在这里检查代码,如果你愿意的话。

下面是我们的内部nginx的:

{
  "id": "nginx-internal",
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "nginx:1.7.7",
      "network": "BRIDGE",
      "portMappings": [
        { "hostPort": 0, "containerPort": 80, "servicePort": 10001 }
      ],
      "forcePullImage":true
    }
  },
  "instances": 1,
  "cpus": 0.1,
  "mem": 65,
  "healthChecks": [{
      "protocol": "HTTP",
      "path": "/",
      "portIndex": 0,
      "timeoutSeconds": 10,
      "gracePeriodSeconds": 10,
      "intervalSeconds": 2,
      "maxConsecutiveFailures": 10
  }],
  "labels":{
    "HAPROXY_GROUP":"internal"
  }
}

请注意,我们指定一个servicePort参数。servicePort端口是该服务(本例中的Ninx)在marathon-lb中的端口。默认情况下,marathon-lb保留从10000至10100的端口,用于对外的服务使用,所以你应该从10000开始使用(如果你数一下,共计101服务端口可以使用)。您可能需要使用电子表格,来跟踪记录这些端口在marathon-lb中的分配和使用情况,以及每个端口是与哪组LB的服务对应。

让我们再添加一个Nginx实例:

{
  "id": "nginx-everywhere",
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "nginx:1.7.7",
      "network": "BRIDGE",
      "portMappings": [
        { "hostPort": 0, "containerPort": 80, "servicePort": 10002 }
      ],
      "forcePullImage":true
    }
  },
  "instances": 1,
  "cpus": 0.1,
  "mem": 65,
  "healthChecks": [{
      "protocol": "HTTP",
      "path": "/",
      "portIndex": 0,
      "timeoutSeconds": 10,
      "gracePeriodSeconds": 10,
      "intervalSeconds": 2,
      "maxConsecutiveFailures": 10
  }],
  "labels":{
    "HAPROXY_GROUP":"external,internal"
  }
}

内外部都可以方案该Nginx实例。请注意,我们已经改变了servicePort端口,因此不会与其他Nginx的情况下重叠。

可以通过使用端口映射来定义服务端口(如在上面的例子),或者在marathon application的定义中增加ports参数。

为了测试我们的配置,用SSH登录到集群中的实例(如主机)之一,并尝试curl-ing端点:

$ curl http://marathon-lb.marathon.mesos:10000/

$ curl http://marathon-lb-internal.marathon.mesos:10001/

$ curl http://marathon-lb.marathon.mesos:10002/

$ curl http://marathon-lb-internal.marathon.mesos:10002/

每一个地址都应该返回Nginx的“欢迎”页面,如下所示:

用DCOS和marathon-lb实现服务发现和负载均衡:第一部分_第3张图片

虚拟主机

marathon-lb的一个重要特点是支持虚拟主机。这可以使您将HTTP通路分发到多个主机(FQDN的),并且将请求路由到正确的endpoint。例如,你可以有两个不同的网络地址,ilovesteak.com和steaknow.com,同时这两个地址的DNS都通过相同的端口指向同一个LB,并且将HAProxy基于域名将通信路由到正确的endpoint。

要测试虚拟主机功能,切换到AWS控制台,查看您的punblic ELB。为了进行测试,我们将对public ELB进行两处修改。

首先,我们将修改健康检查,使用HAProxy的内置的健康检查:

用DCOS和marathon-lb实现服务发现和负载均衡:第一部分_第4张图片

其次,修改健康检查的路径/_haproxy_health_check,让它去ping主机的9090端口。现在,如果你浏览到实例选项卡,您应该看到界面列出状态为InService的实例,就像这样:

用DCOS和marathon-lb实现服务发现和负载均衡:第一部分_第5张图片

现在,我们的ELB能够将流量路由到HAProxy的。接下来,让我们修改nginx的应用程序来暴露我们的服务。要做到这一点,你需要从Description tab页面中找到ELB public DNS的名称。在这个例子中,我的public DNS名字是brenden-j-PublicSl-1LTLKZEH6B2G6-1145355943.us-west-2.elb.amazonaws.com。

现在我将修改外部nginx的应用是这样的:

{
  "id": "nginx-external",
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "nginx:1.7.7",
      "network": "BRIDGE",
      "portMappings": [
        { "hostPort": 0, "containerPort": 80, "servicePort": 10000 }
      ],
      "forcePullImage":true
    }
  },
  "instances": 1,
  "cpus": 0.1,
  "mem": 65,
  "healthChecks": [{
      "protocol": "HTTP",
      "path": "/",
      "portIndex": 0,
      "timeoutSeconds": 10,
      "gracePeriodSeconds": 10,
      "intervalSeconds": 2,
      "maxConsecutiveFailures": 10
  }],
  "labels":{
    "HAPROXY_GROUP":"external",
    "HAPROXY_0_VHOST":"brenden-j-PublicSl-1LTLKZEH6B2G6-1145355943.us-west-2.elb.amazonaws.com"
  }
}

我们已经添加了标签HAPROXY_0_VHOST,它告诉marathon-lb就用虚拟主机的外部负载均衡来暴露Nginx的访问。在labels中,包含0的Key与servicePort定义对应 ,从0开始。如果你有多个servicePort定义,你会遍历它们作为0,1,2,依此类推。

现在,如果你浏览到在浏览器中ELB的公共DNS地址,您应该看到以下内容:

用DCOS和marathon-lb实现服务发现和负载均衡:第一部分_第6张图片

当当!

注:原文是“Ta-da!”,语气词而已,不是当当网

在第二部分中,在这里我们谈论更多marathon-lb的高级功能,以及如何使用HAProxy的实现应用程序autoscaling。

总结

本文更多的是在讲解如何来使用marathon-lb,以及在marathon-lb中,如何对HAProxy进行分组。讲得还是比较浅,特别是没有说明marathon-lb自动增加节点进行负载均衡没有说明。我本人搭的环境中,marathon-lb是可以进行自动负载均衡的,例如:关闭一个Nginx容器,marathon-lb会根据scaling(就是下一部分要说的)的值,自动创建一个Nginx镜像。但是,组合internal和external的情况,还没有成功。等试验成功,再补充进来。


参考资料:
[1]: https://mesosphere.com/blog/2015/12/04/dcos-marathon-lb/
[2]: http://blog.chinaunix.net/uid-23241716-id-134106.html
[3]: http://bbs.51cto.com/thread-909189-1.html

你可能感兴趣的:(Mesos)