返回 登录
4

将已有应用程序迁移到Mesos上(Part 1)

作者简介:David Greenberg是Two Sigma公司的首席架构师,他负责公司交易战略的分布式计算环境。他也是Cook的设计师,Cook是一个开源的Mesos框架,用来做抢占式作业的调度。

译者简介:崔婧雯,现就职于IBM,高级软件工程师,负责IBM业务流程管理软件的系统测试工作。曾就职于VMware从事桌面虚拟化产品的质量保证工作。对分布式集群管理,虚拟化,业务流程管理都有浓厚的兴趣。

本文节选自《用Mesos框架构建分布式应用》第三章。

本章介绍如何在Mesos上构建应用程序。我们并不是完全从头开始构建,而是一起探讨如何利用已有框架将遗留应用程序迁移到Mesos上。大部分应用程序可以归为两大类:响应请求的应用程序以及在特定时间点完成操作的应用程序。在LAMP技术栈里,这两种组件分别是PHP和cron作业。

本章首先会讲述如何将一个已有的基于HTTP的应用程序从现有基础架构里迁移到Mesos上。要实现这一目的,就需要利用Mesos的扩展性和弹性,最终构建出一个能够从常见故障里自动修复并且恢复的系统。除了改进应用程序本身的弹性,还需要改进应用程序组件之间的隔离性。这样做有助于达到更好的服务质量,而无须费力地直接在虚拟机上构建这些组件。这里将使用Marathon,一个流行的Mesos框架,来托管基于HTTP的应用程序。

之后,会以Chronos作为学习案例,介绍如何使用Marathon为其他框架添加高可用和高可靠性。Chronos让用户可以按照指定的间隔时间运行程序——可以用它计划设定每隔15分钟就启动一次夜间数据生成作业或者报告。之后我们还会介绍一些建议,关于如何高效且可维护地使用Chronos。

最后简单介绍Marathon的一些替代方案,Singularity和Aurora,它们分别由HubSpot和Twitter公司开发。

将Web应用程序迁移到Mesos上


几乎每个公司都会有web应用程序。但是,无论是用Ruby on Rails、Scala Play!还是Python的Flask编写,保证这些web应用程序的部署可靠,可扩展,并且可用性高,这一直都是一个巨大的挑战。本节会介绍Marathon——一个由Mesosphere开发的很易用的平台即服务(PaaS)产品——及其如何和其他工具集成,比如HAProxy。通过这样的学习,可以体会到之前所述架构的优势所在:

  1. 所有后台进程都能够运行在任意机器上,Mesos框架会在后台已有实例失败时,自动启动新实例。
  2. 在完全不同的容器内托管静态资产、快速响应的端点、危险端点(这里指的是该端口可能会在数据库上运行查询,或者构造一个外部服务调用,而用户无法预测该调用的完成需要多长时间,或者是否会无限制地消费资源),以及API,来改进隔离性。
  3. 更容易部署新版本或者回滚,在几秒钟之内就可以完成。
  4. 会将所有这些整合在一起,允许应用程序基于需求自动扩展。

本质上,Marathon允许用户指定命令行或者Docker镜像、CPU个数、内存总量,以及实例数,并且它会使用请求的CPU和内存数量,在容器内启动该命令行或者镜像的指定数量的实例。本节会研究这些基础配置,并且学习Marathon和负载均衡器集成的几种方式,从而将服务暴露给内部和外部世界。

搭建Marathon

显然,要使用Marathon,需要先下载。Mesosphere网站上有为Ubuntu、Debian、Red Hat和CentOS预打包的Marathon版本。当然,用户也可以自己构建,从Mesosphere网站上下载最新的tarball,或者从GitHub上克隆下代码。Marathon用Scala编写,因此用户只需要运行sbt assembly就可以完成构建。从这里开始,本书假定已经完成了Marathon的安装。

