docker容器集群之swarm

swarm是docker原生集成的容器编排服务,类似google的kubernetes和apache的mesos。

之前的BLOG里提过docker容器,它大大简化了应用程序的环境配置过程,并实现了一定程度的网络隔离,但它没有解决以下问题:

  • 多vm的部署问题。登陆到集群的每台vm上去部署实在是太麻烦了。
  • 服务间互相调用的问题。服务间内部互相调用通常使用ip+端口的形式,一旦某个服务的ip或者端口发生了变更,所有依赖它的服务都要进行相应的修改。

swarm解决这两个问题的方案是:

  • 一个vm集群维护若干个manager节点,部署脚本只需要在manager节点上执行,容器会按照给定的约束条件,如用户可以指定该服务在哪些节点上运行,该服务运行几个容器副本,等等,并自动完成部署工作。一个或者若干个容器如果挂掉了,manager节点会根据情况重新启动新的,维护服务的可用性。
  • 容器内部集成DNS服务,容器间可以通过域名互访,无需使用ip

swarm的结构

基础性的介绍还是推荐阅读官方文档。

docker有两个基础概念,镜像和容器。swarm则在此基础上拓展了一些新的概念。

service

一个service规定了某个镜像在运行时的执行策略,包括文件映射,端口映射,环境变量,启动的副本数量等,即docker run的执行参数。CLI为docker service ...

stack

一个stack通常由一个或多个service组成。每个stack可以指定一个或多个要加入的网络名,同一个网络下的容器,可以通过service name或者stack+service name互相访问。每一个stack通常对应一个compose-file。CLI为docker stack ...

swarm

swarm通常是一个或者多个node的集合(这里node可以简单的理解为vm)。node有三种角色:leader, manager, worker.

  • worker: 普通节点,只能被动接收manager节点的安排并运行容器。
  • manager: 管理节点。针对集群的操作都只能在manager节点上进行,如docker stack deploy和创建overlay网络等。每个node可以同时具有manager和worker的身份,即它本身也可以运行容器。
  • leader: 主节点,从manager节点中产生,集群内唯一。

CLI有两个,创建、加入swarm等使用docker swarm ...,查看swarm状态则使用docker node ...。这是一个比较奇怪的设计。

overlay网络

overlay网络是一种跨主机通信的网络,它和swarm紧密结合,提供集群内容器间的互访能力。实际上,只能在swarm集群的manager节点上创建overlay网络,非manager节点或者本身不是某个swarm的成员都是无法创建overlay网络的。CLI为docker network create --driver overlay ...

swarm的部署

swarm部署使用的文件叫做compose file. 还是推荐阅读官方文档

swarm的集群选举

swarm使用raft一致性算法进行集群选举. 基本要求是有过半的投票数才能选出leader, 只有manager节点才具有投票权, worker节点是不计算在内的. leader当选的条件是获得超过半数的成员支持, 通常选择奇数个节点作为manager, 是因为这样更节约资源.

  • 2节点时, 不能容忍任何一个节点离线, 略过
  • 3节点和4节点时, 都只能容忍一个节点离线, 但前者少用一个节点, 更节约资源. 依次类推, 5节点和6节点也是类似的.

更多数量的节点会带来更好的可靠性, 但耗费在节点间通信上的开销也会增加, 因此需要在二者之间取得一个平衡.

处于群龙无首状态的swarm集群会发生什么? 引用官方文档的一句话:

This means that in a cluster of 5 Managers running Raft, if 3 nodes are unavailable, the system cannot process any more requests to schedule additional tasks. The existing tasks keep running but the scheduler cannot rebalance tasks to cope with failures if the manager set is not healthy.

即: 没有leader的集群, 服务暂时是可用的, 但维持容器状态的机制已经消失了, 比如有容器挂掉了也不会有manager来自动添加新容器来维持副本数量达到要求了.

swarm负载均衡

