分布式协调Kubernet

处理调度Jobs

单一的应用程序,就是以前在单个节点上运行的单个实例,包括了不少在数据库更新状态的调度jobs(如今也一样发布商务events)。单体程序建立在java中,而且大量使用Spring,因此job看起来是这个样子的:html

Spring以后会确认提到过的 doSomethingEveryMinute方法每分钟执行一次。问题是,若是咱们目前不在Kubernetes上主持单体程序,而且跟多个实例一块儿运行,这个job就每分钟会在每一个实例上被执行一次,而不只仅只是每分钟执行了一次而已。若是job有相似发送通知邮件或更新数据库这样的反作用的话,这就是一个问题了。因此咱们要怎样避免这个?固然,解决方案仍是不少的,显而易见的选择就是利用Kubernetes Jobs,让Kubernetes本身周期性调度jobs。问题就是这个做用只在Kubernetes1.3版本及以上版本中可用,可是1.3尚未发布。可是即便咱们可以使用这样一个功能,从技术角度来讲,这也是不太可行的。咱们的jobs被高度耦合到已经存在的代码库,而且提取每一个job到它本身的应用程序,程序可能会有错误,并且若是一次性完成的话会很是耗费时间。因此咱们最初的计划是提取全部的调度jobs到一个应用程序,这个应用程序在Kubernetes中只能做为一个实例来运行。但因为现有代码的本质,和高耦合性,即便是这样也很难实现。那么,有没有一种很轻松的办法容许咱们目前在单体应用中保持jobs,而且当咱们从这个应用中提取功能到独立的服务的时候,逐渐替代他们呢?其实仍是有的。java

Kubernetes中的Leader选举

要解决这个,咱们须要作一些分布式协调,好比,当jobs被Spring执行的时候,若是这个节点不是“leader节点”,为运行调度jobs负责,咱们就只须要传回信息(并且,不要和job一块儿运行代码)。有一些项目可以帮助咱们来处理诸如zookeeper和hazelcast之类的东西。可是仅仅只是为了决定哪一个节点执行调度jobs,以此来设置、保留zookeeper集群就太劳师动众了。咱们须要一些易于管理的东西,假如咱们可以利用Kubernetes会怎么样呢?Kubernetes已经在cover下(使用 RAFT consensus algorithm)处理了leader选举。结果证实,这个功能经过使用gcr.io/google_containers/leader-elector Docker镜像已经被暴露给了终端用户。以前已经有一个很棒的博客帖子很细节地描述过这个是如何运行的了,点击这个网址查看:http://blog.kubernetes.io/2016/01/simple-leader-election-with-Kubernetes.html。因此在这里我就很少加赘述了,可是我会讲一讲咱们是如何利用镜像来解决咱们的问题的。数据库

解决问题

咱们作的就是带来gcr.io/google_containers/leader-elector容器到咱们的pod,这样就可让单体应用的实例都运行一个leader选举的实例。这是证实Kubernetes pod有用的典型例子。服务器

如下是一个在咱们的配置resource中定义好的pod的摘录:分布式

咱们开启leader选举以及咱们的单体应用程序。注意,咱们将 --election=monolith-jobs看成第一个参数。这就意味着leader选举知道容器属于哪个组。因此指定这个组的容器会是leader选举进程中的一部分,这个组之中只有一个容器会被选举为leader。 --http=localhost:4040的第二个参数一样是很是重要的。它在4040端口打开了一个网页服务器,在这个端口,咱们能够查询到目前leader的pod名字,而后以这个格式返回:google

这是咱们决定要不要运行咱们的job的一个小把戏。咱们要作的事情就是检查即将执行调度pod的名字是否跟选举出来的leader一致,若是一致,咱们就应该继续执行,而且执行job,或者其它的咱们应该返回的东西。好比:spa

因此咱们来看看ClusterLeaderService是如何被实施的。首先,咱们必须从应用程序得到pod的名字。Kubernetes将pod名字存储在/etc/hostname ,Java将这个/etc/hostname暴露在HOSTNAME环境变量,这就是咱们将在这个例子中引用的。另外一个方法就是使用 Downward API将pod名字暴露到环境变量选择。好比:htm

从这里,咱们能够看到 metadata.name (也就是pod的名字)会与 MY_POD_NAME环境变量联系在一块儿。可是如今让咱们来看看 ClusterLeaderService的实施是看起来是怎么样的:blog

在这里例子中,咱们正在从 RESTAssured 项目使用 JsonPath来查询选举者网页服务,而且从回应中提取pod的名字。而后咱们简单地将本地容器的名字跟leader相比较,若是他们是相同的,那么咱们就知道这个实例就是leader!就是这样!进程

结论

事实证实,上述工做运行地很不错!若是leader节点要挂掉了,那么另外一个就会自动选举上。但这个过程会花上一点时间,要一分钟左右。因此这个仍是要权衡一下的。假如你的工做中不容许错过任意一个job执行,那么这个选择对你来讲是不合适的。但在咱们上述的例子中,中间有那么一分钟job没有被准确执行,对咱们来讲无伤大雅。因此我以为这个方法十分简单,并且当移植一个现有的包含调度jobs的应用程序的时候颇有价值,由于调度jobs总有各类各样很难提取的缘由。

相关文章
相关标签/搜索