从零开始学习docker(十九)Swarm mode 集群服务间通信--RoutingMesh

在上一节中,我们介绍了通过service create部署了wordpress和mysql,我们发现了几个问题:

不同节点之间如何通信?

通过service创建,将mysql和wordpress部署到cluster中,然后这两个service位于不同的节点上,这两个节点之间是可以相互通信的,并且可以通过service name进行通信,这里面就涉及到一个DNS服务发现的问题。

我们在之前将docker-compose时讲过,我们通过docker-compose部署一个application,这个application中的service 如果是连在了同一个网络上,那么他们之间是可以通过service name相互访问的。这个底层是通过DNS服务去实现的。这是docker-compose在单机的情况下。

今天我们在swarm cluster中我们的service是位于不同的节点上面,他们之间也可以通过service name进行通信的,所以说这也是DNS的功劳在里面。对于swarm来讲,我们有内置的DNS服务发现功能,通过swarm创建一个service时,如果是连到了一个overlay上,就可以为所有连到这个overlay上的service增加一条DNS记录,然后通过DNS记录就可以得到IP地址,然后就可以访问服务了。如下图所示:

eb69b83c912366e805baf0080f22072912d.jpg

其中DNS的name用service name来表示,而对应的记录IP并不是service所在容器的IP,而是一个虚拟IP(Virtual IP)。

为什么会这样?我们想一想,如果我们的service有一个横向的扩展(scale),那么service就不一定会在哪个节点上面,有一种情况是:某个节点的service down掉了,我们在其他节点上重新启动一个service,这时他的IP地址发生了变化;还有一种情况:有多个service,因此会对应多个IP地址。如果我们在DNS中通过实际的容器地址去表示IP地址,那么这会产生不稳定的现象,因为IP地址有可能发生变化。这时我们如果通过虚拟IP来解决这个问题。我们通过service来分配一个虚拟IP,而这个虚拟IP是不会变化的,也就是说一旦我们的service创建之后,IP就不会发生变化。但是这个虚拟IP地址背后,它所指的是实际IP(也就是容器IP),这时通过LVS实现的。

下面我们通过实验来具体演示一下。

准备环境

创建一个overlay类型的网络,名称叫my-demo

iie4bu@hostdocker:~$ docker network create -d overlay my-demo
cojus8blvkdozz8ykefozf7ml

创建一个service:这个service使用一个whoami的image,这个image会提供一个web服务的,如果我们访问他的8000端口的话,它会返回容器的hostname。

iie4bu@hostdocker:~$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                   PORTS
9i6wz6cg4koc        whoami              replicated          1/1                 jwilder/whoami:latest   *:8000->8000/tcp

查看whoami 运行在哪个节点:

iie4bu@swarm-manager:~$ docker service ps whoami
ID                  NAME                IMAGE                   NODE                DESIRED STATE       CURRENT STATE             ERROR               PORTS
6hhuf528spdw        whoami.1            jwilder/whoami:latest   swarm-manager       Running             Running 23 minutes ago

可以看到运行在swarm-manager节点上,可以通过docker container ls 看到这个容器:

iie4bu@swarm-manager:~$ docker container ls
CONTAINER ID        IMAGE                   COMMAND             CREATED             STATUS              PORTS               NAMES
cc9f97cc5056        jwilder/whoami:latest   "/app/http"         23 minutes ago      Up 23 minutes       8000/tcp            whoami.1.6hhuf528spdw9j9pla7l3tv3t

监听了本地的8000端口,

iie4bu@swarm-manager:~$ curl 127.0.0.1:8000
I'm cc9f97cc5056

返回了hostname。

然后我们再创建一个service,也连到这个my-demo上面,这个service是busyboxservice。

iie4bu@swarm-manager:~$ docker service create --name client -d --network my-demo busybox sh -c "while true; do sleep 3600; done"
jsj6euq2qlwljg421bet1d8cr

然后查看service:

iie4bu@swarm-manager:~$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                   PORTS
jsj6euq2qlwl        client              replicated          1/1                 busybox:latest          
9i6wz6cg4koc        whoami              replicated          1/1                 jwilder/whoami:latest   *:8000->8000/tcp

当client的REPLICAS变为1/1之后,说明已经启动成功。

查看client位于哪个节点:

iie4bu@swarm-manager:~$ docker service ps client
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE                ERROR               PORTS
czotxqi6bi5k        client.1            busybox:latest      swarm-worker2       Running             Running about a minute ago

可以看到是位于swarm-worker2节点上。

进入到swarm-worker2节点中,查看client的容器:

