详解Docker Swarm服务发现和负载均衡原理

 更新时间:2018年05月04日 09:36:50   作者:Anoyi  
这篇文章主要介绍了详解Docker Swarm服务发现和负载均衡原理,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

本文将介绍基于 DNS 的负载均衡、基于 VIP 的负载均衡和路由网格(Routing Mesh)。

使用的技术

Docker 使用了 Linux 内核 iptables 和 IPVS 的功能来实现服务发现和负载均衡。

iptables 是 Linux 内核中可用的包过滤技术,它可用于根据数据包的内容进行分类、修改和转发决策。

IPVS 是 Linux 内核中可用的传输级负载均衡器。

准备工作

swarm 集群: 【Manager】node1、【Worker】node2

客户端镜像: registry.cn-hangzhou.aliyuncs.com/anoy/ubuntu

服务端镜像: registry.cn-hangzhou.aliyuncs.com/anoy/vote

如图所示,我们将在 swarm 集群中部署 “client” 服务 和 “vote” 服务,其中 “vote” 服务部署多个副本。客户端请求 “vote” 服务时,输出结果中包含服务端的容器 ID,这样就更方便演示网络请求。

集群状态

[root@node1 ~]# docker node ls
ID              HOSTNAME      STATUS       AVAILABILITY    MANAGER STATUS   ENGINE VERSION
rnr2i1y2of3n5vy2vzh2vkzq0 *  node1        Ready        Active       Leader       18.03.1-ce
qvik057dvphx5s06evmswahaf   node2        Ready        Active                 18.03.1-ce

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

docker network create --driver overlay overlay1

基于 DNS 的负载均衡

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

DNS server 内嵌于 Docker 引擎。Docker DNS 解析服务名 “vote” 并返回容器 ID 地址列表(随机排序)。客户端通常会挑第一个 IP 访问,因此负载均衡可能发生在服务器的不同实例之间。

使用如下命令创建 2 个基于 DNS 负载均衡的服务 “client” 、 “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

查看服务信息:

[root@node1 ~]# docker service ls
ID         NAME        MODE        REPLICAS      IMAGE                         PORTS
2mrj3pqyioc3    client       replicated     1/1         registry.cn-hangzhou.aliyuncs.com/anoy/ubuntu:latest
826s79tsixuh    vote        replicated     2/2         registry.cn-hangzhou.aliyuncs.com/anoy/vote:latest

[root@node1 ~]# docker service ps client
ID         NAME        IMAGE                         NODE        DESIRED STATE    CURRENT STATE      ERROR        PORTS
f74i688vbh12    client.1      registry.cn-hangzhou.aliyuncs.com/anoy/ubuntu:latest  node2        Running       Running 2 minutes ago

[root@node1 ~]# docker service ps vote
ID         NAME        IMAGE                        NODE        DESIRED STATE    CURRENT STATE        ERROR        PORTS
7iiuzl2a63hy    vote.1       registry.cn-hangzhou.aliyuncs.com/anoy/vote:latest  node1        Running       Running 47 seconds ago
uyhxxqfdima7    vote.2       registry.cn-hangzhou.aliyuncs.com/anoy/vote:latest  node2        Running       Running about a minute ago

可以看出 "client" 运行于 node2,在 node2 上进入 client 容器,使用 dig 来解析服务名 "vote",如下所示,"vote" 解析到 10.0.0.6 和 10.0.0.5

[root@node2 ~]# docker ps
CONTAINER ID    IMAGE                         COMMAND         CREATED       STATUS       PORTS        NAMES
1eed67d37cbb    registry.cn-hangzhou.aliyuncs.com/anoy/vote:latest   "gunicorn app:app -b…"  About a minute ago  Up About a minute  80/tcp       vote.2.uyhxxqfdima7smos5pki84wul
436702b21a1c    registry.cn-hangzhou.aliyuncs.com/anoy/ubuntu:latest  "ping anoyi.com"     3 minutes ago    Up 3 minutes              client.1.f74i688vbh12on8oniufht633

