如图所示,我们将在 swarm 集群中部署 “client” 服务 和 “vote” 服务,其中 “vote” 服务部署多个副本。

客户端请求 “vote” 服务时,输出结果中包含服务端的容器 ID,这样就更方便演示网络请求。

docker node ls

使用如下命令,创建 overlay 网络:

docker network create --driver overlay overlay

一、基于 DNS 的负载均衡(DOCKER引擎内嵌了DNS服务器,创建容器时,在各个容器内设置nameserver,指向dns服务)--内部转发

dns服务内会配置overlay网络内的容器的IP和容器主机之间的映射

下图描述了基于 DNS 的负载均衡是如何工作的:DNS轮询

DNS server 内嵌于 Docker 引擎。

Docker DNS 解析服务名 “vote” 并返回容器 ID 地址列表(随机排序)。

客户端通常会挑第一个 IP 访问,因此负载均衡可能发生在服务器的不同实例之间。

  • 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
可以看出 "client" 运行于 node2,在 node2 上进入 client 容器,使用 dig 来解析服务名 "vote",如下所示,"vote" 解析到 10.0.0.6 和 10.0.0.5
docker exec -it 436702b21a1c /bin/bash
dig vote; 使用 ping 解析 "vote" 服务,如下所示,交替解析到 10.0.0.6 和 10.0.0.5

基于 DNS 负载均衡存在如下问题:

  • 某些应用程序将 DNS 主机名缓存到 IP 地址映射,这会导致应用程序在映射更改时超时

  • 具有非零 DNS ttl 值会导致 DNS 条目反映最新的详细信息时发生延迟

二、基于 VIP 的负载均衡(IPVS)--内部转发

克服了基于 DNS 负载均衡的一些问题。

在这种方法中,每个服务都有一个 IP 地址,并且该 IP 地址映射到与该服务关联的多个容器的 IP 地址。

在这种情况下,与服务关联的服务 IP 不会改变,即使与该服务关联的容器死亡并重新启动。

下图描述了基于 VIP 的负载均衡是如何工作的:

DNS server 会将服务名 "vote" 解析到 VIP,使用 iptables 和 ipvs,VIP 实现 2 个服务端 "vote" 容器的负载均衡。

 

查看这 2 个服务和它们的服务 IP:

  1. [root@node1 ~]# docker service inspect --format {{.Endpoint.VirtualIPs}}  vote
    [{tetug0isdx1gri62g7cfm889i 10.0.0.9/24}]
  2.  
  3. [root@node1 ~]# docker service inspect --format {{.Endpoint.VirtualIPs}}  client
    [{tetug0isdx1gri62g7cfm889i 10.0.0.7/24}]

Service IP "10.0.0.9" 使用 Linux 内核的 iptables 和 IPVS 负载均衡到 2 个容器。

iptables 实现防火墙规则,IPVS 实现负载均衡。

为了证明这一点,我们需要使用 nsenter 进入容器的网络空间 (namespace)。为此,我们需要找到网络的命名空间。

[root@node2 ~]# cd /run/docker/netns/

[root@node2 netns]# ls 1-tetug0isdx  1-vyy22w04t6  be7330b99a27  d67fa9efb59e  ingress_sbox

[root@node2 netns]# docker ps

CONTAINER ID        IMAGE                                                  COMMAND                  CREATED             STATUS              PORTS               NAMES43a789312e70        registry.cn-hangzhou.aliyuncs.com/anoy/vote:latest     "gunicorn app:app -b…"   3 minutes ago       Up 3 minutes        80/tcp              vote.1.u46ms31e8zjdxtwrxvaec8zub
f3d1c4ef53f8        registry.cn-hangzhou.aliyuncs.com/anoy/ubuntu:latest   "ping anoyi.com"         4 minutes ago       Up 4 minutes                            client.1.ycox088aek5ajejezubwsjqf2
 
[root@node2 netns]# docker inspect f3d1c4ef53f8 | grep -i sandbox
            "SandboxID": "be7330b99a274a03a7f58e9e991346dc6f048836a1682c7244a6068acbfb664c",            "SandboxKey": "/var/run/docker/netns/be7330b99a27",

SandboxID 即为 "client" 容器的网络命名空间。