iie4bu@swarm-worker2:~$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
f84e7570ee1c        busybox:latest      "sh -c 'while true; …"   4 minutes ago       Up 4 minutes                            client.1.czotxqi6bi5k8uwkgzxcrwp1r

实验

进入swarm-worker2的client容器中,然后去ping whoami

iie4bu@swarm-worker2:~$ docker exec -it f84e sh
/ # ping whoami
PING whoami (10.0.2.5): 56 data bytes
64 bytes from 10.0.2.5: seq=0 ttl=64 time=0.085 ms
64 bytes from 10.0.2.5: seq=1 ttl=64 time=0.078 ms
64 bytes from 10.0.2.5: seq=2 ttl=64 time=0.077 ms
^C
--- whoami ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.077/0.080/0.085 ms

发现是可以ping通whoami的,并且是ping的10.0.2.5这个IP地址。而我们是在swarm-worker2节点中,去ping swarm-manager节点。说明是可以通过name访问到service,但是这个ip 10.0.2.5地址并不是whoami容器的ip地址。

思考:我们将whoami服务scale变成多个,那么在ping whoami的时候地址会不会变呢?

扩展whoami:

iie4bu@swarm-manager:~$ docker service scale whoami=2
whoami scaled to 2
overall progress: 2 out of 2 tasks 
1/2: running   [==================================================>] 
2/2: running   [==================================================>] 
verify: Service converged

然后我们查看whoami这个服务:

iie4bu@swarm-manager:~$ docker service ps whoami
ID                  NAME                IMAGE                   NODE                DESIRED STATE       CURRENT STATE               ERROR               PORTS
6hhuf528spdw        whoami.1            jwilder/whoami:latest   swarm-manager       Running             Running about an hour ago                                                
bw90ld3onwya        whoami.2            jwilder/whoami:latest   swarm-worker1       Running             Running 42 seconds ago                         

可以看到,service被分别部署到了swarm-manager和swarm-worker1上。 

在swarm-worker1上查看:

iie4bu@swarm-worker1:~$ docker container ls
CONTAINER ID        IMAGE                     COMMAND             CREATED             STATUS                       PORTS                                                          NAMES
5559895ccaea        jwilder/whoami:latest     "/app/http"         2 minutes ago       Up 2 minutes                 8000/tcp                                                       whoami.2.bw90ld3onwyabn3vv9rfoj9qf

发现确实,在swarm-worker1中有了一个whoami容器。

然后我们在client中再去ping一下whoami

/ # ping whoami
PING whoami (10.0.2.5): 56 data bytes
64 bytes from 10.0.2.5: seq=0 ttl=64 time=0.083 ms
64 bytes from 10.0.2.5: seq=1 ttl=64 time=0.073 ms
64 bytes from 10.0.2.5: seq=2 ttl=64 time=0.072 ms
64 bytes from 10.0.2.5: seq=3 ttl=64 time=0.072 ms
64 bytes from 10.0.2.5: seq=4 ttl=64 time=0.072 ms
64 bytes from 10.0.2.5: seq=5 ttl=64 time=0.072 ms

可以看到:我们在ping whoami 的时候可以ping通,而且地址还是10.0.2.5 是不是很奇怪?我们现在有两个whoami,它ping的一个地址到底是谁的呢?

其实ip地址10.0.2.5并不是我们任何一个whoami service容器的地址,而是一个VIP(虚拟IP)。如何证明?

使用nslookup命令可以证明。这个命令就是用来查询DNS的。可以去DNS服务器上查询一个DNS name。

 例如通过nslookup查询百度的IP地址:

iie4bu@swarm-manager:~$ nslookup www.baidu.com
Server:		8.8.8.8
Address:	8.8.8.8#53

Non-authoritative answer:
www.baidu.com	canonical name = www.a.shifen.com.
www.a.shifen.com	canonical name = www.wshifen.com.
Name:	www.wshifen.com
Address: 103.235.46.39

然后我们在client容器中运行nslookup。

/ # nslookup whoami
Server:		127.0.0.11
Address:	127.0.0.11:53

Non-authoritative answer:

*** Can't find whoami: No answer

/ # 

127.0.0.11为DNS服务器的地址,这个DNS服务器是有cluster维护的,而我们现在并没有返回正确结果,原因是新版busybox镜像的问题,使用旧版本即可,如1.28.3版。
删除busybox服务后,重新运行:

iie4bu@swarm-manager:~$ docker service rm client
client
iie4bu@swarm-manager:~$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                   PORTS
9i6wz6cg4koc        whoami              replicated          2/2                 jwilder/whoami:latest   *:8000->8000/tcp
iie4bu@swarm-manager:~$ docker service create --name client -d --network my-demo busybox:1.28.3 sh -c "while true; do sleep 3600; done"
h4wlczp85sw5ez5op51plfazn
overall progress: 1 out of 1 tasks 
1/1: running   [==================================================>] 
verify: Service converged 