[root@node2 ~]# docker exec -it 436702b21a1c /bin/bash

root@436702b21a1c:/# dig vote

;; ANSWER SECTION:
vote.      600 IN A  10.0.0.5
vote.      600 IN A  10.0.0.6

使用 ping 解析 "vote" 服务,如下所示,交替解析到 10.0.0.6 和 10.0.0.5

root@436702b21a1c:/# ping -c1 vote
PING vote (10.0.0.6) 56(84) bytes of data.
64 bytes from vote.2.uyhxxqfdima7smos5pki84wul.overlay1 (10.0.0.6): icmp_seq=1 ttl=64 time=0.087 ms

root@436702b21a1c:/# ping -c1 vote
PING vote (10.0.0.5) 56(84) bytes of data.
64 bytes from vote.1.7iiuzl2a63hyj084qgufc175v.overlay1 (10.0.0.5): icmp_seq=1 ttl=64 time=0.767 ms

如果使用 curl,如下所示,请求也能解析到不同的容器

root@436702b21a1c:/# curl vote | grep -i "container id"
 % Total  % Received % Xferd Average Speed  Time  Time   Time Current
                 Dload Upload  Total  Spent  Left Speed
100 3162 100 3162  0   0  7542   0 --:--:-- --:--:-- --:--:-- 7546
     Processed by container ID 9b42319d4f13

root@436702b21a1c:/# curl vote | grep -i "container id"
 % Total  % Received % Xferd Average Speed  Time  Time   Time Current
                 Dload Upload  Total  Spent  Left Speed
100 3162 100 3162  0   0  452k   0 --:--:-- --:--:-- --:--:-- 514k
     Processed by container ID 1eed67d37cbb

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

  1. 某些应用程序将 DNS 主机名缓存到 IP 地址映射,这会导致应用程序在映射更改时超时
  2. 具有非零 DNS ttl 值会导致 DNS 条目反映最新的详细信息时发生延迟

基于 VIP 的负载均衡

基于 VIP 的负载均衡克服了基于 DNS 负载均衡的一些问题。在这种方法中,每个服务都有一个 IP 地址,并且该 IP 地址映射到与该服务关联的多个容器的 IP 地址。在这种情况下,与服务关联的服务 IP 不会改变,即使与该服务关联的容器死亡并重新启动。

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

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

使用如下命令创建 2 个 VIP 模式的服务 “client” 、 “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

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

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

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

在 "client" 的容器中使用如下命令,可以看到服务名 "vote" 映射到 VIP "10.0.0.9"

[root@node2 ~]# docker exec -it f3d1c4ef53f8 /bin/bash

root@f3d1c4ef53f8:/# dig vote

;; ANSWER SECTION:
vote.      600 IN A  10.0.0.9

Service IP "10.0.0.9" 使用 Linux 内核的 iptables 和 IPVS 负载均衡到 2 个容器。iptables 实现防火墙规则,IPVS 实现负载均衡。为了证明这一点,我们需要使用 nsenter 进入容器的网络空间 ( namespace )。为此,我们需要找到网络的命名空间。

如下是 node2 上的网络命名空间:

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

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

前 2 个命名空间是用于 overlay 网络,后面的用于容器。下面的命令用于找到 "client" 容器的网络命名空间:

[root@node2 netns]# docker ps
CONTAINER ID    IMAGE                         COMMAND         CREATED       STATUS       PORTS        NAMES
43a789312e70    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 输出:

sh-4.2# iptables -nvL -t mangle

Chain OUTPUT (policy ACCEPT 606 packets, 50867 bytes)
 pkts bytes target   prot opt in   out   source        destination
  0   0 MARK    all -- *   *    0.0.0.0/0      10.0.0.7       MARK set 0x102
  0   0 MARK    all -- *   *    0.0.0.0/0      10.0.0.9       MARK set 0x103

