docker-overylay
overlay网络转发原理
- 创建好docker-overlay类型的容器后,docker会创建一个命名空间,里面会有一个br0网卡
- 而这个命名空间内veth0桥接着br0,它的作用是和容器的eth0进行veth pair连接通信,
- 这个命名空间内还有一个vxlan0网卡,它的作用是进行跨主机通信,只要两端的 命名空间内的 vxlan_id相同就可以通信
- 要相同的 id才能通信,那么就需要consul来同步两台docker主机的数据了,也就是说,只要有consul,其中一台docker创建一个块新的网卡,马上就会同步到,第二台主机中,两台主机的容器只要使用相同的网卡就能够进行通信了
准备overlay环境
做之前,需要跨网络的其中一台主机需要下载consul镜像
docker1主机下载镜像
[root@localhost ~]# docker pull progrium/consul
因为consul在主机间传输数据依靠主机名来做,所以我们先改一下两台的主机名,以便区分
[root@localhost ~]# hostname docker1 [root@localhost ~]# bash [root@docker1 ~]# # docker2 [root@localhost ~]# hostname docker2 [root@localhost ~]# bash [root@docker2 ~]#
两台主机放行端口
docker管理端口:2376/tcp 2376/udp
docker集群通信:2733/tcp 2733/udp
docker主机间通信:7946/tcp 7946/udp
docker overlay网络:4789/tcp 4789/udp
两台主机放行端口,打开路由转发
# 两台docker都要放行
[root@docker1 ~]# firewall-cmd --add-port=2733/tcp --permanent
[root@docker1 ~]# firewall-cmd --add-port=2733/udp --permanent
[root@docker1 ~]# firewall-cmd --add-port=2376/udp --permanent
[root@docker1 ~]# firewall-cmd --add-port=2376/tcp --permanent
[root@docker1 ~]# firewall-cmd --add-port=7946/tcp --permanent
[root@docker1 ~]# firewall-cmd --add-port=7946/udp --permanent
[root@docker1 ~]# firewall-cmd --add-port=4789/udp --permanent
[root@docker1 ~]# firewall-cmd --add-port=4789/tcp --permanent
[root@docker1 ~]# firewall-cmd --reload
[root@docker1 ~]# firewall-cmd --list-port
[root@localhost ~]# echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
[root@localhost ~]# sysctl -p
net.ipv4.ip_forward = 1
docker1运行consul
[root@docker1 ~]# docker run -d --restart always -p 8400:8400 -p 8500:8500 \
-p 8600:53/udp progrium/consul -server -bootstrap -ui-dir /ui
44bd33f2b9911b86c0479efb6169c39090b0503c28b9ff2c7edd32bed4cc7586
consul加入docker启动文件,让docker加入到consul
[root@docker1 ~]# vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376 --containerd=/run/containerd/containerd.sock --cluster-store=consul://192.168.100.211:8500 --cluster-advertise=ens33:2376
#--cluster-store 指定 consul 的地址。
#--cluster-advertise 告知 consul 自己的连接地址。
两台主机重启docker
# docker1重启
[root@docker1 ~]# systemctl daemon-reload
[root@docker1 ~]# systemctl restart docker
# docker2重启
[root@docker2 ~]# systemctl daemon-reload
[root@docker2 ~]# systemctl restart docker
- 打开浏览器,访问http://192.168.100.211:8500
- 找到以下两个节点,也就是docker1和docker2的ip:2376docker管理节点
创建overlay网络
- 需要先开启网卡的混杂模式
docker1
[root@docker1 ~]# ifconfig ens33 promisc [root@docker1 ~]# ip a | grep PROMISC 2: ens33: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP>
创建overylay网络
[root@docker1 ~]# docker network create --driver overlay --attachable ov_net1 a921406c8f1e6c3899b39c3ecc862d806107f7abbab4f93e9b529896dd23b66d # 默认情况下overlay只能用于docker swarm集群环境,使用--attachable可以在集群之外单独使用
查看创建成功的overlay网络
这个网卡是基于global(全局范围),也就是所有添加过consul端口的docker服务器都会创建这块网卡了# docker1 [root@docker1 ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 49670536d26e bridge bridge local dc8bfdbda464 host host local ecbab8a758e6 none null local a921406c8f1e ov_net1 overlay global # docker2 [root@docker2 ~]# docker network ls NETWORK ID NAME DRIVER SCOPE b1240547891e bridge bridge local fb1387ab7fc3 host host local a728ac0f7801 none null local a921406c8f1e ov_net1 overlay global
查看overlay的网络信息
[root@docker1 ~]# docker network inspect ov_net1 "Subnet": "10.0.0.0/24", # 网段 "Gateway": "10.0.0.1" # 网关
使用overlay网络运行容器
docker1
[root@docker1 ~]# docker run -itd --name bbox1 --network ov_net1 busybox
d74c87e1bd18e1624207d162f75cce6c13892d86a2c13e41bfdc225602eefd23
[root@docker1 ~]# docker exec bbox1 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
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
47: eth0@if48: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue
link/ether 02:42:0a:00:00:02 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.2/24 brd 10.0.0.255 scope global eth0
valid_lft forever preferred_lft forever
50: eth1@if51: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.2/16 brd 172.18.255.255 scope global eth1
valid_lft forever preferred_lft forever
- 会发现这个容器上除了lo网络还有两块网卡,eth0是overlay的网络的网卡,eth1默认路由要去使用的网卡
- 这时候docker还会多出一块网卡docker_gwbridge,用来为所有的连接到overlay网络的容器提供了访问外网的能力
[root@docker1 ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 49670536d26e bridge bridge local da3b5eb55718 docker_gwbridge bridge local dc8bfdbda464 host host local ecbab8a758e6 none null local a921406c8f1e ov_net1 overlay global
- 查看该网卡网段,与使用overlay网络的容器中是同一个网段,他本身也是一个overlay的网络
[root@docker1 ~]# docker network inspect docker_gwbridge "Subnet": "172.18.0.0/16", "Gateway": "172.18.0.1"
查看桥接网卡
- 注意看,veth20a968a被桥接在docker_gwbridge网卡上
[root@docker1 ~]# ip a ... 51: veth20a968a@if50: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker_gwbridge state UP group default link/ether ee:16:6e:72:93:e6 brd ff:ff:ff:ff:ff:ff link-netnsid 2 inet6 fe80::ec16:6eff:fe72:93e6/64 scope link valid_lft forever preferred_lft forever [root@docker1 ~]# brctl show bridge name bridge id STP enabled interfaces docker0 8000.024217bee795 no veth3ed4284 docker_gwbridge 8000.0242dbe46d3e no veth20a968a virbr0 8000.525400d7704d yes virbr0-nic
- docker_gwbridge就是为容器连接外网的
[root@docker1 ~]# docker exec bbox1 ping www.baidu.com PING www.baidu.com (61.135.169.121): 56 data bytes 64 bytes from 61.135.169.121: seq=0 ttl=127 time=4.131 ms
- 使用overlay网络的容器内映射端口也是没有问题的
[root@docker1 ~]# docker run -p 80:80 -d --network ov_net1 --name web1 httpd:latest 6b60e837f2b9984b0b9c0ae6ffa88e97f0ece4b8628a9fa5f4a64af9204aed44 [root@docker1 ~]# curl 192.168.100.211 <html><body><h1>It works!</h1></body></html>
跨主机容器通信
- 要开启路由转发
- 上面在docker1已经运行一个容器,现在在docker2中运行容器
docker2
- 使用overlay网络运行容器,并查看ip
[root@docker2 ~]# docker run -itd --name bbox2 --network on_net1 busybox 0723927f22394709d4d0deb20bae90a728dfd144083d474d65e058ac8e6731b6 [root@docker2 ~]# docker exec bbox2 ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 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 8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue link/ether 02:42:0a:00:00:04 brd ff:ff:ff:ff:ff:ff inet 10.0.0.4/24 brd 10.0.0.255 scope global eth0 valid_lft forever preferred_lft forever 11: eth1@if12: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff inet 172.18.0.2/16 brd 172.18.255.255 scope global eth1 valid_lft forever preferred_lft forever
- 通过ip发现,与docker1中同样的网卡网段,这由consul统一的数据分配的
- 尝试与docker1的bbox1容器通信,成功~
[root@docker2 ~]# docker exec bbox2 ping -c 2 bbox1 PING bbox1 (10.0.0.2): 56 data bytes 64 bytes from 10.0.0.2: seq=0 ttl=64 time=0.739 ms 64 bytes from 10.0.0.2: seq=1 ttl=64 time=1.134 ms --- bbox1 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.739/0.936/1.134 ms
- 所有在consul集群中同一overlay网络中的容器可以互相通信
- docker 会为每个 overlay 网络创建一个独立的 network namespace
docker网络的存放位置
[root@docker1 ~]# cd /var/run/docker/netns/ [root@docker1 netns]# ll total 0 -r--r--r--. 1 root root 0 Apr 2 22:09 1-a921406c8f -r--r--r--. 1 root root 0 Apr 2 22:22 244cf69f028a -r--r--r--. 1 root root 0 Apr 2 21:43 663ad80947aa -r--r--r--. 1 root root 0 Apr 2 22:09 e8cb0000018a
- 为了可让ip netns直接可以查看docker网络,做一个软链接
# docker1 and docker2 ln -s /var/run/docker/netns/ /var/run/netns
docker1
[root@docker1 ~]# ip netns 244cf69f028a (id: 3) e8cb0000018a (id: 2) 1-a921406c8f (id: 1) 663ad80947aa (id: 0)
docker2
[root@docker2 ~]# ip netns c8a0a325610f (id: 1) 1-a921406c8f (id: 0)
- 观察可以看到两台主机都有相同的网络1-a921406c8f,这就是两台主机所在的相同的网络命名空间,为什么说在同一个命名空间。
docker1
[root@docker1 ~]# docker exec bbox1 ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 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 47: eth0@if48: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue link/ether 02:42:0a:00:00:02 brd ff:ff:ff:ff:ff:ff inet 10.0.0.2/24 brd 10.0.0.255 scope global eth0 valid_lft forever preferred_lft forever 50: eth1@if51: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff inet 172.18.0.2/16 brd 172.18.255.255 scope global eth1 valid_lft forever preferred_lft forever
- 使用的overlay网卡是47@48的,再看物理机中是否有这样的网卡(没有)
- 那这两块网卡就在另外一个网络命名空间范围
进入ip netns查看到的相同命名空间可以看到如下
[root@docker1 ~]# ip netns exec 1-a921406c8f ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 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 2: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default link/ether 46:1f:b7:ea:30:4e brd ff:ff:ff:ff:ff:ff inet 10.0.0.1/24 brd 10.0.0.255 scope global br0 valid_lft forever preferred_lft forever 46: vxlan0@if46: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master br0 state UNKNOWN group default link/ether d6:9f:87:b1:84:32 brd ff:ff:ff:ff:ff:ff link-netnsid 0 48: veth0@if47: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master br0 state UP group default link/ether 46:1f:b7:ea:30:4e brd ff:ff:ff:ff:ff:ff link-netnsid 1 53: veth1@if52: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master br0 state UP group default link/ether 56:41:d1:39:8b:e8 brd ff:ff:ff:ff:ff:ff link-netnsid 2
- 再来看47@48桥接在这个命名空间内br0的网卡上,可以看到上方br0也是10网段,还存在一个vxlan0
- 也就是说 vxlan0是跨主机通信的网卡,而veth0是访问外网的网卡,他们都桥接到br0上了
[root@docker1 ~]# ip netns exec 1-a921406c8f brctl show bridge name bridge id STP enabled interfaces br0 8000.461fb7ea304e no veth0 veth1 vxlan0
- 跨主机通讯的前提是两个容器内的vxlan的域id相同
[root@docker1 ~]# ip netns exec 1-a921406c8f ip -d l show vxlan0 46: vxlan0@if46: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master br0 state UNKNOWN mode DEFAULT group default link/ether d6:9f:87:b1:84:32 brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 1 vxlan id 256 srcport 0 0 dstport 4789 proxy l2miss l3miss ageing 300 noudpcsum noudp6zerocsumtx noudp6zerocsumrx
- 可以看到是256
- 如图所示,在创建ov_net1的时候,两台主机都有了这个overlay网卡,当在1.12中使用ov_net1运行bbox1时,生成了47@48的overlay网络和50@51的与1.12物理机通信的网络,同时也生成了一个网络的命名空间(1-a921406c8f)。
- 在网络命名空间中,br网卡通过桥接veth0与bbox1的overlay网络相连,和桥接vxlan0实现跨主机通信
- 与此同时,1.13中的bbox2是同理,他们之间的互相通信,因为他们的网络命名空间的相同和vxlan id相同,进而可以进行通信
overlay的隔离
- 不同的 overlay 网络是相互隔离的。创建第二个overlay网络ov_net2来运行容器
创建第二个overlay网络
docker1
# 创建一个新网卡 [root@docker1 ~]# docker network create --driver overlay ov_net2 e2ddd9d7d1a609576c217d685cf8eb7e95b7ba74742afce5c31b8c7a1f53b0b1
运行容器
[root@docker1 ~]# docker run -itd --name bbox3 --network ov_net2 busybox
09a1c1a651aa4ffeb2ee8885f896c308d4a038fd47011ccfa3dcaa623d892edb
查看bbox3容器ip
[root@docker1 ~]# docker exec bbox3 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
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
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue
link/ether 02:42:0a:00:01:02 brd ff:ff:ff:ff:ff:ff
inet 10.0.1.2/24 brd 10.0.1.255 scope global eth0
valid_lft forever preferred_lft forever
16: eth1@if17: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
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
bbox3 ping bbox1 和 bbox2
[root@docker1 ~]# docker exec -it bbox3 ping -c 2 bbox1
ping: bad address 'bbox1'
[root@docker1 ~]# docker exec -it bbox3 ping -c 2 bbox2
ping: bad address 'bbox2'
overlay跨网段通信
- 接上面的bbox3
- 通过个 bbox3的容器添加 一个 ov_net1网卡
[root@docker1 ~]# docker network connect ov_net1 bbox3 # 将ov_net1网络连接到bbox3的网络 [root@docker1 ~]# docker exec -it bbox3 ping -c 2 bbox2 PING bbox2 (10.0.0.4): 56 data bytes 64 bytes from 10.0.0.4: seq=0 ttl=64 time=0.189 ms --- bbox2 ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max = 0.189/0.189/0.189 ms [root@docker1 ~]# docker exec -it bbox3 ping -c 2 bbox1 PING bbox1 (10.0.0.2): 56 data bytes 64 bytes from 10.0.0.2: seq=0 ttl=64 time=1.686 ms 64 bytes from 10.0.0.2: seq=1 ttl=64 time=1.411 ms --- bbox1 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 1.411/1.548/1.686 ms
查看bbox3的网卡变化
- 该容器有了三块网卡 14 和 18 是用来连接 ov_net1 和 ov_net2的网卡 16 是连接 本地自动创建的网卡的 这三个都是新创建的
[root@docker2 ~]# docker exec -it bbox3 ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 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 14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue link/ether 02:42:0a:00:01:02 brd ff:ff:ff:ff:ff:ff inet 10.0.1.2/24 brd 10.0.1.255 scope global eth0 valid_lft forever preferred_lft forever 16: eth1@if17: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 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 18: eth2@if19: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue link/ether 02:42:0a:00:00:05 brd ff:ff:ff:ff:ff:ff inet 10.0.0.5/24 brd 10.0.0.255 scope global eth2 valid_lft forever preferred_lft forever
手动指定overlay网段
[root@docker1 ~]# docker network create --driver overlay --subnet 10.22.1.0/24 --gateway 10.22.1.1 ov_net3
03a6a6ce682d4e911ea6f0ec328eb0efddd92f5724258f01bb4fb7d0c0acbdc6
[root@docker1 ~]# docker network inspect ov_net3
"Subnet": "10.22.1.0/24",
补充
- 跨主机:消息能传到路由上(在物理网卡上联通,再传到路由上)
- Docker network分为两种类型:本机通讯类型(none/host/bridge)
- 跨主机通讯类型:(macvlan/pverlay)
跨主机通讯概念
- 前面已经有了 Docker 的几种网络方案:none、host、bridge 和 joined 容器,它们解决了单个 Docker主机内容器通信的问题。
- libnetwork & CNM
- libnetwork 是 docker 容器网络库,最核心的内容是其定义的 Container Network Model (CNM),这个模型对容器网络进行了抽象,由以下三类组件组成:
sandbox、endpoint、network
- sandbox
- Sandbox 是容器的网络栈,包含容器的 interface、路由表和 DNS 设置。 Linux Network Namespace 是 Sandbox 的标准实现。Sandbox 可以包含来自不同 Network 的 Endpoint
- endpoint
- Endpoint 的作用是将 Sandbox 接入 Network。Endpoint 的典型实现是 veth pair,一个 Endpoint 只能属于一个网络,也只能属于一个 Sandbox。
- network
- Network 包含一组 Endpoint,同一 Network 的 Endpoint 可以直接通信。Network 的实现可以是 Linux Bridge、VLAN 等。
- 如图所示两个容器,一个容器一个 Sandbox,每个 Sandbox 都有一个 Endpoint 连接到 Network,第二个 Sandbox 还有一个 Endpoint 将其接入 Network 2.
- 由network的概念知道,同一network的endpoint可以直接通信,也就是与图中network向量的三个endpoint的sandbox以及web1都能够通信,而network2连接的sandbox就不可以,因为network2只有一个endpoint
本博客所有文章是以学习为目的,如果有不对的地方可以一起交流沟通共同学习 邮箱:1248287831@qq.com!