Marathon是否作为高可用性应用程序运行并不重要。实际上,在高可用配置下运行Marathon所需的所有事情仅仅是确保启动了两个或者三个Marathon实例,并且这些实例共享相同的–zk命令行参数。还必须确保其他参数也一致,比如—master、–framework-name以及侦听HTTP请求的端口,否则就会看到令人困惑的行为。当以这样的模式运行Marathon时,Marathon的所有实例都可以正确地响应请求,并且它们会神奇地同步状态,因此用户完全不需要担心这些。通常通过给Marathon实例指派一个轮询(round-robin)的DNS名称,或者将其放在负载均衡器之后,就可以完成搭建了。表3-1列出了命令行参数相关的更多信息。

表3-1 Marathon部分命令行参数

参数 功能
–master < instance > Mesos master 的URL。通常格式为zk://host1:port,host2:port,host3:port/mesos
–framework-name < name > 允许用户自定义Mesos 里的Marathon 的实例名称,在有多个 Marathon 实例运行时这很有用
–zk < instance > 保存了Marathon 状态的ZooKeeper 的实例集合。通常格式为 zk://host1:port,host2:port,host3:port/marathon
–https-port < port > 启用Marathon 的HTTPS 访问。细节详见下面文字。

保护Marathon 和Chronos

这里介绍如何通过在改动Marathon 和Chronos 之前强制要求认证来保护Marathon和Chronos,并且确保所有API 通信都受SSL 保护。虽然很多公司都是在其受信网络里运行Marathon 和Chronos,但还是有一些公司需要应用访问限制来确保只有授权用户才能查看或者更改运行着的作业。注意这并不会保护Marathon或Chronos 和Mesos 之间的连接, 要达到这个目的, 用户需要为所选择的Mesos 用户认证方案配置–mesos_authentication_principal 和–mesos_authentication_secret_file。这样做能够有效地防止有人不小心删除或者改变生产环境上至关重要的服务,也能防御想进行恶意破坏的员工。

所有这些安全设置都可以通过环境变量或者命令行参数配置。最好使用环境变量,因为任何登录运行着Marathon 或Chronos 机器的人都可以通过运行ps -f 看到命令行参数里的密码。让启动应用程序的脚本在启动之前export 所有敏感的环境变量,这样可以保护环境变量。同时设置启动器脚本的权限控制,让机器的大部分用户不可读,从而保护所使用的密码。

Chronos 和Marathon 都是基于相同的名为Chaos 的HTTP/REST 服务库而构建。Chaos 目前仅仅支持HTTP 基础认证, 即用户名/ 密码认证。要设置username:password,用户需要遵守这样的格式(由冒号分隔)。可以通过如下参数将其传递给命令行:

--ssl_keystore_password password

或者通过环境变量:

MESOSPHERE_KEYSTORE_PASS=password

这时,你很可能会问:“为什么Java 总是想以不同的方式完成每件事情呢?为什么它不能直接兼容常规证书呢?”幸运的是,将标准PEM 格式的PKCS12 证书(这是大多数证书发行机构使用的类型)转换成keystore 很容易。要达到这一目的,用户需要key(mykey.pem)和证书(mycert.pem)。首先,运行如下命令生成一个组合文件(mykeycert.pem):

cat mykey.pem mycert.pem > mykeycert.pem

然后,使用openssl 创建包含证书的keystore(mykeystore.pkcs12)。很奇怪的是,keystore 要求其存储的所有证书都要有“别名”。本书的证书别名为myalias。最终命令如下:

openssl pkcs12 -export -in mykeycert.pem -out mykeystore.pkcs12 \
-name myalias -noiter -nomaciter

成功啦!现在就可以使用任何标准颁发的证书来保护Marathon 和Chronos 了。

完成上述配置之后,一定要确保禁用HTTP 访问,否则就相当于在前门上锁,但是后门敞开了!可以通过命令行参数–disable_http 禁用Marathon 和Chronos的HTTP 访问。

使用Marathon

Marathon 完全通过其HTTP API 来控制。当Marathon 运行着时,让我们尝试启动一个应用程序。