sh-4.2# ipvsadm
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
 -> RemoteAddress:Port      Forward Weight ActiveConn InActConn
FWM 258 rr
 -> node2:0           Masq  1   0     0
FWM 259 rr
 -> 10.0.0.10:0         Masq  1   0     0
 -> 10.0.0.11:0         Masq  1   0     0

Service IP "10.0.0.9" 使用 iptables OUTPUT 链获得标记 0x103 (十六进制 -> 十进制:259),然后 IPVS 使用此标记并将它负载均衡到 "10.0.0.10" 和 "10.0.0.11" 。

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

[root@node2 netns]# docker inspect vote.1.u46ms31e8zjdxtwrxvaec8zub | grep IPv4
            "IPv4Address": "10.0.0.10"

[root@node1 ~]# docker inspect vote.2.tutj19i4iwu1xn7arsaq815cu | grep IPv4
            "IPv4Address": "10.0.0.11"

进入 client 服务的容器,使用 curl 请求 vote 服务,输出结果如下,即请求分发到不同的容器:

root@f3d1c4ef53f8:/# curl vote | grep -i "container id"
 % Total  % Received % Xferd Average Speed  Time  Time   Time Current
                 Dload Upload  Total  Spent  Left Speed
100 3162 100 3162  0   0 14409   0 --:--:-- --:--:-- --:--:-- 14438
     Processed by container ID c2af209c4e90

root@f3d1c4ef53f8:/# curl vote | grep -i "container id"
 % Total  % Received % Xferd Average Speed  Time  Time   Time Current
                 Dload Upload  Total  Spent  Left Speed
100 3162 100 3162  0   0  165k   0 --:--:-- --:--:-- --:--:-- 171k
     Processed by container ID 43a789312e70

路由网格 (Routing mesh)

使用路由网格,服务暴露的端口会暴露在 Swarm 集群中的所有工作节点。Docker 是通过创建 "ingress" overlay 网络来实现这一点的,所有节点默认使用内在的 sandbox 网络命名空间成为 "ingress" overlay 网络的一部分。

下图描述了 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:

[root@node1 ~]# iptables -nvL -t nat

Chain DOCKER-INGRESS (2 references)
 pkts bytes target   prot opt in   out   source        destination
  0   0 DNAT    tcp -- *   *    0.0.0.0/0      0.0.0.0/0      tcp dpt:8080 to:172.18.0.2:8080
 315 18876 RETURN   all -- *   *    0.0.0.0/0      0.0.0.0/0

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

[root@node1 netns]# nsenter --net=ingress_sbox sh

sh-4.2# iptables -nvL -t mangle
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target   prot opt in   out   source        destination
  0   0 MARK    tcp -- *   *    0.0.0.0/0      0.0.0.0/0      tcp dpt:8080 MARK set 0x105

sh-4.2# ipvsadm
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
 -> RemoteAddress:Port      Forward Weight ActiveConn InActConn
FWM 261 rr
 -> 10.255.0.5:0         Masq  1   0     0
 -> 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 的流量会负载均衡到不同的容器实例:

[root@node1 netns]# docker inspect 6173afd5fab8 | grep IPv4
            "IPv4Address": "10.255.0.6"
            "IPv4Address": "10.0.0.14"

[root@node2 ~]# docker inspect b07e95c5c681 | grep IPv4
            "IPv4Address": "10.255.0.5"
            "IPv4Address": "10.0.0.13"

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

[root@node1 netns]# curl node2:8080 | grep -i "container id"
 % Total  % Received % Xferd Average Speed  Time  Time   Time Current
                 Dload Upload  Total  Spent  Left Speed
100 3162 100 3162  0   0  199k   0 --:--:-- --:--:-- --:--:-- 192k
     Processed by container ID 6173afd5fab8