再次进入到容器中:

iie4bu@swarm-worker2:~$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
633ddfc082b9        busybox:1.28.3      "sh -c 'while true; …"   53 seconds ago      Up 52 seconds                           client.1.3iv3gworpyr5vdo0h9eortlw0
iie4bu@swarm-worker2:~$ docker exec -it 633 sh
/ # 

然后执行nslookup:

iie4bu@swarm-worker2:~$ docker exec -it 633 sh
/ # nslookup whoami
Server:    127.0.0.11
Address 1: 127.0.0.11

Name:      whoami
Address 1: 10.0.2.5

返回了whoami的IP地址是10.0.2.5,但是这个地址既不是swarm-manager上的ip又不是swarm-worker1上面的ip。

看一下swarm-manager上面的whoami 的 ip:

iie4bu@swarm-manager:~$ docker container ls
CONTAINER ID        IMAGE                   COMMAND             CREATED             STATUS              PORTS               NAMES
cc9f97cc5056        jwilder/whoami:latest   "/app/http"         About an hour ago   Up About an hour    8000/tcp            whoami.1.6hhuf528spdw9j9pla7l3tv3t
iie4bu@swarm-manager:~$ docker exec -it cc9f97cc5056 sh
/app # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet 10.255.0.168/32 brd 10.255.0.168 scope global lo
       valid_lft forever preferred_lft forever
    inet 10.0.2.5/32 brd 10.0.2.5 scope global lo
       valid_lft forever preferred_lft forever
18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue state UP 
    link/ether 02:42:0a:ff:00:05 brd ff:ff:ff:ff:ff:ff
    inet 10.255.0.5/16 brd 10.255.255.255 scope global eth0
       valid_lft forever preferred_lft forever
20: eth1@if21: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.3/16 brd 172.18.255.255 scope global eth1
       valid_lft forever preferred_lft forever
23: eth2@if24: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue state UP 
    link/ether 02:42:0a:00:02:07 brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.7/24 brd 10.0.2.255 scope global eth2
       valid_lft forever preferred_lft forever
/app # 

在swarm-worker2上面查看一下whoami的ip:

iie4bu@swarm-worker1:~$ docker exec -it 5559895ccaea sh
/app # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
20: eth0@if21: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue state UP 
    link/ether 02:42:0a:ff:00:06 brd ff:ff:ff:ff:ff:ff
    inet 10.255.0.6/16 brd 10.255.255.255 scope global eth0
       valid_lft forever preferred_lft forever
22: eth2@if23: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:ac:13:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.3/16 brd 172.19.255.255 scope global eth2
       valid_lft forever preferred_lft forever
24: eth1@if25: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue state UP 
    link/ether 02:42:0a:00:02:0a brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.10/24 brd 10.0.2.255 scope global eth1
       valid_lft forever preferred_lft forever
/app # 

发现都没有10.0.2.5IP地址。

然后在client中使用命令nslookup tasks.whoami

/ # nslookup tasks.whoami
Server:    127.0.0.11
Address 1: 127.0.0.11

Name:      tasks.whoami
Address 1: 10.0.2.10 whoami.2.bw90ld3onwyabn3vv9rfoj9qf.my-demo
Address 2: 10.0.2.7 whoami.1.6hhuf528spdw9j9pla7l3tv3t.my-demo
/ # 

我们看到tasks.whoami一共有两个地址,一个是10.0.2.7,一个是10.0.2.10,跟我们上面的container中查看的一致。这才是真正的ip地址。所以通过tasks.whoami可以查看到真正的容器地址。

如果我们把whoami横向扩展成3个,会怎么样?

在swarm-manager中设置scale whoami=3

iie4bu@swarm-manager:~$ docker service scale whoami=3
whoami scaled to 3
overall progress: 3 out of 3 tasks 
1/3: running   [==================================================>] 
2/3: running   [==================================================>] 
3/3: running   [==================================================>] 
verify: Service converged
iie4bu@swarm-manager:~$ docker service ps whoami
ID                  NAME                IMAGE                   NODE                DESIRED STATE       CURRENT STATE               ERROR               PORTS
6hhuf528spdw        whoami.1            jwilder/whoami:latest   swarm-manager       Running             Running 2 hours ago                                                       
bw90ld3onwya        whoami.2            jwilder/whoami:latest   swarm-worker1       Running             Running about an hour ago                       
9idgk9jbrlcm        whoami.3            jwilder/whoami:latest   swarm-worker2       Running             Running 49 seconds ago