这里会运行一个简单的应用程序:著名的Python SimpleHTTPServer。这一应用程序在启动时会简单暴露其目录下的文件。本书示例以此为基础,因为几乎所有人都安装了Python,并且默认可用。

如果在你的机器上运行如下命令:

python -m SimpleHTTPServer 8000

那么在浏览器里打开localhost:8000,就能够看到启动服务器的目录下的文件列表。一起看看如何在运行在marathon.example.com:8080的Marathon服务器上运行这一应用程序。首先构造一个文件,包含示例3-1中所示的Marathon应用程序的JSON描述符。

示例3-1 SimpleHTTPServer JSON描述符

{
    "cmd": "python -m SimpleHTTPServer 31500",
    "cpus": 0.5, 
    "mem": 50, 
    "instances": 1, 
    "id": "my-first-app",
    "ports": [31500], 
    "requirePorts": true
}
  • “cmd”指定将要启动应用程序的命令行。
  • “cpus”指定应用程序容器应该占用的CPU数。该数值可以是分数。
  • “mem”指定应用程序容器应该占用的内存MB数。
  • “instances”指定在集群里应该启动的应用程序拷贝数。本演示中,仅仅生成一个实例,但是典型的应用程序可以生成2到2000个实例。
  • “id”是将来通过API如何指代该应用程序。对于每个应用程序而言该值必须唯一。
  • “ports”是应用程序要求的端口数组。本例只需要一个端口。之后会讲解如何动态分配和绑定到端口。
  • 因为显式指定想要分配的端口,所以必须告诉Marathon,否则它会默认使用自动端口分配。

现在假定上述数据已经存储在名为my-first-app.json的文件里。为了启动应用程序,使用HTTP POST将数据发送给运行在marathon.example.com:8080的Marathon服务器:

curl -X POST -H 'Content-Type: application/json' \
    marathon.example.com:8080/v2/apps --data @my-first-app.json

会得到类似如下的响应:

    {
        // This section contains parameters we specified
        "id" : "/my-first-app",
        "instances" : 1,
        "cmd" : "python -m SimpleHTTPServer 31500",
        "ports" : [ 31500 ],
        "requirePorts": true,
        "mem" : 50,
        "cpus" : 0.5,
        // This section contains parameters with their automatically assigned values
        "backoffFactor" : 1.15,
        "maxLaunchDelaySeconds" : 3600,
        "upgradeStrategy" : {
            "minimumHealthCapacity" : 1,
            "maximumOverCapacity" : 1
        },
        "version" : "2015-06-04T18:26:18.834Z",
        "deployments" : [
            {
                "id" : "54e5fdf8-8a81-4f95-805f-b9ecc9293095"
            }
        ],
        "backoffSeconds" : 1,
        "disk" : 0,
        "tasksRunning" : 0,
        "tasksHealthy" : 0,
        "tasks" : [],
        "tasksStaged" : 0,
        // This section contains unspecified parameters
        "executor" : "",
        "storeUrls" : [],
        "dependencies" : [],
        "args" : null,
        "healthChecks" : [],
        "uris" : [],
        "env" : {},
        "tasksUnhealthy" : 0,
        "user" : null,
        "requirePorts" : true,
        "container" : null,
        "constraints" : [],
        "labels" : {},
    }

这表明应用程序已经正常启动了。

查询my-first-app(这个应用程序的名称)相关的信息,就可以得到这个运行着的应用程序的所有信息:

curl marathon.example.com:8080/v2/apps/my-first-app | python -m json.tool

