使用Kubernetes和Docker进行简单的领导者选举

总览

Kubernetes简化了集群上运行的服务的部署和运营管理。但是,这也简化了这些服务的开发。在本文中,我们将介绍如何使用Kubernetes在分布式应用程序中轻松执行领导者选举。分布式应用程序通常为了可靠性和可伸缩性而复制服务的任务,但是通常有必要将其中一个副本指定为负责所有副本之间协调的领导者。

通常在领导者选举中,会确定一组要成为领导者的候选人。这些候选人都竞相宣布自己为领导人。其中一名候选人获胜并成为领导者。一旦选举获胜,继续领导“心跳”,以更新他们作为领导者的地位,而其他候选人定期做新的尝试,成为佼佼者。如果当前领导者由于某种原因失败,这可以确保快速识别新领导者。

实施领导者选举通常需要部署诸如ZooKeeper,etcd或Consul之类的软件并将其用于达成共识,或者替代地,自行实现共识算法。我们将在下面看到,Kubernetes使在应用程序中使用领导者选举的过程变得非常容易。

在Kubernetes中实施领导人选举

领导者选举的首要要求是确定要成为领导者的候选人集。 Kubernetes已经使用 终点 代表包含服务的一组Pod的复制集,因此我们将重复使用同一对象。 (此外:您可能以为我们会使用 复制控制器,但它们绑定到特定的二进制文件,通常,即使您正在执行滚动更新,您通常也想拥有一个领导者)

为了执行领导者选举,我们使用所有Kubernetes API对象的两个属性:

  • ResourceVersions-每个API对象都有一个唯一的ResourceVersion,您可以使用这些版本在Kubernetes对象上执行比较和交换
  • 注释-每个API对象都可以使用供客户端使用的任意键/值对进行注释。

有了这些原语,使用主选举的代码就相对简单了,您可以找到它 这里。让我们自己运行它。

$ kubectl run leader-elector --image=gcr.io/google_containers/leader-elector:0.4 --replicas=3 -- --election=example

这将创建具有3个副本的领导者选举集:

$ kubectl get pods
NAME                   READY     STATUS    RESTARTS   AGE
leader-elector-inmr1   1/1       Running   0          13s
leader-elector-qkq00   1/1       Running   0          13s
leader-elector-sgwcq   1/1       Running   0          13s

要查看哪个荚被选为领导者,您可以访问其中一个荚的日志,用您自己的荚名称之一代替

${pod_name}, (e.g. leader-elector-inmr1 from the above)

$ kubectl logs -f ${name}
leader is (leader-pod-name)

…或者,您可以直接检查端点对象:

“示例”是上述kubectl run…命令中候选集的名称

$ kubectl get endpoints example -o yaml

现在,要验证领导者选举是否确实有效,请在另一个终端中运行:

$ kubectl delete pods (leader-pod-name)

这将删除现有的领导者。由于Pod集是由复制控制器管理的,因此新Pod会替换已删除的Pod,从而确保复制集的大小仍为3。通过领导者选举,这三个Pod中的一个被选择为新的领导者,您将看到领导者故障转移到另一个Pod。因为Kubernetes中的Pod有一个 宽限期 在终止之前,这可能需要30-40秒。

领导者选举容器提供了一个可以在任何地址(例如http:// localhost:4040)上投放的简单网络服务器。您可以通过删除现有的领导者选举组并创建一个新的选举组来进行测试,在该组中您还将--http =(host):( port)规范传递给领导者选举人图像。这使集合中的每个成员都通过网络挂钩提供有关领导者的信息。

# delete the old leader elector group
$ kubectl delete rc leader-elector

# create the new group, note the --http=localhost:4040 flag
$ kubectl run leader-elector --image=gcr.io/google_containers/leader-elector:0.4 --replicas=3 -- --election=example --http=0.0.0.0:4040

# create a proxy to your Kubernetes api server
$ kubectl proxy

然后,您可以访问:

http:// localhost:8001 / api / v1 / proxy / namespaces / default / pods /(leader-pod-name):4040 /

您将看到:

{"name":"(name-of-leader-here)"}

边车领导选举

好的,那很好,您可以进行领导者选举并通过HTTP找出领导者,但是如何从自己的应用程序中使用它呢?这就是“边车”这一概念出现的地方。在Kubernetes中,“荚”由一个或多个容器组成。通常,这意味着您将sidecar容器添加到主应用程序中以组成Pod。 (有关此主题的更多详细信息,请参阅我之前的博客文章)。

领导者选举容器可以用作边车,您可以在自己的应用程序中使用它。 Pod中任何对当前主控主机感兴趣的容器都可以访问http:// localhost:4040,然后它们将返回一个简单的JSON对象,其中包含当前主控主机的名称。由于Pod中的所有容器共享相同的网络名称空间,因此不需要发现服务!

For example, 这里 is a simple Node.js application that connects to the leader election sidecar and prints out whether 要么 not it is currently the master. The leader election sidecar sets its identifier to hostname by default.

var http = require('http');
// This will hold info about the current master
var master = {};

  // The web handler for our nodejs application
  var handleRequest = function(request, response) {
    response.writeHead(200);
    response.end("Master is " + master.name);
  };

  // A callback that is used for our outgoing client requests to the sidecar
  var cb = function(response) {
    var data = '';
    response.on('data', function(piece) { data = data + piece; });
    response.on('end', function() { master = JSON.parse(data); });
  };

  // Make an async request to the sidecar at http://localhost:4040
  var updateMaster = function() {
    var req = http.get({host: 'localhost', path: '/', port: 4040}, cb);
    req.on('error', function(e) { console.log('problem with request: ' + e.message); });
    req.end();
  };

  / / Set up regular updates
  updateMaster();
  setInterval(updateMaster, 5000);

  // set up the web server
  var www = http.createServer(handleRequest);
  www.listen(8080);

当然,您可以从任何支持HTTP和JSON的语言中使用此工具。

结论

希望我已经向您展示了使用Kubernetes为您的分布式应用程序构建领导者选举有多么容易。在以后的文章中,我们将向您展示Kubernetes如何使构建分布式系统变得更加容易。在此期间,前往 Google容器引擎 要么 kubernetes.io 开始使用Kubernetes。