现在whoami位于三个容器,分别位于swarm-manager、swarm-worker1、swam-worker2。

这时返回到client,在执行nslookup tasks.whoami

/ # nslookup tasks.whoami
Server:    127.0.0.11
Address 1: 127.0.0.11

Name:      tasks.whoami
Address 1: 10.0.2.10 whoami.2.bw90ld3onwyabn3vv9rfoj9qf.my-demo
Address 2: 10.0.2.13 whoami.3.9idgk9jbrlcm3ufvkmbmvv2t8.my-demo
Address 3: 10.0.2.7 whoami.1.6hhuf528spdw9j9pla7l3tv3t.my-demo

可以看到又多了一条记录。

新增的10.0.2.13就是新增的service的地址,可以验证一下,在swarm-worker:

iie4bu@swarm-worker2:~$ docker exec -it f47e05019fd9 sh
/app # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet 10.255.0.168/32 brd 10.255.0.168 scope global lo
       valid_lft forever preferred_lft forever
    inet 10.0.2.5/32 brd 10.0.2.5 scope global lo
       valid_lft forever preferred_lft forever
24: eth2@if25: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue state UP 
    link/ether 02:42:0a:00:02:0d brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.13/24 brd 10.0.2.255 scope global eth2
       valid_lft forever preferred_lft forever
26: eth1@if27: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:ac:12:00:04 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.4/16 brd 172.18.255.255 scope global eth1
       valid_lft forever preferred_lft forever
28: eth0@if29: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue state UP 
    link/ether 02:42:0a:ff:00:07 brd ff:ff:ff:ff:ff:ff
    inet 10.255.0.7/16 brd 10.255.255.255 scope global eth0
       valid_lft forever preferred_lft forever

可以看到10.0.2.13。

实际上任何一个连到my-demo网络上的容器执行nslookup都会的到这个结果。

总结:

    在client中ping whoami,返回的ip是10.0.2.5

    而使用命令nslookup tasks.whoami 返回的ip并没有10.0.2.5。

 ip:10.0.2.5就是虚拟ip。

这个虚拟IP是不会变的。因为service的数量会有变化的。而虚拟的ip与实际的container ip有一个map关系。通过这个map关系去找到了这个虚拟ip

访问whoami这个service具体情况 

因为我们的busybox没有装curl,所以我们用wget模拟请求。

在client container中访问whoami:8000

/ # wget whoami:8000
Connecting to whoami:8000 (10.0.2.5:8000)
index.html           100% |*******************************|    17   0:00:00 ETA
/ # more index.html 
I'm f47e05019fd9
/ # 

可以正常访问到。其中f47e05019fd9是container的id。

将index.html删掉,然后在访问一遍whoami:

/ # wget whoami:8000
Connecting to whoami:8000 (10.0.2.5:8000)
index.html           100% |*******************************|    17   0:00:00 ETA
/ # more index.html 
I'm cc9f97cc5056
/ # 

发现container的id变为cc9f97cc5056。

可以说每次访问whoami:8000返回内容都是不一样的,也就是说我们做了一个负载均衡。也就是说10.0.2.5背后其实是 10.0.2.10、10.0.2.13和10.0.2.7这三个web服务器。每次访问10.0.2.5,都会做一个负载均衡。第一次是 10.0.2.10给的响应,第二次是10.0.2.13依次循环。

这些负载均衡、VIP都是通过LVS帮我们实现的。

1c00d86652a4e6bf24539cb1b9e6970ac6a.jpg

ed4f82893f6847a74804c3038c465feef9d.jpg

简单总结一下:

8f88d864622f16f1608a8d04d84e76cc31e.jpg

我们这节讲的其实就是Routing Mesh。这一节讲的是Internal 网络。

Internal网络:我们在swarm中连接到同一个overlay网络中的容器是通过service name通信的,然后这个service name对应的ip地址并不是容器的具体ip地址,而是一个虚拟ip,而且如果容器做了scale,那么通过VIP去访问服务的时候Internal会帮我们做负载均衡。

Ingress网络:如果service有绑定端口,比如说我们本节的whoami绑定的8000端口,上一节的wordpress绑定的80端口,虽然这个service在cluster中的部分节点中运行,但是可以在swarm的任何节点通过对应的端口访问到服务,这就是Ingress Routing Mesh。

426c1cdb465904e99211f37546b92c7f196.jpg

下一节详细介绍Ingress网络。

 

转载于:https://my.oschina.net/duanvincent/blog/3071202

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值