该查询返回的数据和创建应用程序返回的数据几乎完全一致。不同之处在于这里应用程序已经开始运行了一段时间,因此可以看到运行任务相关的信息如下:

    // ... snip (same as before) ...
        "tasks": [
            {
                "appId": "/my-first-app",
                "host": "10.141.141.10",
                "id": "my-first-app.7345b7b5-0ae7-11e5-b3a7-56847afe9799",
                "ports": [ 31500 ], 
                "stagedAt": "2015-06-04T18:28:09.235Z",
                "startedAt": "2015-06-04T18:28:09.404Z",
                "version": "2015-06-04T18:28:05.214Z"
            }
        ],
        "tasksHealthy" : 1, 
    // ... snip (same as before) ...
  • 该值告诉用户运行该任务的主机的DNS名称和IP地址。
  • 任务的id是一个Mesos结构。可以使用Mesos master的UI来检查任务,比如,可以查看其stdout和stderr。
  • 是否选择应用程序运行的端口,或者允许Marathon代替用户做出选择(细节见示例3-2),可以找到任务实际预留的端口。
  • 任务的staging时间是将该任务提交给某个Mesos offer的时间。
  • 任务的开始时间是Mesos实际启动任务的时间。
  • 每次更新Marathon描述符时,都会标记成一个新版本(见最初POST的响应)。每个任务都会在其注释里标明启动版本。
  • 这里给出了应用程序里当前健康任务的数量概览。

可以进一步查看一些应用程序相关的更为丰富的信息。首先,可以看到创建应用程序时指定的所有配置参数。还可以看到很多其他设置,其中大部分本书都会介绍。还有一个很有意思的字段是“tasks”,是应用程序的所有实际运行实例的数组。每个任务都表示为JSON对象,带有一些有用的字段:

  • “host”和“ports”是分配给任务的实际主机和端口。这些字段是了解应用程序实际上在哪里运行的关键,从而用户可以连接上去。
  • “id”是Mesos TaskID。将每个任务唯一的UUID添加到应用程序ID上而构造出来的,从而可以通过Mesos UI里的Mesos CLI工具很便捷地实现定位。
  • “stagedAt”和“startedAt”告诉用户什么时候任务上发生了生命周期事件。一旦Marathon实际请求Mesos在特定offer上启动任务,任务就变成staged;一旦任务开始运行就变成started。

Marathon REST API即将发生的改动:本书的REST API示例基于Marathon 0.9版本。将来,Marathon会对结果进行过滤,这样请求就无须返回兆比特的JSON数据。当这一功能实现时,用户需要制定额外的可重复的URL参数embed。也就是说,它会取代现在的/v2/apps/my-first-app,变为使用请求/v2/apps/my-first-app?embed=app.counts&embed=app.tasks来获得上述示例的数据。Marathon REST API文档里介绍了embed的所有参数。

通常,用户不想硬编码应用程序的端口:毕竟,如果这么做了,那么每个slave上就只能运行该应用程序的一个实例。Marathon可以替用户指定端口:将应用程序所要求的端口简单设置为0,并且将分配的端口记录在环境变量$PORT0、$PORT1等里。利用这一功能改动之前的配置,就会如示例3-2所示。

示例3-2 SimpleHTTPServer JSON描述符,使用动态选择的端口

{
    "cmd": "./python -m SimpleHTTPServer $PORT0",
    "cpus": 0.5,
    "mem": 50,
    "instances": 1,
    "id": "my-first-app",
    "ports": [0], 
    "uris": [
        "http://fetchable/uri/with/python.tar.gz"
    ]
}
  • 注意使用$PORT0访问环境变量,其包含分配给“ports”数组的首个索引的端口。
  • 设置所需端口为0,意味着让Marathon做选择。
  • 还提供待获取的URI列表,在运行命令行之前解压缩到容器内。支持的URI命名方案详见“配置进程环境”部分。

一些想要运行在Marathon上的应用程序不接受命令行传入的端口。不用担心!用户可以很容易地将$ PORT 0环境变量传递进配置文件。假定应用程序配置文件设置为和应用程序一起下载的URL。现在,想要使用sed将配置文件里的某个特定字符串替换为必需的环境变量,可能是$ PORT 0或者$ MESOS_DIRECTORY:

