首先创建swarm集群:
docker swarm init 并在work节点上执行docker swarm join 加入集群
创建网络:docker netwrok create mynet -d overlay
创建服务:docker service create --name web --network mynet -p 8080:80 --replicas 2 nginx:latest
注意:如果在work节点无法下载镜像,会导致work节点启动不起来
查看容器状态
查看网络:
主节点:
work节点:
他们是一样的
服务启动起来之后,在node1 和node2上都可以访问到容器这个可以理解,但是我们访问node3 ,也能访问到容器
在node1 和node2上,有容器运行,并且都监听了8080 端口:
在node3 上,没有容器运行,但是也监听了8080 端口:
那么我们分别看下node1,和node3 的iptables:
在manager节点上查看iptables:
这里需要注意的是最后有个 DOCKER-INGRESS: 吧所有的8080端口的包都转发致了172.18.0.2:8080端口
这里还需要注意一点是POSTROUTING里面:有一条 docker_gwbridge网桥的流量都nat转换为本机ip也就是通过nat修改了地址的(MASQUERADE)
那我们在work节点看下有没有:
也是一样,都吧8080端口的包转发到了172.18.0.2:8080
那么这个172.18.0.2是什么地址呢:
我们通过ifconfig 可以看到 docker_gwbridge的网段是172.18.0.2
然后查看网桥
上面插了一个网卡:veth84f003c
我们查看docker的网络详情
docker_gwbridge上面插了一个容器网卡, ingress-sbox 这个其实是一个网络命名空间:
通过docker run -it --rm -v /var/run/docker/netns:/netns --privileged=true nicolaka/netshoot nsenter --net=/netns/ingress_sbox sh进入命名空间
这个命名空间有两个网卡:
一个是10.255.0.5/16 一个是172.18.0.2/16 而宿主机上172.18.0.2则是docker_gwbridge的网段,而第一个地址其实是连接到了ingress 这个后面说
并且这个172.18.0.2网络地址,正是宿主机8080端口转发的地址.
这个网络命名空间里面:将进来的8080端口的统一做了一个MARK,值为0x101也就是十进制的257
而下面的ipvsadm显示将257的做了一个负载均衡
那么也就是说,外面进来的地址,通过docker_gwbridge转发到了ingress_bos ,然后通过ipvs做了一个负载均衡
在运行了服务容器的节点上进入ingress_box命名空间查看:
也是一样的结果
但是这里有个问题:负载均衡的地址是10.255.0.7和10.255.0.8 这两个地址到底是什么,还有就是上面的ingress 这个网络到底是啥?
首先这里在提一下ingress ,这是一个网桥,网桥的作用就是根据mac地址进行请求转发,比如docker0网桥,单机docker容器的通信就是靠他来进行转发,容器的网络设备是一对veth设备,
一端在容器内,一段插到docker0,这样,容器向容器内网络命名空间网络设备发送的包都会出现在docker0 上,而docker0根据ip地址和mac地址进行转发,就实现了容器间的通信
那么这里的ingress网络,是一个overlay网络,overlay是一个覆盖网络,基于linux的vxlan在三层网络上组成的二层网络,我们看到docker_gwbridge的驱动是local,也就是说他是一个本地的网络设备,
而ingress是overlay网络,也就是说我们在本地找不到这个设备,但是到达ingress的请求都会被封vxlan的请求头以及解封vxlan的请求,进行转发
我们查看ingress详情:
可以看到,他的网段是10.255.0.0/16而接入他的有两个容器,一个是ingress-box,一个是web.2的一个容器,他的ip是10.255.0.8,下面的peers是集群的所有节点
那么也就是说,接入这个ingress网络的有两个容器,一个是ingress-sbox ,一个是web.2容器
我们的web.2正是在node1 节点上,而如果我们在node2上查看ingress详情:
如果我们查看docker_gwbridge详情可以看到上面是有一个ingress-sbox的而他的地址,正是172.18.0.2,并且在所有节点上,这个地址都是不变的,下面分别是node1和node2
那么到此为止:
外面来的请求会根据iptables规则,转发到172.18.0.2来处理,172.18.0.2则是ingress_sbox网络空间,这个会根据端口来吧流量打上标签,然后根据标签进行负载均衡转发
转发的地址则是各个节点的ingress地址,
172.168.137.0/24 网段是宿主机网段
172.18.0.0/16网段是docker_gwbridge网段
10.255.0.0/16 是ingress网段
10.0.0.0/24 是mynet网段
ingress_sbox有两个网卡,一个插在docker_gwbridge上,一个插在ingress上
而每个容器也有两个网卡,一个插在docker_gwbridge上,一个插在mynet上
IP 情况:
ingress_sbox:
宿主机 |
192.168.137.131 |
192.168.137.132 |
192.168.137.133 |
docker_gwbridge |
172.18.0.1/16 |
172.18.0.1/16 |
172.18.0.1/16 |
ingress |
10.255.0.1/16 |
10.255.0.1/16 |
10.255.0.1/16 |
mynet |
10.0.0.1/16 |
10.0.0.1/16 |
10.0.0.1/16 |
ingress_sbox |
10.255.0.3/16 172.18.0.2/16 |
10.255.0.4/16 172.18.0.2/16 |
10.255.0.5/16 172.18.0.2/16 |
web |
10.255.0.2/16 10.0.0.4/24 |
10.255.0.7/16 10.0.0.3/24 |
|
ip route(宿主机) |
172.18.0.0/16 docker_gwbridge处理 |
172.18.0.0/16 docker_gwbridge处理 |
172.18.0.0/16 docker_gwbridge处理 |
ip tables(宿主机 nat) |
tcp dpt:8080 to 172.18.0.2:8080 |
tcp dpt:8080 to 172.18.0.2:8080 |
tcp dpt:8080 to 172.18.0.2:8080 |
ip route(ingress sbox) |
10.255.0.0/16 -> eth0(10.255.0.3) 172.18.0.0/16 -> eth1(172.18.0.2) |
10.255.0.0/16 -> eth0(10.255.0.4) 172.18.0.0/16 -> eth1(172.18.0.2) |
10.255.0.0/16 -> eth0(10.255.0.5) 172.18.0.0/16 -> eth1(172.18.0.2) |
ip tables(ingress sbox) |
tcp dpt:8080 MARK set 0x100 dst 10.255.0.6 MARK set 0x100 |
tcp dpt:8080 MARK set 0x100 dst 10.255.0.6 MARK set 0x100 |
tcp dpt:8080 MARK set 0x100 dst 10.255.0.6 MARK set 0x100 |
ipvsadm(ingress sbox) |
256 -> 10.255.0.2 & 10.255.0.7 |
256 -> 10.255.0.2 & 10.255.0.7 |
256 -> 10.255.0.2 & 10.255.0.7 |
那么在mynet网域内,访问172.18.0.2则会进入到ingress_sbox,然后进行标记负载均衡分发
外网访问只能通过宿主机的映射端口来进行访问,宿主机收到请求走iptables请求转发,给172.18.0.2那么又是走到上面的逻辑
那么留下一个问题:mynet是如何处理请求的:
请求交给172.18.0.2之后,会通过ipvs进行负载均衡,负载的节点ip是10.255.0.2 & 10.255.0.7,这个地址是mynet的地址,所以这个流量会根据iproute规则给mynet处理,mynet则是通过vxlan来进行分包发送给对应的地址,
也就是说容器启动后实际有三个网卡,一个连接到ingress 用于容器间通信,一个连接到docker_gwbridge用于访问外网,一个是加入了我们自己创建的网络mynet也是用于荣期间通信,ingress和mynet的区别是 mynet存在dns解析即服务发现功能
容器上有三个网络设备:
一个是连接docker_gwbridge的veth设备,用于容器访问外网
一个是接入mynet的 vtep 设备(vxlan),用于通过服务名访问(即服务发现),比如两个service, web 和redis,如果他们需要互相访问,则可以加入到同一个网络,然后直接通过服务名即可访问
一个是接入ingress的vtep设备(vxlan),用于容器之间的访问,以及外网访问的负载均衡
那vxlan是如何工作的呢:
这里借一张图:
实例文章:https://www.cnblogs.com/lkun/p/8034039.html