一,swarm的三个网络
名称 | 类型 | 注释 |
---|---|---|
docker_gwbridge | bridge | none |
ingress | overlay | none |
<custom-network> | overlay | none |
Docker中内置的网络模式包括如下几种:
bridge 我们基于该网络模式创建了mynet网络 host 本地网络模式 macvlan 这个模式貌似是最新加的 null 无网络 overlay 用于swarm集群中容器的跨主机网络访问
docker_gwbridge和ingress是当用户执行了docker swarm init/connect之后自动创建的。
docker_gwbridge是bridge类型的负责本机container和主机直接的连接。docker_gwbridge是一种桥接网络,将 overlay 网络(包括 ingress 网络)连接到一个单独的 Docker 守护进程的物理网络。默认情况下,服务正在运行的每个容器都连接到本地 Docker 守护进程主机的 docker_gwbridge 网络。docker_gwbridge 网络在初始化或加入 Swarm 时自动创建。大多数情况下,用户不需要自定义配置,但是 Docker 允许自定义。 ingress负责service在多个主机container之间的路由。ingress network 是一个特殊的 overlay 网络,用于服务节点间的负载均衡。当任何 Swarm 节点在发布的端口上接收到请求时,它将该请求交给一个名为 IPVS 的模块。IPVS 跟踪参与该服务的所有IP地址,选择其中的一个,并通过 ingress 网络将请求路由到它。初始化或加入 Swarm 集群时会自动创建 ingress 网络,大多数情况下,用户不需要自定义配置,但是 docker 17.05 和更高版本允许你自定义。 <custom-network>
是用户自己创建的overlay网络,通常我们都需要创建自己的network并把service挂在上面。
Overlay networks 管理 Swarm 中 Docker 守护进程间的通信。你可以将服务附加到一个或多个已存在的 overlay 网络上,使得服务与服务之间能够通信。
二,swarm service的路由
swarm service的路由办法通常有两种,VIP和DSN
(一) service路由之:虚拟IP
这是缺省情况设置,当用户创建service的时候,这个service会被分配一个 VIP,然后每一个具体的container都有一个独立的IP,ingress会负责从VIP到各个container之间的路由。
Overlay 网络创建及部署
docker network create --driver overlay mynet
docker@manager1:~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
669d98d758ac bridge bridge local
042df78b01ec docker_gwbridge bridge local
1c27fcf531c2 host host local
95e47qzos7zn ingress overlay swarm
pybpdb2fibky my-network overlay swarm
i5xm0y9n835s mynet overlay swarm
37d3b44c34e2 none null local
复制
创建新服务并使用 overlay 网络
创建两个service
docker@manager1:~$ docker service create --replicas 2 --network mynet --name my-web nginx
lpgc43imsl1s3iocgcpy3dhkm
overall progress: 2 out of 2 tasks
1/2: running [==================================================>]
2/2: running [==================================================>]
verify: Service converged
docker@manager1:~$ docker service create --replicas 1 --network mynet --name my-box busybox:1.28.3 sleep 3000
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
复制
部署完成之后 查看 my-web 服务的虚拟IP 地址
docker service inspect my-web -f "{{ .Endpoint.VirtualIPs }}"
复制
docker@manager1:~$ docker service inspect my-web -f "{{ .Endpoint.VirtualIPs }}"
[{pybpdb2fibkyk9jklcjqkrch7 10.0.1.2/24}]
docker@manager1:~$ docker service inspect my-box -f "{{ .Endpoint.VirtualIPs }}"
[{pybpdb2fibkyk9jklcjqkrch7 10.0.1.19/24}]
复制
查看容器IP地址 和 service 的VIP
docker@manager1:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fcd9f0e5d0f2 nginx:latest "nginx -g 'daemon of…" 8 hours ago Up 8 hours 80/tcp my-web.2.ssl05byx4s3kr4dku1mw79f6f
docker@manager1:~$ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-web.2.ssl05byx4s3kr4dku1mw79f6f
10.0.1.8
复制
docker@worker1:~$ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-box.1.vc14enzddj8c88rykqszf38fe
10.0.1.20
docker@worker1:~$ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-web.1.50zdanlgukvwxq2fujtcg9o4n
10.0.1.7
复制
docker@worker1:~$ docker exec -it ae92907ac302 sh
/ #
/ #
/ # nslookup my-web
Server: 127.0.0.11
Address 1: 127.0.0.11
Name: my-web
Address 1: 10.0.1.2 bogon # my-web 的虚拟IP
/ # nslookup tasks.my-web
Server: 127.0.0.11
Address 1: 127.0.0.11
Name: tasks.my-web # 返回服务的容器IP地址
Address 1: 10.0.1.8 my-web.2.ssl05byx4s3kr4dku1mw79f6f.my-network
Address 2: 10.0.1.7 my-web.1.50zdanlgukvwxq2fujtcg9o4n.my-network
/ # nslookup my-box # 返回my-box服务的VIP
Server: 127.0.0.11
Address 1: 127.0.0.11
Name: my-box
Address 1: 10.0.1.19 bogon
/ # nslookup tasks.my-box
Server: 127.0.0.11
Address 1: 127.0.0.11
Name: tasks.my-box
Address 1: 10.0.1.20 ae92907ac302
复制
将现有服务连接到 overlay 网络
docker service update --network-add my-network my-web
复制删除正在运行的服务网络连接
docker service update --network-rm my-network my-web
复制
从这个例子我们可以看到:
service my-web的虚拟IP是10.0.1.2 它有两个containers,IP分别是:10.0.1.7 和 10.0.1.8 127.0.0.11是swarm内置的DSN服务器,用来解析service名字到IP地址
我们再进入container看看:
docker@worker1:~$ docker exec -it 29cce8d4f412 sh
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:0A:00:01:15
inet addr:10.0.1.21 Bcast:10.0.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
eth1 Link encap:Ethernet HWaddr 02:42:AC:12:00:04
inet addr:172.18.0.4 Bcast:172.18.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:11 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:866 (866.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
复制
每一个container有两块网卡:
eth0: 10.0.1.3 这就是我们前面看到的service container IP地址,是属于网络my-network的。 eth1: 172.18.0.4,这是另一个网络地址;是谁的呢, 是网络docker_gwbridge。(另外bridge网络使用的是172.17网段) 也就是说每一个container属于两个网络,my-network和docker_gwbridge,分别用来service路由,和连接主机网络。
补充一点网卡eth1: 172.18.0.4,对应的网关地址是172.18.0.1,那个这个网关地址172.18.0.1是谁呢,它就是主机网络上的docker_gwbridge,在主机上运行ifconfig可以看到:
docker@worker1:~$ ifconfig
docker0 Link encap:Ethernet HWaddr 02:42:F1:8A:BC:80
inet addr:172.17.0.1 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
docker_gwbridge Link encap:Ethernet HWaddr 02:42:B0:55:BE:A8
inet addr:172.18.0.1 Bcast:172.18.255.255 Mask:255.255.0.0
inet6 addr: fe80::42:b0ff:fe55:bea8/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:41 errors:0 dropped:0 overruns:0 frame:0
TX packets:126 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:2041 (1.9 KiB) TX bytes:9471 (9.2 KiB)
复制
bridge网络的网段地址从172.17.X.X/16开始,第一个内置的docker0使用了172.17.X.X,后面每新增一个bridge网络就新增一个网地址,172.18.X.X, 172.19.X.X,。。。
至此两个bridge网络都比较清楚了。
另外如果发布service的时候指定了主机端口映射,那么container里面会有三块网卡分别属于:
1. <my-network>
docker_gwbridge ingress, 其网段是10.255.X.X,每一个service在ingress上也有一个VIP,例如VIP=10.255.0.2,对映两个container:10.255.0.3和10.255.0.4
遇到的一些问题:docker busybox服务中nslookup命令报错
docker@worker1:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
275444f7dbac busybox:latest "sleep 3000" 32 minutes ago Up 32 minutes my-box.1.lz7cd0j5h86m4h353rjt21wcy
fe7281a21572 nginx:latest "nginx -g 'daemon of…" 8 hours ago Up 8 hours 80/tcp my-web.1.50zdanlgukvwxq2fujtcg9o4n
docker@manager1:~$ docker exec -it my-box.1.zuga19xe4yau0mtgpuos936zs bin/sh
/ #
/ # nslookup my-web
Server: 127.0.0.11
Address: 127.0.0.11:53
Non-authoritative answer:
*** Can't find my-web: No answer
复制
新版的busybox好像有问题,使用旧版的busybox即可
docker@manager1:~$ docker service create --replicas 1 --network mynet --name my-box busybox:1.28.3 sleep 3000
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
复制
(二) service路由之:DSN轮询
$ docker service create --replicas 2 --network my-network --name my-dnsrr-web --endpoint-mode dnsrr richarvey/nginx-php-fpm
复制
dns方式是不允许有-p这个参数的,同时vip是 创建VIP类型,也可以不加--endpoint-mode参数。
先看两个容器的IP地址:
docker@manager1:~$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
r6agac07qrx4 my-dnsrr-web replicated 2/2 richarvey/nginx-php-fpm:latest
docker@manager1:~$ docker service ps my-dnsrr-web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
i92e357ahd5l my-dnsrr-web.1 richarvey/nginx-php-fpm:latest worker1 Running Running 20 seconds ago
juqnhkk8e4fb my-dnsrr-web.2 richarvey/nginx-php-fpm:latest manager1 Running Running 19 seconds ago
docker@manager1:~$
docker@manager1:~$
docker@manager1:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3a47e1aacdc6 richarvey/nginx-php-fpm:latest "docker-php-entrypoi…" 24 seconds ago Up 23 seconds 80/tcp, 443/tcp, 9000/tcp my-dnsrr-web.2.juqnhkk8e4fbnz7bs1xpzbz42
docker@manager1:~$ docker exec -it my-dnsrr-web.2.juqnhkk8e4fbnz7bs1xpzbz42 bash
bash-5.0# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:0A:00:01:83
inet addr:10.0.1.131 Bcast:10.0.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
eth1 Link encap:Ethernet HWaddr 02:42:AC:12:00:03
inet addr:172.18.0.3 Bcast:172.18.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:9 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:726 (726.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
bash-5.0#
复制
docker@worker1:~$ docker exec -it my-dnsrr-web.1.i92e357ahd5lz91lseal6aa00 bash
bash-5.0# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:0A:00:01:82
inet addr:10.0.1.130 Bcast:10.0.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
eth1 Link encap:Ethernet HWaddr 02:42:AC:12:00:03
inet addr:172.18.0.3 Bcast:172.18.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:10 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:796 (796.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
复制
my-dnsrr-web.1.i92e357ahd5lz91lseal6aa00
eth0 10.0.1.130 eth1 172.18.0.3
my-dnsrr-web.2.juqnhkk8e4fbnz7bs1xpzbz42
eth0 10.0.1.131 eth1 172.18.0.3
查看DNS解析结果(轮询访问)
bash-5.0# ping my-dnsrr-web
PING my-dnsrr-web (10.0.1.131): 56 data bytes
64 bytes from 10.0.1.131: seq=0 ttl=64 time=0.039 ms
64 bytes from 10.0.1.131: seq=1 ttl=64 time=0.074 ms
64 bytes from 10.0.1.131: seq=2 ttl=64 time=0.071 ms
^C
--- my-dnsrr-web ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.039/0.061/0.074 ms
bash-5.0# ping my-dnsrr-web
PING my-dnsrr-web (10.0.1.130): 56 data bytes
64 bytes from 10.0.1.130: seq=0 ttl=64 time=1.029 ms
64 bytes from 10.0.1.130: seq=1 ttl=64 time=0.894 ms
64 bytes from 10.0.1.130: seq=2 ttl=64 time=0.846 ms
64 bytes from 10.0.1.130: seq=3 ttl=64 time=1.233 ms
复制
nslookup访问
bash-5.0# nslookup my-dnsrr-web
nslookup: can't resolve '(null)': Name does not resolve
Name: my-dnsrr-web
Address 1: 10.0.1.131 3a47e1aacdc6
Address 2: 10.0.1.130 my-dnsrr-web.1.i92e357ahd5lz91lseal6aa00.my-network
bash-5.0#
复制
三、发布服务端口
当你创建一个服务时, 你可以使用--publish参数来发布端口。
# docker service create \
--name <Service-Name> \
--publish <Publish-Port>:<Target-Port> \
<Docker Image>
复制
<目标端口>为Docker容器中所监听的端口,<发布端口>为Swarm集群中使得服务可以访问的端口。
例如, 在Swarm集群中发布Nginx应用服务, 将容器中的80端口映射为Swarm集群的8080端口。
$ docker service create \
--name my-web \
--publish 8080:80 \
--replicas 2 \
nginx
复制
当你在任何节点上访问8080端口时,Swarm集群的负载均衡会将您的请求路由至活动容器中。
Swarm集群的路由网络在发布的端口上监听分配给该节点的任何IP地址。对于外部可路由的IP地址,端口可从主机外部获得。对于其他的IP地址,只能从主机中访问。
Ingress Network 使用以下命令可以为已经发布的服务发布端口:
$ docker service update \
--publish-add <PUBLISHED-PORT>:<TARGET-PORT> \
<SERVICE>
复制
使用docker service inspect查看服务端口。
# docker service inspect --format="" nginx-service
复制
仅发布TCP端口或仅发布UDP端口
默认情况下, 所发布的端口一般为TCP端口。你可以专门指定发布UDP端口,而不是TCP或之外的端口。当发布TCP和UDP端口时,Docker 1.12.2版本和早前版本需要为TCP端口指定后缀/tcp。后缀为可选的参数。
仅发布TCP端口
# docker service create --name dns-cache -p 53:53 dns-cache
复制
或
# docker service create --name dns-cache -p 53:53/tcp dns-cache
复制
发布TCP和UDP端口
# docker service create --name dns-cache -p 53:53/tcp -p 53:53/udp dns-cache
复制
仅发布UDP端口
# docker service create --name dns-cahce -p 53:53/udp dns-cache
复制
配置外部负载均衡
可通过配置外部负载均衡实现Swarm集群的服务路由。例如, 使用HAProxy实现已发布端口8080的Nginx服务的负载均衡。
Load Balance 在这种情况下, 必须在Swarm集群节点和HAProxy之间打开8080端口,Swarm集群节点可以驻留在代理服务器可以访问的专用网络上,但不能公开访问。
我们可以将负载均衡配置为Swarm集群中的每个节点之间的请求平衡,即使该 节点上没有计划任务。例如, 我们可以在/etc/haproxy/haproxy.cfg
中配置HAProxy的负载均衡。
global
log dev/log local0
log dev/log local1 notice
...snip...
# Configure HAProxy to listen on port 80
frontend http_front
bind *:80
stats uri /haproxy?stats
default_backend http_back
# Configure HAProxy to route requests to swarm nodes on port 8080
backend http_back
balance roundrobin
server node1 192.168.99.100:8080 check
server node2 192.168.99.101:8080 check
server node3 192.168.99.102:8080 check
复制
当您在端口80上访问HAProxy负载均衡服务时,它会将请求转发到Swarm集群中的节点。Swarm集群路由网络将请求路由到活动任务中。如果由于任何原因swarm调度程序将任务分派给不同的节点,则不需要重新配置负载均衡。
https://www.linuxidc.com/Linux/2017-11/148370.htm[1]
https://www.jianshu.com/p/cacdd5ff0f14[2]
参考资料
https://www.linuxidc.com/Linux/2017-11/148370.htm: https://www.linuxidc.com/Linux/2017-11/148370.htm
[2]https://www.jianshu.com/p/cacdd5ff0f14: https://www.jianshu.com/p/cacdd5ff0f14