Docker Swarm - 服务发现和负载均衡原理 - 简书

标签: | 发表时间:2019-07-13 17:23 | 作者:
出处:https://www.jianshu.com

本文将介绍基于 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 负载均衡存在如下问题:

  • 某些应用程序将 DNS 主机名缓存到 IP 地址映射,这会导致应用程序在映射更改时超时
  • 具有非零 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 swarm 服务] 推荐:

基于 Consul 的 Docker Swarm 服务发现

- - IT瘾-dev
基于 Consul 的 Docker Swarm 服务发现. 2017 年 1 月 10 日发布. Docker 是一种新型的虚拟化技术,它的目标在于实现轻量级操作系统的虚拟化. 相比传统的虚拟化方案,Docker. 虚拟化技术有一些很明显的优势:启动容器的速度明显快于传统虚拟化技术,同时创建一台虚拟机占用的资源也要远远小于传统的虚拟技术.

Docker Swarm - 服务发现和负载均衡原理 - 简书

- -
本文将介绍基于 DNS 的负载均衡、基于 VIP 的负载均衡和路由网格(Routing Mesh). Docker 使用了 Linux 内核 iptables 和 IPVS 的功能来实现服务发现和负载均衡. iptables 是 Linux 内核中可用的包过滤技术,它可用于根据数据包的内容进行分类、修改和转发决策.

How to configure autoscaling on docker swarm? - Stack Overflow

- -
This will involve a lot of scripting but the idea is to monitor the cluster for CPU / Memory / Network usage (with.

Docker Swarm管理节点高可用分析 | Jalon'Blog

- -
SwarmKit构建的 Docker 引擎内置(原生)的集群管理和编排工具. 其主要作用是把若干台Docker主机抽象为一个整体,并且通过一个入口统一管理这些Docker主机上的各种Docker资源. Swarm和Kubernetes比较类似,但是更加轻量,具有的功能也较kubernetes更少一些.

Traefik 实战(traefik+docker swarm) - 好脑袋和烂笔头 - OSCHINA

- -
    traefik是一个使你把微服务暴露出来变的更容易的http反向代理和负载均衡软件. traefik支持K8S、docker swarm、mesos、consul、etcd、zookeeper等基础设施组件,个人认为更适合容器化的微服务,traefik的配置会自动的、动态的配置更新自己. traefik的原理在另一篇讲解,本章直接实战看效果.

减少使用Java应用服务器,迎接Docker容器

- - ITeye资讯频道
【编者的话】随着Docker的发展,越来越多的应用开发者开始使用Docker. James Strachan写了一篇有关Java开发者如何使用Docker进行轻量级快速开发的文章. 他告诉我们,使用Docker和服务发现的机制,可以有效减轻Java运维人员的负担,进行项目的快速启动和持续迭代. 多年来,Java生态系统一直在使用应用服务器.

使用Spring Cloud和Docker构建微服务架构

- - Oopsguy
原文: https://dzone.com/articles/microservice-architecture-with-spring-cloud-and-do. 作者:Alexander Lukyanchikov. 如何使用Spring Boot、Spring Cloud、Docker和Netflix的一些开源工具来构建一个微服务架构.

微服务应用-基于Spring Cloud和Docker构建电影推荐微服务

- - CSDN博客推荐文章
使用Spring Cloud和Docker构建电影推荐微服务. 如果你对云应用很了解,可以直接移步下载运行项目(https://github.com/kbastani/spring-cloud-microservice-example),或跳转到部署步骤,. 本博客系列将向你介绍一些使用Spring Cloud和Docker构建微服务平台的基本概念.

Docker & Flatpak

- - IT瘾-dev
目前最流行的技术莫过于Docker,Docker和Docker衍生的东西用到了很多很酷的技术,目前deepin应用软件发布转变成flatpak,这些看似风牛马不相及的技术方案,实际都使用了一个共同的底层技术——Namespace,假如没有namespace支持,这些技术实现都将成为空中楼阁. 一句话总结,无论是Docker、sysmted-nspawn还是flatpak,都是在namespace基础上,针对不同的场景,生出的不同的解决方案.

去哪儿网基于Mesos和Docker构建私有云服务的实践

- - IT瘾-bigdata
【导读】本文深入介绍了去哪儿网利用Mesos和Docker构建私有云服务的全过程,分享了从无状态应用向有状态应用逐步过度的经验与心得. 2014年下半年左右,去哪儿完成了有关构建私有云服务的技术调研,并最终拍定了Docker/Mesos这一方案. 下图1展示了去哪儿数据平台的整体架构:. 图1:去哪儿数据平台的整体架构.