sed -e 's#@MESOSDIR@#'"$MESOS_DIRECTORY"'#' config.templ > config
sed -e 's#@PORT@#'"$PORT0"'#' config2.templ > config2
  • 这里将字符串@MESOSDIR@替换为任务的沙箱目录。将配置文件里的字符串用@符号包围,因为@符号几乎不会出现在配置语言里(当然,其实可以使用任意的特别字符串)。另外,在sed命令行里使用单引号包含“常量”,用双引号包含环境变量,从而确保shell能够正确执行该命令。最后,在sed命令里使用#代替/,这样就可以成功放置本身包含斜杠的环境变量。
  • 这里将索引为0的端口放置到配置文件里。实际如果想在一个配置文件里放置多个变量,可以向sed传递多个-e参数。

之后介绍使用这些变量的特性时会再介绍其他字段。

扩展应用程序

本节探讨如何将HTTP服务器扩展到五个实例。准备好了吗?

curl -X PUT -H 'Content-Type: application/json' \
        marathon.example.com:8080/v2/apps --data '{"instances": 5}'

当然,没有人会真的需要将这个没什么用的应用程序启动五个实例,因此为什么不缩小实例数呢?

curl -X PUT -H 'Content-Type: application/json' \
        marathon.example.com:8080/v2/apps --data '{"instances": 1}'

真幸运,伸缩相当容易!

使用位置约束

Marathon可以约束在何处启动应用程序。这些约束可以是slave的主机名或者任意slave属性。约束放在数组里提供给应用程序,每个约束本身是包含两个或三个元素的数组,取决于是否需要传入参数。下面是可用的约束及其使用方法:

GROUP_BY

该运算符确保应用程序的实例在带有特定属性的节点上均匀分布。可以借助该值在主机或者机架(假定机架信息记录在slave的rack属性里,示例3-4)间均匀分发应用程序(见示例3-3)。

示例3-3 主机间均匀分布

    {
        // ... snip ...
        "constraints": [["hostname", "GROUP_BY"]]
    }

示例3-4 机架间均匀分布

    {
        // ... snip ...
        "constraints": [["rack", "GROUP_BY"]]
    }

UNIQUE

该运算符确保应用程序的每个实例都运行在UNIQUE约束值不相同的机器上。该值类似于GROUP_BY,除了一点:当缺少足够的具有不同该属性值的机器时,应用程序的完整部署就会失败,而不会在某些slave上运行多个实例。通常,GROUP_BY是保证可用性的最佳方案,因为其通常优先在单台slave上运行多个任务。示例3-5展示如何使用UNIQUE确保集群内的每个slave上不会有多于一个实例运行。

示例3-5 每台主机上最多运行一个实例

    {
        // ... snip ...
        "constraints": [["hostname", "UNIQUE"]]
    }

CLUSTER

该运算符允许用户仅仅在某个属性值为特定值的slave上运行应用程序。如果某个slave带有特别的硬件配置,或者如果用户想限制应用程序在某个机架上执行,这时该运算符就很有用。但是,LIKE更强大,并且通常更实用。比如,假定用户的数据中心是ARM和x86处理器的混合,并且在slave上设置了属性cpu_arch来帮助区分机器的架构。示例3-6展示如何确保仅仅在x86处理器的机器上运行应用程序。

示例3-6 仅仅运行在x86上

    {
        // ... snip ...
        "constraints": [["cpu_arch", "CLUSTER", "x86"]]
    }

注意CLUSTER运算符带了一个参数。

LIKE

该运算符确保应用程序仅仅运行在拥有某个特定属性的slave上,并且该属性值能够匹配所提供的正则表达式。该运算符的使用方法和CLUSTER类似,但是更为灵活,因为它能够匹配很多值。比如,假定集群运行在Amazon上,并且所有slave设置了instance_type属性。示例3-7展示了如何限制应用程序仅仅运行在最大的C4计算优化的机器上。

示例3-7 仅仅运行在c4.4xlarge和c4.8xlarge机器上

    {
        // ... snip ...
        "constraints": [["cpu_arch", "LIKE", "c4.[48]xlarge"]]
    }

LIKE的参数是正则表达式。

UNLIKE

UNLIKE是LIKE的补充:它帮助避免在某些特定的slave上运行。可能用户不想在DMZ内的机器上运行后台程序(比如处理用户海量信息的程序),因为DMZ处在不受保护的网络区域。在DMZ内的机器上将dmz属性设置为true,就可以避免在这些机器上运行应用程序,如示例3-8所示。

