docker 网络-bridge

主要内容介绍

[重点章节]docker默认网络模式

1、实现基础
1.1、namespace + veth 连通性测试
1.2、namespace +bridge 连通性测试

2、docker bridge
2.1、docker bridge 网络模型介绍
2.2、docker bridge 网络创建测试
2.3、docker bridge 命令背后的操作
2.4 、docker 命名后面为何看不到ns?
2.5、 docker bridge DNS 功能,服务发现?

3、总结
bridge 优缺点以及适用的业务场景

namespace + veth 连通性测试

1、需要完成的功能(如图网络连接情况)

1.1、三个命名空间 server ,gw ,client
1.2、server ping gw /client ping gw
1.3、server ping client / client ping server
1.4、server ping host eth0,server ping host eth1
1.5、server ping www.baidu.com

测试网络拓扑.png

备注:网卡命名@符号,vethsl@if9 表示一对 ,if 9 表示 9号接口,所有命名空间的接口ID 值唯一可以通过@符号找到对应的设备对。

2、测试命名以及步骤
1、创建三个命名空间

sudo ip netns add server
sudo ip netns add gw
sudo ip netns add client
#查看已创建的命名空间
ip netns ls

2、创建veth-pair

`#client-gw 连接对
sudo ip link add vethcl type veth peer name vethcg
#server-gw 连接对
sudo ip link add vethsl type veth peer name vethsg
#查看已创建的设备
ip a

3、veth-pair 连接network namespace

sudo ip link set vethsl netns server
sudo ip link set vethsg netns gw
sudo ip link set vethcg netns gw
sudo ip link set vethcl netns client
#查看主机设备情况
ip a
#查看命名空间里面的设备
sudo ip netns exec server ip a
sudo ip netns exec gw ip a
sudo ip netns exec client ip a

4、激活设备,并且分配ip地址

由于:手动创建的ns 不会自动分配ip,激活设备,配置路由。这些相关操作都需要手动执行

.
# 4.1 server ns 设备激活分配ip
sudo ip netns exec server ip link set vethsl up
sudo ip netns exec server ip addr add 192.168.100.3/24 dev vethsl
sudo ip netns exec server ip link set lo up
sudo ip netns exec server ip a
#4.2 client ns 设备激活分配ip
sudo ip netns exec client ip link set vethcl up
sudo ip netns exec client ip addr add 172.31.100.3/24 dev vethcl
sudo ip netns exec client ip link set lo up
sudo ip netns exec client ip a
#4.3 gw ns 激活分配ip
sudo ip netns exec gw ip link set vethsg up
sudo ip netns exec gw ip addr 192.168.100.1/24 dev vethsg
sudo ip netns exec gw ip link set lo up
sudo ip netns exec gw ip link set vethcg up
sudo ip netns exec gw ip addr add 172.31.100.1/24 dev vethcg
sudo ip netns exec gw ip a

5、测试网络连通

问题1,问题2,问题3?

.
# server ping gw ,ok
sudo ip netns exec server ping 192.168.100.1
# client ping gw,ok
sudo ip netns exec server ping 172.31.100.1
# server ping client,提示:Network is unreachable
# 问题1,解决方案 见 6点
sudo ip netns exec server ping 172.31.100.3
# server ping 主机 eth0 , 提示 :Network is unreachable
# 问题2,解决方案 见 7点
sudo ip netns exec server ping 10.0.2.15
# server ping 主机 eth0 , 提示 :Network is unreachable
# 问题3,解决方案 见 8点
sudo ip netns exec server ping www.baidu.com

6、解决 问题1

1、提示 Network is unreachable,一般情况下 是找不到对应的路由。
2、输入ping 命令后,如果长时间没有返回,一般情况下只有单边的路由。或者是arp 中找不对对应的mac 地址
3、ping 命名需要来回两条路都有正确的路由才能ping 通。

.
#查看server ns 路由,发现只有到gw一个接口 的路由
sudo ip netns exec server ip r
# 添加默认路由,所有数据都通过vethsl 接口,gw 表示下跳,所以应该为
# veth 的另一端
sudo ip netns exec server ip route add default gw 192.168.100.1
#再次ping,无应答,单边通
sudo ip netns exec server ping 172.31.100.3
# 查看 gw 路由,正确(目前)
sudo ip netns exec gw ip r
#查看client 路由,发现也只有到gw 直接连接的接口路由。
sudo ip netns exec client ip r
# 与server 一样添加 默认路由
sudo ip netns exec client route add default gw 172.31.100.1
# ping 再次测试,正常ping 通
sudo ip netns exec server ping 172.31.100.3
sudo ip netns exec client ping 192.168.100.3

7、解决问题2,命名空间无法与主机通信

思路:创建一对veth对,一端放入 gw 中,一端放入 主机中,并且配置相关路由
注意:ip 地址设置,尽量使用与主机不同的网段,避免路由冲突
备注:删除ip 地址,重新配置命名sudo ip addr del

.
# 创建veth-pair,放入gw 中
sudo ip link add vethgo type veth peer name vethgi
sudo ip link set vethgi netns gw
sudo ip netns exec gw ip link set vethgi up
sudo ip netns exec gw ip addr add 192.168.98.1/24 dev vethgi
#设置主机中veth
sudo ip link set vethgo up
sudo ip addr add 192.168.98.3/24 dev vethgo
# 主机 ping gw 直连接口,ok
ping 192.168.98.1
# 主机 ping gw 其他端口,无响应。
ping 172.31.100.1
ping 192.168.100.1
# 同理配置主机路由,client & server 网段
sudo ip route add 172.31.100.0/24 via 192.168.98.1 dev vethgo
sudo ip route add 192.168.100.0/24 via 192.168.98.1 dev vethgo
#为gw 配置默认路由,连接到主机的vethgo 接口
sudo ip netns exec gw ip route add default via 192.168.98.3 dev vethgi
# ping 测试 主机ping server ,主机ping client ,ok
ping 172.31.100.3
ping 192.168.100.3

8、问题3,ns 无法连通外部网络

理解:主机里面的网络在一个局网内,有自己的局网ip,(比如 192.168.100.3),如果从主机发送出去的数据包的源地址为192.168.100.3,收到该数据包的主机,有可能没办法 回应消息。比如 host-A(172.10.1.2) 有自己的ns ,里面有一个ip 为192.168.100.3, host-B(172.10.1.3) 有自己的ns ,里面有一个ip 也为192.168.100.3,那么 host-a-ns 与host-b-ns 是无法直接连通的。host-a 收到host-b 的ping ,host-a 会应答给host-a-ns。

解决方案:SNAT(修改数据包源地址)

所有ns 出口的数据包 都修改原地址为主机的ip 儿不是ns 的ip,这样相当于两个主机通信。主机收到消息后在分发给自己ns

修改了原地址,怎么知道回来的消息改发给哪个ns?iptables 会记录每次nat 会话(“连接”)的信息,所以回来的消息,能够正确发送到正确的ns。

备注:iptables 功能以及详情使用,见docker-网络 准备 推荐阅读

.
#开启 linux kernel ip forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
# -t :指明iptables 的表名称
# -A :添加一条nat 规则
# 将数据包源ip 地址为192.168.45.0 这个网段的地址 ,替换为 eth0 的ip 地址
# MASQUERADE 自动获取[eth0] 网络接口的IP地址
# server namespace nat
sudo iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o eth0 -j MASQUERADE
# 在默认 FORWARD 规则为 DROP 时显式地允许 veth1 和 eth0 之间的 forwarding
sudo iptables -t filter -A FORWARD -i eth0 -o vethgo -j ACCEPT
sudo iptables -t filter -A FORWARD -o eth0 -i vethgo -j ACCEPT
# 查看iptables配置详细情况
sudo iptables -L FORWARD -v
sudo iptables -t nat -L POSTROUTING -v
# ping 外网,ok
sudo ip netns exec server ping www.baidu.com

namespace +bridge 连通性测试

0、创建虚拟机

docker-machine create --driver virtualbox bridge
docker-machine ls
ssh docker@192.168.99.105 -i ~/.docker/machine/machines/bridge/id_rsa

1、创建bridge 设备

sudo ip link add br0 type bridge
sudo ip link set dev br0 up
ip l

2、创建veth 设备

sudo ip link add veth0 type veth peer name veth1

3、将一端连接 bridge

sudo ip link set dev veth0 master br0
sudo ip link set dev veth0 up

4、创建ns-net1,连接veth

sudo ip netns add net1
sudo ip link set veth1 netns net1
sudo ip netns exec net1 ip link set veth1 up
sudo ip netns exec net1 ip addr add 192.168.101.3/24 dev veth1
sudo ip netns exec net1 ip link set lo up

5、查看结果,以及ping 测试

sudo ip addr add 192.168.101.1/24 dev br0
sudo ip netns exec net1 route add default gw 192.168.101.1
ping 192.168.101.3

6、bridge 其他命令 bridge,brctl (略)

备注:其他ns 连接bridge 同样操作,连接外网配置NAT

docker bridge

1、docker bridge 网络模型介绍 如图 ,实现功能

1、每一个容器使用自己的网络命名空间
2、每个容器的网络与主机的bridge 设备连接(主机与容器通信,容器间通信)
3、主机NAT(端口映射) 容器里面的数据包ip 与外部通信
4、官网推荐使用自定义bridge 网络,不使用默认的docker0。
自定义的bridge 比docker 默认的bridge 网络有更多功能和灵活性,详情见官网
5、各个bridge 里面的网络隔离,如图 docker 里面网络 与 my_bridge 不能连通。
实现了自己局网连通,隔离其他局网

docker-bridge.png
2、docker bridge 测试

docker-bridge.png

#测试命令
# 1 创建bridge99 网络
docker network create -d bridge --subnet 172.31.99.0/24 bridge99
# 查看docker 网络
docker network ls
docker network inspect bridge99
docker run -itd --name 99c1 --net bridge99 hub.c.163.com/library/busybox sh
docker run -itd --name 99c2 --net bridge99 hub.c.163.com/library/busybox sh
# 查看容器ip, -f docker inspect 99c1 可以查看输入文件结构,用{{}} 定位字段值
docker inspect -f "{{.NetworkSettings.Networks.bridge99.IPAddress}}" 99c1
# host ping container 99c1
ping docker inspect -f "{{.NetworkSettings.Networks.bridge99.IPAddress}}" 99c1
# container ping 外网
docker exec -it 99c1 ping www.baidu.com
# 1、创建bridge98 网络
docker network create -d bridge --subnet 172.31.98.0/24 bridge98
docker run -itd --name 98c1 --net bridge98 hub.c.163.com/library/busybox sh
docker inspect -f "{{.NetworkSettings.Networks.bridge98.IPAddress}}" 98c1
# 2.1 host ping container 99c1
ping docker inspect -f "{{.NetworkSettings.Networks.bridge98.IPAddress}}" 98c1
# 2.2 container ping 外网
docker exec -it 98c1 ping www.baidu.com

3、docker bridge 测试结果

0、为何看不到 docker 容器的namespace ?

/var/run/netns 目录下面没有 namespace 符号链接,创建一个ns 的符号链接就可以

ip netns ls
mkdir -p /var/run/netns/
pid=$(docker inspect -f '{{.State.Pid}}' 99c1)
ln -sfT /proc/$pid/ns/net /var/run/netns/99c1
# 可以看到命名空间
ip netns ls
ip netns exec 99c1 ip a

1、bridge99 与 bridge98 网络隔离
2、bridge99 与 bridge98 分别可以局部内通信,以及与外部通信(NAT)
3、bridge99 与 bridge98 分别可以使用docker 内部 DNS 服务。使用默认的docker0 bridge 没有DSN 服务
4、路由配置分析

  • 4.1、容器里面的命名空间自动添加了一条默认路由,使用ip 命令 需要我们自己添加默认路由
  • 4.2、主机空间里面的bridge由于设置了ip ,也自动添加了路由,与我们自己创建bridge 设备一样

5、iptables 配置分析
NAT 配置,这儿是 docker 容器能够连通外网的原因

# 查看nat 表
sudo iptables -t nat -v -L

Chain POSTROUTING
out !=bridge98 ,用出口的的接口的ip 修改原数据包ip
out !=bridge99 ,用出口的的接口的ip 修改原数据包ip

bridge99 与 bridge98 隔离配置

# 查看filter 表
sudo iptables  -v -L

Chain FORWARD
a 表示一个接口
in=a out=!a 跳转到 Chain DOCKER-ISOLATION-STAGE-1

Chain DOCKER-ISOLATION-STAGE-1
in =bridge98 ,out !=bridge98,跳转到 Chain DOCKER-ISOLATION-STAGE-2
in =bridge99 ,out !=bridge99 跳转到 Chain DOCKER-ISOLATION-STAGE-2

Chain DOCKER-ISOLATION-STAGE-2 ,
out =bridge98,out=bridge99 drop
这条配置是bridge98 与bridge99 隔离原因

清除 DOCKER-ISOLATION-STAGE-2 配置

sudo iptables -F  DOCKER-ISOLATION-STAGE-2

# bridge98 与bridge99 可以连通
docker exec -it 99c1 ping `docker inspect -f "{{.[NetworkSettings.Networks.bridge98.IPAddress](http://NetworkSettings.Networks.bridge98.IPAddress)}}" 98c1`

总结

1、docker 的网络模型,简化了网络的设置。屏蔽了不同操作系统的实现。为上层提供统一接口支持还提供了内建DNS服务,负载均衡服务等。

2、bridge 优缺点以及适用的业务场景能够满足大部分业务场景,性能没有host 模式高,但是能够支持各种自定义网络, 以及实现网络隔离,能够满足容器网络隔离的要求。

相关内容

docker 网络-准备
docker 网络-host
docker 网络-bridge
docker 网络-overlay
docker 网络-macvlan