美文网首页
2018-11-20

2018-11-20

作者: 喵喵唔的老巢 | 来源:发表于2018-11-20 09:31 被阅读0次

    使用Kubernetes和Docker进行简单的leader选举

    Kubernetes简化了运行在集群中的服务部署和运维管理,然而,它也简化了这些管理工作的部署。本篇文章将会展示如何在分布式应用系统中使用Kubernetes来简单地运行leader选举。

    概述

    为了可靠性和伸缩性,分布式系统通常会复制多个服务任务,但往往有必要指定一个副本作为leader负责协调所有的副本。

    通常在leader选举中,一组有机会成为leader的候选者都是可以确认的。这些候选者都竞相宣布自己是leader,其中会有一个候选者脱颖而出成为leader。一旦赢了选举之后,leader将会继续以leader身份发送“心跳”来更新他们的位置。而其它的候选者将会周期性地作出尝试来成为leader,这套机制确保了如果当前的leader由于某些原因失效了,可以快速指定新的leader。

    leader选举的实现通常需要任一一套分布式协调系统比如ZooKeeper、etcd或者Consul,使用它们来取得共识,或者交替实现自己的共识算法。接下来我们将会看到Kubernetes如何使得在应用中进行leader选举明显更容易。

    Kubernetes中leader选举的实现

    leader选举的第一个要求是对于有意成为leader的一组候选者的规范,Kubernetes已经使用了Endpoints来表示一组包含服务的Pods副本,所以我们将重用这个相同的对象(旁白:你可能会认为我们将使用ReplicationControllers,但它们被绑定到一个特定的二进制软件包,即使在执行滚动更新的过程中也通常需要一个leader)。

    执行leader选举将使用Kubernetes API中的两个属性:

    ResourceVersions——每个API都有一个唯一的ResourceVersions,用户可以使用这些版本在Kubernetes对象上执行Compare-and-Swap操作。

    Annotations——每个API都可以被用于客户端的任意键/值对注解。

    鉴于这些原语,使用选主的代码相对简单,可以在这儿找到相关代码,运行如下:

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

    这将会创建一个有三个副本的leader选举组:

    $ 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被选为了leader,用户可以访问Pods的日志,在下面的位置替换为你自己的Pod的名字:

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

    $ kubectl logs -f ${name}

    leader is (leader-pod-name)

    或者,用户可以直接检查Endpoints对象:

    # ‘example’ is the name of the candidate set from the above kubectl run … command

    $ kubectl get endpoints example -o yams

    现在需要验证leader选举是否生效,在另外一个终端中执行:

    $ kubectl delete pods (leader-pod-name)

    这个命令将会删除已有的leader,因为Replication Controller管理Pods组,一个新的Pod将会替换掉已经删除的,从而确保副本数目仍然为3。通过leader选举,这三个Pod中将会有一个被选为leader,并且leader角色还会失效转移到不同的Pod上。因为Kubernetes框架中Pod在终止前会有一个宽限期,通常是持续30~40秒。

    leader选举容器提供了一个简单的Web服务器,可以运行在任何地址上(比如http://localhost:4040),我们可以通过删除一个已有的leader选举组并创建一个新的来测试这个容器,此处可以另外传入一个形如-http=(host):(port) 规格的配置到镜像中,这样就会导致每一个组成员通过Webhook来获得有关leader的服务信息。

    # 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)"}

    leader选举与sidecars

    太好了,现在可以通过HTTP来进行leader选举和找出leader,但怎么能在您自己的应用程序中使用它们呢?这就需要引入Sidecars的概念。在Kubernetes中,Pods由一个或者多个容器组成,通常,这意味着添加sidecars容器到主应用程序中组成一个Pod(对于这个主题的更详细的处理,请看我以前的博客文章)。

    leader选举容器可以作为一个Sidecars来从自己的应用中使用,Pod中的任何容器对谁是当前的选主感兴趣的都可以简单地通过http://localhost:4040 来访问,然后返回一个简单的JSON对象,其中包含了当前选主的名字。既然Pod中的所有容器共享了相同的网络命名空间,就不再需要服务发现了!

    举个例子,有一个简单的Node.js应用程序连接到leader选举Sidecar,然后打印出这个是否是当前的选主,领导人选举Sidecar将其标识符设置为默认的主机名。

    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来使用这个Sidecar。

    总结

    希望我已经向你展示了是多么容易为分布式应用程序使用Kubernetes来构建leader选举。在以后的部分我们将向您展示Kubernetes是如何使得构建分布式系统更容易。与此同时,还前往Google容器引擎或kubernetes.io来开始使用Kubernetes。

    本文翻译:胡震

    相关文章

      网友评论

          本文标题:2018-11-20

          本文链接:https://www.haomeiwen.com/subject/mghtqqtx.html