示例3-8 不在DMZ内运行

    {
        // ... snip ...
        "constraints": [["dmz", "UNLIKE", "true"]]
    }

UNLIKE的参数也可以是正则表达式。

位置约束还可以进行组合。比如,确保应用程序不在DMZ内运行,并且在其他机器上均匀分布,如示例3-9所示。

示例3-9 组合的约束

    {
        // ... snip ...
        "constraints": [["dmz", "UNLIKE", "true"],
                    ["hostname", "GROUP_BY"]]
    }

组合约束帮助用户精确控制应用程序在集群内的运行位置。

运行容器化的应用程序

Marathon很好地支持了Docker容器。如果应用程序已经容器化了,就很容易在Marathon上运行。

为了支持Docker,首先需要确保Mesos集群已经启用了Docker支持。要达到这一目的,需要确保已经启用Docker容器机,并且增加执行器的超时时间(详见“使用Docker”部分)。

本节仅仅在配置应用程序的JSON里添加Docker配置。示例3-10展示了使用Docker时用户可用的参数。注意该JSON配置文件只是完整文件的一部分,完整配置必须包含示例3-1所示的参数。

示例3-10 Marathon Docker JSON配置

{
    // ... snip ...
    "container": {
        "type": "DOCKER",
        "docker": {
            "image": "group/image",
            "network": "HOST"
        }
    }
}
  • 因为Mesos会继续添加新的容器类型,比如Rocket或KVM容器,所以大部分容器配置并非特定于Docker的。该示例里必须提供Docker特定的配置,因为这里用的是Docker容器。
  • 这是最重要的部分:指定容器镜像在哪里。(如果想要使用私有Docker存储库,可以在应用程序描述符里将.dockercfg添加到“uris”字段,详情见“使用Docker”小节的注释“高级Docker配置”。)
  • 将在主机网络模式下运行Docker,Docker会直接使用slave的网络资源。

一旦Docker容器启动了,它就能访问Mesos沙箱目录,该目录存储在环境变量$MESOS_SANDBOX里。

挂载主机卷

使用Docker时,用户通常需要挂载一些主机上可用的卷,可能是一些全局性分布式配置文件、数据文件,也可能是不会被自动垃圾回收的数据目录。示例3-11展示了如何将这些卷添加到JSON配置里。

示例3-11 Mount主机卷

{
    "container": {
        "type": "DOCKER",
        "docker": {
            "image": "group/image",
            "network": "HOST"
        },
        "volumes": [
            {
                "containerPath": "/var/hostlib",
                "hostPath": "/usr/lib",
                "mode": "RO"
            },
            {
                "containerPath": "/var/scratch",
                "hostPath": "/mount/ssd",
                "mode": "RW"
            }
        ]
    }
}
  • 注意“volumes”并不是Docker特有的,并且这里可以指定一个数组。
  • 卷允许用户从Docker容器内访问宿主机器的/usr/lib目录。这在用户想要访问主机的libmesos.so时很有用,就无须持续更新Docker镜像了。
  • 可以以只读(RO)或者只写(RW)模式挂载卷。
  • 该卷给了用户一些SSD挂载的空白空间,假定该SSD挂载在主机的/mount/ssd上。

将主机卷挂载到Docker容器内似乎是在Marathon上托管数据库的一种好方法,这样,可以向容器提供持久化的主机存储。不过,即使可以向Docker上挂载卷,这么做其实也很困难(至少,只有等到Mesos原生支持卷时情况可能才会有所改善)。首先,沟通哪台机器有可用磁盘这件事就十分枯燥。为了达到这一目的,需要使用位置约束来确保如下几个方面:

  1. 有空闲卷的每个slave需要设置特别的属性,表明其有空白卷,这样才可以使用CLUSTER运算符来确保使用这些slave。
  2. 应用程序的UNIQUE运算符设置为主机名,这样每台slave上仅仅会启动应用程序的一个实例(因为每台机器仅有一个特定的加载点)。
  3. 每个slave的主机卷加载在相同路径上(很幸运的是,这是最容易办到的)。