使用如下命令,我们就能够进入到 "client" 容器的网络命令空间:

nsenter --net=f3d1c4ef53f8 sh

下面,我们可以看到 iptables 的转发规则和 IPVS 输出:

  1. sh-4.2#   iptables -nvL -t mangle Chain OUTPUT (policy ACCEPT 606 packets, 50867 bytes)
  2.  pkts bytes target     prot opt in     out     source               destination
  3.     0     0 MARK       all  --  *      *       0.0.0.0/0            10.0.0.7             MARK set 0x102
  4.     0     0 MARK       all  --  *      *       0.0.0.0/0            10.0.0.9             MARK set 0x103
  5.  
  6. sh-4.2# ipvsadm   IP Virtual Server version 1.2.1 (size=4096)
  7. Prot LocalAddress:Port Scheduler Flags
  8.   -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
  9. FWM  258 rr
  10.   -> node2:0                      Masq    1      0          0
  11. FWM  259 rr
  12.   -> 10.0.0.10:0                  Masq    1      0          0
  13.   -> 10.0.0.11:0                  Masq    1      0          0
 

查看 vote 服务的 2 个容器的 IP 如下所示,即 VIP "10.0.0.9" 负载均衡到不同的容器实例:

  1. [root@node2 netns]# docker inspect vote.1.u46ms31e8zjdxtwrxvaec8zub | grep IPv4
  2.                         "IPv4Address": "10.0.0.10"
    [root@node1 ~]# docker inspect vote.2.tutj19i4iwu1xn7arsaq815cu | grep IPv4
  3.                         "IPv4Address": "10.0.0.11"
三、路由网格 (Routing mesh)--外部访问内部

使用路由网格,服务暴露的端口会暴露在 Swarm 集群中的所有工作节点上。

Docker 是通过创建 "ingress" overlay 网络来实现这一点的,所有节点默认使用内在的 sandbox 网络命名空间成为 "ingress" overlay 网络的一部分。

sandbox 网络命名空间:具有独立的网络栈,IPTABLE 路由转发规则,独立的IPVS内核负载均衡,会通过接入sandbox 网络命名空间的ingress网络,分发请求到接入这个网络的某个容器

具体过程:主机指定端口流量,,通过iptable,会通过接入这个sandbox 网络命名空间,导向到ngress_sbox(ls /run/docker/netns),进入IPvs

下图描述了 Routing mesh 如何实现负载均衡的:

首先,会将 Hostname 或 IP 映射到 Sandbox IP,Sandbox 中的 iptables 和 IPVS 负责将请求负载均衡到 2 个 vote 容器。Ingress sandbox 网络命名空间驻留在 swarm 集群中的所有工作节点,它通过将主机映射的端口负载均衡到后端容器来协助路由网格功能。

使用如下命令创建 vote 服务,使用路由网格暴露端口到所有节点:

docker service create --name vote --network overlay1 --replicas 2 -p 8080:80 registry.cn-hangzhou.aliyuncs.com/anoy/vote

下图显示了 Sandbox、容器和每个节点的网络之间的映射关系:

如图所示,Sandbox 和 vote 容器是 "ingress" 网络的一部分,它有助于路由网格。client 容器和 vote 容器是 "overlay1" 网络的一部分,它有助于内部负载均衡。所有容器都是默认 "docker_gwbridge" 网络的一部分。

遵循 iptables 中的 NAT 规则显示,端口 8080 上的主机流量发送到 node1 里的 Sandbox:

  1. [root@node1 ~]# iptables -nvL -t natChain DOCKER-INGRESS (2 references)
  2.  pkts bytes target     prot opt in     out     source               destination
  3.     0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8080 to:172.18.0.2:8080
  4.   315 18876 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

进入 node1 上的 Sandbox 网络命名空间  (ingress_sbox),查看 iptables 的转发规则和 IPVS 输出:

  1. [root@node1 netns]# nsenter --net=ingress_sbox shsh-4.2# iptables -nvL -t mangleChain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
  2.  pkts bytes target     prot opt in     out     source               destination
  3.     0     0 MARK       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8080 MARK set 0x105
  4.  
  5. sh-4.2# ipvsadmIP Virtual Server version 1.2.1 (size=4096)
  6. Prot LocalAddress:Port Scheduler Flags
  7.   -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
  8. FWM  261 rr
  9.   -> 10.255.0.5:0                 Masq    1      0          0
  10.   -> 10.255.0.6:0                 Masq    1      0          0