这个内置的负载均衡器是swarm比较神奇的功能之一。swarm的负载均衡分为两个部分,一个是外部访问负载均衡,另一个是swarm内部容器间互访的负载均衡。


内部负载均衡

容器内部发起的请求会应用此负载均衡策略。内部负载均衡又分两种模式,分别是virtual ip和dns round-robin.

virtual ip

在这种模式下,docker会给每个service分配一个virtual ip,假设我们的service叫做web,容器和服务ip分配如下所示:

Container/Service Overlay Addr Ingress Addr
容器#1 10.0.0.42 10.255.0.6
容器#2 10.0.0.43 10.255.0.7
web 10.0.0.5 10.255.0.5

那么,在任何一个容器里去ping web,得到的结果都是web的virtual ip 10.0.0.5,后端再按照round-robin模式进行请求分发。

在容器#2内键入curl http://web,假设此时负载均衡到了容器#1上,那么容器#2内部netstat显示类似10.0.0.5:44929 -> 10.0.0.5:80,被访问的容器#1显示10.0.0.43:44929 -> 10.0.0.42:80。像是转发数据包的同时修改了SIP和DIP,这背后的原因还有待进一步的研究。

dnsrr

DNSRR模式下service不再分配virtual ip,DNS将会返回全部容器的overlay网络地址。


外部负载均衡

跨vm间用ip地址+端口互访以及公网的访问将会应用外部负载均衡策略。

假设现在集群上有三台机器ABC,A为manager节点,现在执行一个compose file,部署副本数为2的web服务器,该服务会返回当前的主机名,因为运行在在容器里,所以这个主机名即为容器的id。集群有三个节点,副本数为2, 必然有一台机器是没有运行该容器的。假设A和B执行了该容器,那么尝试访问没有运行该容器的节点,即C,会得到类似以下输出:

$ curl http://35.187.206.120 
43a12a6f881b is working
$ curl http://35.187.206.120 
ba4c33452acc is working

如果继续执行,会发现这两个id继续循环出现。访问A,B的现象也就是类似的。也就是说:

  • http请求被分发到了两个运行的容器中,策略非常像round-robin
  • 在没有运行该容器的节点,同样可以访问该服务。

再做一个实验,把运行容器的节点之一B执行关机操作。此时,通过B已经无法访问该服务了,A和C仍然能正常访问,但是其中一个返回的主机名改变了,原因是manager节点为了维持2个副本又重新运行了一个容器。

实现原理

参考阿里云的这篇文章集群内服务服务间路由和负载均衡,不难得出负载均衡的实现的一些关键信息。

  • 负载均衡基于ingress虚拟网络实现, 它在swarm集群建立的时候创建
  • 负载均衡的原理是IPVS/NAT,默认round-robin策略。用于负载均衡的NAT模式一般有两种,DNAT和FULLNAT。那么swarm的负载均衡是哪种模式呢?进容器,输入netstat:
/home/app # netstat -apn 
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.11:40765        0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1/node
tcp        0      0 10.255.0.19:80          10.255.0.2:32204        ESTABLISHED 1/node
udp        0      0 127.0.0.11:52236        0.0.0.0:* 

输出中有一个ESTABLISHED状态的连接,就是我们的curl请求,其源IP已经被修改到了ingress网段内,因此,负载均衡工作在FULLNAT模式。

FULLNAT模式相较于DNAT,更加灵活,负载均衡无需位于网关位置,但它也有NAT的缺点,所有的流量都会经过负载均衡,这会是一个瓶颈。

参考资料

  • 集群内服务服务间路由和负载均衡
  • IPVS负载均衡(三)IPVS三种工作方式之NAT模式
  • LVS 的基本原理和配置方法
  • MGW——美团点评高性能四层负载均衡
  • Service Discovery and Load balancing Internals in Docker 1.12
  • 基于Swarm的多主机容器网络
  • Docker compose file: endpoint mode

你可能感兴趣的:(docker容器集群之swarm)