Docker Swarm服务发现和负载均衡原理
Docker使用的是Linux内核iptables和IPVS的功能来实现服务发现和负载均衡。Iptables是Linux内核中可用的包过滤技术,可根据数据包的内容进行分类、修改和转发决策。IPVS是Linux内核中可用的传输级负载均衡。
本地创建一个集群环境,我本地有三节点集群环境:
客户端镜像:registry.cn-hangzhou.aliyuncs.com/anoy/ubuntu
服务端镜像:registry.cn-hangzhou.aliyuncs.com/anoy/vote
DNS server内嵌于Docker引擎。在创建集群的时候可以直接指定
--endpoint-mode dnsrr 来指明,这个服务里面的task或者是所有启动的容器访问都通过DNS的方式来进行负载均衡,这个是啥意思。操作下就清楚了:
创建一个网络
docker network create --driver overlay overlay1
创建client节点(启动一个),和vote节点(启动多个),实现client节点访问vote的时候,是给均衡到不同的vote上了。
docker service create --endpoint-mode dnsrr --replicas 1 --name client --network overlay1 registry.cn-hangzhou.aliyuncs.com/anoy/ubuntu ping anoyi.com
docker service create --endpoint-mode dnsrr --name vote --network overlay1 --replicas 2 registry.cn-hangzhou.aliyuncs.com/anoy/vote
然后进行如下操作
docker service ls 查看服务
docker service ps xxxxclient的id 查看client的信息,找到他在哪个节点上,然后登陆到那个节点节点的机器上
docker ps 查看容器,找到client对应的容器
docker exec -it xxxxclientid bash 登陆到这个容器
上面操作如下图
此时在client容器上,可以直接dig vote 看下对vote的dns解析
如上,有两条。可以测试下是不是会被随机解析到上面,这里用ping
是可以看到均衡效果的,这个就是基本的DNS解析来实现负载均衡。但是这样会产生问题,某些应用程序将DNS主机名缓存到IP地址映射,这回导致应用程序在访问更改时超时,具有非零DNS ttl 值会导致DNS条目反应最新的详细信息时发生延迟。
基于VIP的负载均衡可以解决1中DNS总是随便挑给客户端带来的不方便的影响。每个服务都有一个IP地址,并且该IP地址映射到与该服务关联的多个容器的IP地址。在这种情况下,与服务关联的服务IP不会改变,即使与该服务关联的容器死亡并重新启动。
运行过程中,DNS service会将服务名”vote”解析到VIP,使用iptables和ipvs,VIP实现2个服务端”vote”容器的负载均衡。
把上面创建的两个服务删除,然后重新部署。
docker service create --replicas 1 --name client --network overlay1 registry.cn-hangzhou.aliyuncs.com/anoy/ubuntu ping anoyi.com
docker service create --name vote --network overlay1 --replicas 2 registry.cn-hangzhou.aliyuncs.com/anoy/vote
并没有指定--endpoint-mode,也就是说Docker Swarm默认就是用的VIP
查看这两个服务的VIP
docker service inspect --format {{.Endpoint.VirtualIPs}} vote
docker service inspect --format {{.Endpoint.VirtualIPs}} client
然后跟上面姿势一样,找下client在哪个节点上,登上去,看下他是怎么dns vote的。
这次DNS就只有一个解析了,解析到的地址是vote服务的VIP,ping的话也不会存在跳转别的ip的情况。
现在别动,继续在client里面执行
curl vote | grep -i "container id"
通过返回来的容器id来区分到底是谁在为我们干活
路由网格(Routing mesh)
使用路由网格,服务暴露的端口会暴露在Swarm集群中的所有工作节点。Docker是通过创建 ingress overlay网络来实现这一点的。所有节点默认使用内在的sandbox网络命名空间成为ingress overlay网络的一部分:
直接在上面的实操例子上更新一个端口映射
docker service update --publish-add 80:80 9fk2k04fw98p
Sandbox和vote容器是ingress网络的一部分,它有助于路由网格。client容器和vote容器是overlay1网络的一部分,有助于内部负载均衡。所有容器都是默认docker_gwbridge网络的一部分。遵循iptables中的NAT规则显示,端口80上的主机流量发送到node1里的Sandbox.
这样,然后浏览器访问(不同刷新):
跟预期的一样,每个节点上不停的刷新都会看到下面的容器id会交替变化,说明负载均衡是好使的。