如果能够完成上述任务,那么就能够在Marathon上运行某种类型的数据库。但是不幸的是,无法支持扩展或者自动恢复,因为每个slave上有太多必需的特别配置要求。不过,随着Mesos对持久化磁盘支持的完善,会涌现出越来越多的处理启动和配置数据库的专业框架,也许不久之后这里的困难就不复存在了。

健康检查

Marathon会持续跟踪应用程序是否健康。通过REST API暴露这些信息,从而可以很容易地使用Marathon中央化管理所有应用程序的健康检查。当用户查询REST API意图得到特定应用程序的信息时,其所有任务都会包含最新的健康检查结果。默认来说,Marathon假定处于RUNNING状态的任务是健康的。当然,某个应用程序已经开始执行并不意味着它实际上就是健康的。为了改进应用程序的无效健康数据,用户可以指定任务必须满足的三种额外类型的健康检查:基于命令、HTTP和TCP。

示例3-12 常见健康检查字段

{
    "gracePeriodSeconds": 300, 
    "intervalSeconds": 60, 
    "maxConsecutiveFailures": 3, 
    "timeoutSeconds": 30
}
  • 该宽限期是任务启动自身所需花费的给定时间。在这段时间用完之前,不会运行针对该任务的健康检查。该参数是可选的,默认值是5分钟的宽限期。
  • 间隔是两次健康检查运行之间的时间。该参数是可选的,默认值是每次检查间隔1分钟。
  • 连续失败的最大次数,决定多少次失败的健康检查之后Marathon会强制“杀死”该任务,从而让这个任务能在其他地方重启。如果该值设置为0,那么健康检查的失败永远都不会导致“杀死”任务。该参数是可选的,默认三次健康检查失败后任务就会被“杀死”。
  • 有时候,健康检查可能会挂起。Marathon并不会简单地忽略这次检查,而是当检查在这里给定的秒数之内没有完成时,Marathon会认定缓慢或者挂起的健康检查失败了。该参数是可选的,默认健康检查的运行时间为20秒。

本节介绍健康检查三种类型之中的两种:HTTP和TCP。命令式健康检查还相对比较新,并且因为它有一些限制,所以建议等一段时间该功能更为稳定之后再使用。不过要记住,这里的HTTP和TCP健康检查目前是由Marathon master执行的,这意味着它们还无法扩展到上千的任务里。(Mesos以后的版本里会增加横向扩展的功能。可以点击此处查看MESOS-2533和MESOS-3567,看到是否已经添加这些特性。)

HTTP检查

HTTP健康检查验证在某个特定的路由发送GET请求是否会得到成功的HTTP状态码。成功状态码可以是真的成功,或者重定向。因此,响应码必须在200-399的范围内,包含200和399。要配置HTTP健康检查,需要两个必需字段和一个可选字段,如示例3-13所示。

示例3-13 HTTP健康检查字段

{
    "protocol": "HTTP",
    "path": "/healthcheck",
    "portIndex": 0
}
  • 必须在“protocol”字段指定这是一次HTTP健康检查。
  • 必须指定健康检查的路径。本示例尝试向http://myserver.example.com:8888/healthcheck发送GET请求,这里myserver.example.com:8888是Marathon在其上启动任务的主机和端口。
  • 可以为健康检查选择性指定“portIndex”。默认端口索引为0。

为什么健康检查使用“portIndex”而不是“port”?可能大家会很困惑健康检查规范里的“portIndex”是什么,为什么不简单指定实际端口呢。记住Marathon能够(最佳实践也是这么推荐的)选择应用程序所绑定的端口。所以,用户在配置健康检查时实际并不知道应用程序会运行在哪个端口上。但是应用程序使用的所有端口都指定在应用程序描述符的“ports”数组里。因此,用户可以简单指定“ports”数组里的哪个索引对应为想要在其上运行健康检查的端口!