[root@node1 netns]# curl node2:8080 | grep -i "container id"
 % Total  % Received % Xferd Average Speed  Time  Time   Time Current
                 Dload Upload  Total  Spent  Left Speed
100 3162 100 3162  0   0  7551   0 --:--:-- --:--:-- --:--:-- 7546
     Processed by container ID b07e95c5c681

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

[root@node2 ~]# curl node1:8080 | grep -i "container id"
 % Total  % Received % Xferd Average Speed  Time  Time   Time Current
                 Dload Upload  Total  Spent  Left Speed
100 3162 100 3162  0   0  7531   0 --:--:-- --:--:-- --:--:-- 7546
     Processed by container ID 6173afd5fab8

[root@node2 ~]# curl node1:8080 | grep -i "container id"
 % Total  % Received % Xferd Average Speed  Time  Time   Time Current
                 Dload Upload  Total  Spent  Left Speed
100 3162 100 3162  0   0  169k   0 --:--:-- --:--:-- --:--:-- 171k
     Processed by container ID b07e95c5c681

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 一台虚拟机基于docker搭建大数据HDP集群的思路详解

    一台虚拟机基于docker搭建大数据HDP集群的思路详解

    这篇文章主要介绍了一台虚拟机基于docker搭建大数据HDP集群 ,本篇文章主要讲了大数据集群搭建的架构设计和实现思路部分,后面文章会探讨上层应用的构建,需要的朋友可以参考下
    2022-11-11
  • 迁移变更Docker默认数据存储目录的步骤详解

    迁移变更Docker默认数据存储目录的步骤详解

    Docker安装的默认数据目录为/var/lib/docker,但是如果/目录挂载的磁盘空间不够,就需要迁移docker数据到其他目录,接下来本就给大家介绍迁移变更Docker默认数据存储目录的操作步骤,需要的朋友可以参考下
    2023-12-12
  • 在Docker容器中使用Arthas的详细步骤

    在Docker容器中使用Arthas的详细步骤

    本文不是介绍arthas怎么用的。这里要说的是,如何在我们的docker容器中,使用arthas,对如何在Docker容器中使用Arthas相关知识感兴趣的朋友一起看看吧
    2021-12-12
  • Docker 教程之Docker Hub详细介绍

    Docker 教程之Docker Hub详细介绍

    这篇文章主要介绍了Docker 教程之Docker Hub详细介绍的相关资料,需要的朋友可以参考下
    2016-12-12
  • docker image删不掉的解决办法

    docker image删不掉的解决办法

    在使用Docker的时候遇到删不掉image的情况,怎么回事,如何解决呢?下面小编给大家分享下docker image删不掉的解决办法,需要的朋友参考下吧
    2017-01-01
  • Docker制作镜像的两种实现方式

    Docker制作镜像的两种实现方式

    本文主要介绍了Docker制作镜像的两种实现方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Docker Stack部署Java Web项目的实现

    Docker Stack部署Java Web项目的实现

    本文主要介绍了Docker Stack部署Java Web项目的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • Docker在Windows系统中的安装和使用方法详解

    Docker在Windows系统中的安装和使用方法详解

    这篇文章主要给大家介绍了关于Docker在Windows系统中的安装和使用方法,Docker允许开发中将应用、依赖、函数库、配置一起打包,形成可移植镜像Docker应用运行在容器中,需要的朋友可以参考下
    2023-09-09
  • 详解Docker commit的使用

    详解Docker commit的使用

    这篇文章主要介绍了Docker commit使用的相关资料,帮助大家更好的理解和使用docker容器,感兴趣的朋友可以了解下
    2020-09-09
  • CentOS7 PostgreSQL安装、配置、使用详解

    CentOS7 PostgreSQL安装、配置、使用详解

    这篇文章主要介绍了CentOS7 PostgreSQL安装、配置、使用详解的相关资料,需要的朋友可以参考下
    2016-11-11

最新评论