端口 8080 标记为 0x105 (十六进制 -> 十进制:261),IPVS 使用此标记将它负载均衡到 "10.255.0.5" 和 "10.255.0.6" 。

查看 vote 服务的 2 个容器的 IP 如下所示,即主机端口 8080 的流量会负载均衡到不同的容器实例:

  1. [root@node1 netns]# docker inspect 6173afd5fab8 | grep IPv4
  2.                         "IPv4Address": "10.255.0.6"
  3.                         "IPv4Address": "10.0.0.14"[root@node2 ~]# docker inspect b07e95c5c681 | grep IPv4
  4.                         "IPv4Address": "10.255.0.5"
  5.                         "IPv4Address": "10.0.0.13"

验证负载均衡,在 node1 上通过 node2 的 IP 和 8080 端口请求 vote 服务:

  1. [root@node1 netns]# curl node2:8080 | grep -i "container id"
  2.   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
  3.                                  Dload  Upload   Total   Spent    Left  Speed100  3162  100  3162    0     0   199k      0 --:--:-- --:--:-- --:--:--  192k
  4.           Processed by container ID 6173afd5fab8
  5.  
  6. [root@node1 netns]# curl node2:8080 | grep -i "container id"
  7.   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
  8.                                  Dload  Upload   Total   Spent    Left  Speed100  3162  100  3162    0     0   7551      0 --:--:-- --:--:-- --:--:--  7546
  9.           Processed by container ID b07e95c5c681

在 node2 上通过 node1 的 IP 和 8080 端口请求 vote 服务:

  1. [root@node2 ~]# curl node1:8080 | grep -i "container id"
  2.   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
  3.                                  Dload  Upload   Total   Spent    Left  Speed100  3162  100  3162    0     0   7531      0 --:--:-- --:--:-- --:--:--  7546
  4.           Processed by container ID 6173afd5fab8
  5.  
  6. [root@node2 ~]# curl node1:8080 | grep -i "container id"
  7.   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
  8.                                  Dload  Upload   Total   Spent    Left  Speed100  3162  100  3162    0     0   169k      0 --:--:-- --:--:-- --:--:--  171k
  9.           Processed by container ID b07e95c5c681


 

最新文章

  1. .NET DateTime类型变量作为参数时设置默认值
  2. Apache_proxy负载均衡和Session复制
  3. CSS3基础03(3D②) 求粉丝
  4. Windows Azure Virtual Network (7) 设置Azure Virtual Machine固定公网IP (Virtual IP Address, VIP) (2)
  5. Windows上搭建Kafka运行环境
  6. iOS开发——语法OC篇&BOOL / bool / Boolean / NSCFBoolean
  7. 【XCode7+iOS9】http网路连接请求、MKPinAnnotationView自定义图片和BitCode相关错误--备用
  8. Codeforces Round #311 (Div. 2) E - Ann and Half-Palindrome(字典树+dp)
  9. CSS块级元素和行内元素
  10. [iOS Animation]-CALayer 图层树
  11. uva1629,Cake Slicing,记忆化搜索
  12. GoGland 快捷键说明
  13. jQ效果:jQuery之插件开发短信发送倒计时功能
  14. hyperledge工具-cryptogen
  15. Arduino IDE for ESP8266 项目(3)创建AP+STA
  16. kali2016.1 基本配置
  17. 阻止form表单提交的问题
  18. 最短路-Prim算法 dijkstra算法
  19. 移动web开发都会遇到的坑(会持续更新)
  20. Windows进程通信 -- 共享内存

热门文章

  1. mp
  2. P1177排序题解
  3. js实现页面的秒数倒计时
  4. IIS的部署(二)------虚拟目录的使用
  5. Bugku-CTF之求getshell
  6. 后台用map接收数据,报类型转换错误
  7. jmeter实现SMTP邮件协议压测
  8. Scala实现网站流量实时分析
  9. Unity UGUI事件接口概述
  10. logging basic