TCP检查

TCP健康检查验证是否能够成功开启TCP链接到任务上。它们并不发送或者接受任何数据,而只是简单尝试开启socket。要配置TCP健康检查,需要配置一个必需字段和一个可选字段,如示例3-14所示。

示例3-14 TCP健康检查字段

{
    "protocol": "TCP",
    "portIndex": 0
}
  • 必须在“protocol”字段指定这是一次TCP健康检查。
  • 可以为健康检查选择性地指定“portIndex”。默认的端口索引为0。

应用版本化和滚动升级

如果分布式可扩展的PaaS不能滚动升级,它还有什么用呢?一次升级指的是修改应用程序的任意时间点,通常通过发送PUT请求到Marathon上的/v2/apps/$appid处来完成升级。每次升级都会创建一个新版本,由升级所发生的时间戳命名。当查询REST API得到应用程序信息时,每个任务都会告知正在运行的是哪个版本。用户可以在Marathon的/v2/apps/$appid/versions路径处查询有哪些版本可用,还可以从/v2/apps/$appid/versions/$version路径得到该版本的详细信息。示例3-15展示了如何配置应用程序的升级行为。

示例3-15 应用程序升级

{
    "upgradeStrategy": {
        "minimumHealthCapacity": 0.5,
        "maximumOverCapacity": 0.1
    }
}

使用Marathon,用户可以通过应用程序描述符的“minimumHealthCapacity”字段,指定在升级中有多少应用程序需要保持可用。“minimumHealthCapacity”可以设置为0到1之间的任何值。

如果设置为0,当部署新版本的Marathon时,会首先“杀死”所有旧任务,然后启动新任务。

如果设置为0.6,当部署新版本的Marathon时,会首先“杀死”40%的旧任务,然后启动60%的新任务,然后“杀死”剩余的旧任务并且启动剩余的新任务。

如果设置为1,当部署新版本的Marathon时,会首先启动所有新任务(这时应用程序使用的资源可能是常规运营时的两倍),然后关闭旧任务。

“maximumOverCapacity”设置提供了额外级别的安全性,这样应用程序不会在升级中瞬时消耗太多的资源。“maximumOverCapacity”可以设置为0到1之间的任何值。

如果设置为0,当部署新版本的Marathon时,不会启动比实例的目标数量多的任务。

如果设置为0.6,当部署新版本的Marathon时,永远不会超过实例目标数量的160%。

如果设置为1,当部署新版本的Marathon时,则会允许在“杀死”任何旧任务之前就启动所有新任务。

事件总线

当使用Marathon构建应用程序时,用户通常希望在各种事件发生时接收到通知,比如当某个应用程序有了新的部署,或者当其扩容或缩容时。这些通知能够随后用于重新配置代理和路由,日志分析,并且生成报告。Marathon有个内建特性,能够自动将所有内部事件POST到给定URI处。要使用该特性,仅仅需要向Marathon提供两个额外的命令行参数:

--event_subscriber

该参数必须传入值http_callback,才能启用该子系统。现在还不支持其他方案。

--http_endpoints

该参数是由逗号分隔的向其发送JSON格式事件的目标URI列表。比如,有效参数类似于http://host1/foo,http://host2/bar

本文下半部分请点击:将已有应用程序迁移到Mesos上(Part 2)

图片描述

《用Mesos框架构建分布式应用》


由CSDN主办的中国云计算技术大会(CCTC 2017)将于5月18-19日在北京召开,Spark、Container、区块链、大数据四大主题峰会震撼袭来,包括Mesosphere CTO Tobi Knaup,Rancher labs 创始人梁胜、Databricks 工程师 Spark commiter 范文臣等近60位技术大牛齐聚京城,为云计算、大数据以及人工智能领域开发者带来一场技术的盛大Party。现在报名,只需599元就可以聆听近60场的顶级技术专家分享,还等什么,登陆官网(http://cctc.csdn.net/),赶快报名吧!

图片描述

评论