记录我的一些生活写照、无聊的牢骚、内心世界的活动 注册 | 登陆

Docker容器网络的研究

Docker容器网络的研究

一、不带vlan的macvlan网络的研究
局域网两台机器都创建相同网段macvlan
XML/HTML代码
  1. docker network create -d macvlan --subnet=192.168.0.0/24 --gateway=192.168.0.1 -o parent=eth0 macnet
两台机器分别使用macvlan创建同一网段的不同IP,以下都以Alpine容器为例。
XML/HTML代码
  1. docker run  -d --name alpine --hostname alpine --net=macnet --ip 192.168.0.100 -i -t --privileged=true --restart=always  bimg/alpine-ssh
  2. docker run  -d --name alpine --hostname alpine --net=macnet --ip 192.168.0.101 -i -t --privileged=true --restart=always  bimg/alpine-ssh
两台机器分别登录各自的docker容器,互相ping和ssh登录对方
XML/HTML代码
  1. docker exec -it alpine /bin/ash
结论,一个局域网通过macvlan创建的桥接网卡在同一个物理交换机下可以互通,因为他们都是和主网络在一个交换机下面,一个交换机下面只要网段相同就可以互通。
二、带有vlan的macvlan的研究
创建带有vlan的macvlan
两台机器分别创建ID为10和20的vlan
XML/HTML代码
  1. #为 eth0 创建 VLAN 10 接口
  2. sudo ip link add link eth0 name eth0.10 type vlan id 10
  3. sudo ip link set dev eth0.10 up
  4. #为 eth0 创建 VLAN 20 接口
  5. sudo ip link add link eth0 name eth0.20 type vlan id 20
  6. sudo ip link set dev eth0.20 up
  7. #两个机器分别创建两个绑定在vlan10和20上的macvlan
  8. docker network create -d macvlan --subnet=192.168.10.0/24 --gateway=192.168.10.1 -o parent=eth0.10 macnet10
  9. docker network create -d macvlan --subnet=192.168.20.0/24 --gateway=192.168.20.1 -o parent=eth0.20 macnet20
  10. #第一台机器创建绑定在两个vlan上的macvlan容器
  11. docker run  -d --name alpine1 --hostname alpine1 --net=macnet10 --ip 192.168.10.100 -i -t --privileged=true --restart=always  bimg/alpine-ssh
  12. docker run  -d --name alpine2 --hostname alpine2 --net=macnet20 --ip 192.168.20.100 -i -t --privileged=true --restart=always  bimg/alpine-ssh
  13. #第二台机器创建绑定在两个vlan上的macvlan容器
  14. docker run  -d --name alpine1 --hostname alpine1 --net=macnet10 --ip 192.168.10.101 -i -t --privileged=true --restart=always  bimg/alpine-ssh
  15. docker run  -d --name alpine2 --hostname alpine2 --net=macnet20 --ip 192.168.20.101 -i -t --privileged=true --restart=always  bimg/alpine-ssh
  16. #两台机器
  17. docker exec -it alpine1 /bin/ash
  18. docker exec -it alpine2 /bin/ash
发现不同vlan不能互通,此时需要第三台机器作为路由进行三层转发
在运行一个linux或者其他的网关,设置vlan10和20并且绑定ip作为网关
XML/HTML代码
  1. sudo ip link add link eth0 name eth0.10 type vlan id 10
  2. sudo ip link set dev eth0.10 up
  3. sudo ip addr add 192.168.10.1/24 dev eth0.10
  4. sudo ip link set dev eth0.10 up
  5.   
  6. sudo ip link add link eth0 name eth0.20 type vlan id 20
  7. sudo ip link set dev eth0.20 up
  8. sudo ip addr add 192.168.20.1/24 dev eth0.20
  9. sudo ip link set dev eth0.20 up
此时局域网所有vlan都可以互通。
注意:每个docker容器的vlan都不要设置ip,如果每个机器运行以下命令
XML/HTML代码
  1. sudo ip addr add 192.168.10.1/24 dev eth0.10
  2. sudo ip addr add 192.168.20.1/24 dev eth0.20
则每个机器本机都有一个网关,会冲突,造成机器不能互通。
如果作为网关的机器运行以上命令还是不通,则需要打开默认转发,设置防火墙规则。
打开IP转发也就是路由开关(如果没问题可以不管)
XML/HTML代码
  1. sysctl -w net.ipv4.ip_forward=1
XML/HTML代码
  1. #设置防火墙规则允许互通(如果没问题可以不管)
  2. iptables -t nat -A POSTROUTING -o eth0.10 -j MASQUERADE
  3. iptables -t nat -A POSTROUTING -oeth0.20 -j MASQUERADE
  4. iptables -A FORWARD -i eth0.10 -o eth0.20 -m state --state RELATED,ESTABLISHED -j ACCEPT
  5. iptables -A FORWARD -i eth0.20 -o eth0.10 -m state --state RELATED,ESTABLISHED -j ACCEPT
  6. iptables -A FORWARD -i eth0.10 -o eth0.20 -j ACCEPT
  7. iptables -A FORWARD -i eth0.20 -o eth0.10 -j ACCEPT
通过以上设置可以是局域网的不同macvlan的容器互通。
如果想要每个容器都可以上网,需要个第三个作为路由的机器设置下nat转发规则
XML/HTML代码
  1. iptables -t nat -A POSTROUTING -s 0.0.0.0/0 -j SNAT --to 192.168.19.103
  2. route add default gw 192.168.19.1
192.168.19.103是路由机器本事自己的ip地址,192.168.19.1是路由机器自己可以上网的网关。
通过以上设置可以是局域网任意容器可以上网,不管是绑定了哪个vlan的macvlan的机器,就是让三方机器充当了路由器。
从而使容器有了网络,通过路由,容器也可以和宿主机进行通讯。
XML/HTML代码
  1. #给容器添加多个macvlan网卡
  2. docker run  -d --name alpinex --hostname alpinex  -i -t --privileged=true --restart=always  bimg/alpine-ssh
  3. docker network connect --ip 192.168.10.111 macnet10 alpinex
  4. docker network connect --ip 192.168.20.111 macnet20 alpinex
  5. docker exec -it alpinex ifconfig
  6. #可以看到容器已经获取多个网卡
如果没有条件用其他机器做路由,也可以用本机建立一个容器加载两个macvlan,当成路由用。
XML/HTML代码
  1. docker run  -d --name alpinex --hostname alpinex  -i -t --privileged=true --restart=always  bimg/alpine-ssh
  2. docker network connect --ip 192.168.10.1 macnet10 alpinex
  3. docker network connect --ip 192.168.20.1 macnet20 alpinex
XML/HTML代码
  1. docker exec -it alpinex /bin/ash
  2. apk add iptables
  3. ifconfig
  4. ifconfig eth1 192.168.10.1
  5. ifconfig eth2 192.168.20.1
  6. route add default gw 172.17.0.1
  7. iptables -t nat -A POSTROUTING -s 0.0.0.0/0 -j SNAT --to 172.17.0.3
  8. #172.17.0.3是路由容器的ip地址,172.17.0.1是路由容器的默认网关。
注意以上命令重启容器会失效是临时的,所有重启后需要再次配置才可以使用。
 
macvlan创建
一些程序,特别是应用程序或者网络流量监控程序,期望直接连接到物理网络,这种情况下,可使用Macvlan网络模式,给每个容器的虚拟网络接口配置一个mac地址,使得连接容器,看起来是直接到一个物理主机上。这种情况下,需要在主机上 为macvlan驱动,指定一个物理接口,一起子网与默认网关,甚至使用不同的物理网络接口,隔离navlan网络。但必须了解如下几点:
     (1)IP地址溢出,和虚拟网络传播(VLAN spreads)将很容易导致网络损坏。例如网络中有众多无效的唯一mac地址,
     (2)网络设备需要处理“混杂模式”, 多个mac地址关联一个物理接口
     (3)如果应用程序可使用 bridge 模式 或者 overlay 模式,从长远来讲,将是更好的选择。
一、创建一个macvlan 网络
当创建一个macvlan网络时,我们可选如下两种模式
bridge mode : 桥接模式, 该模式下,网络数据路由,通过主机的一个物理设备。
802.1 q trunk birdge mode: 802.1 q主干桥接模式, (虚拟桥接局域网),流量通过docker 动态创建一个以 802.1 q的子接口传输(这里不深入解释802.1 q)这允许用户在更细的层次上控制路由和筛选。
1、Bridge mode
创建一个该模式下的网络,需要一个给定的物理接口,指定 --driver macvlan  , 使用指令  docker  network create 创建, 同时必须指定 parent  标记,也即通讯流实际在docker主机上流经的物理接口。 
XML/HTML代码
  1. docker network create -d macvlan \
  2.  --subnet=172.16.86.0/24 \
  3.  --gateway=172.16.86.1  \
  4.  -o parent=eth0 pub_net
如果需要,正在使用的macvlan中,排除一些ip,例如用户给定使用ip的,可使用 --aux-addresses 修改
XML/HTML代码
  1. docker network create -d macvlan  \
  2.  --subnet=192.168.32.0/24  \
  3.  --ip-range=192.168.32.128/25 \
  4.  --gateway=192.168.32.254  \
  5.  --aux-address="my-router=192.168.32.129" \
  6.  -o parent=eth0 macnet32
2、802.1 q trunk bridge mode
如果以包含点号 "."命名方式 指定一个 parent 接口时, 例如 eth0.50 ,  docker将把它看做eth0的一个子网,并自动创建子接口。
XML/HTML代码
  1. docker network  create  -d macvlan \
  2.  --subnet=192.168.50.0/24 \
  3.  --gateway=192.168.50.1 \
  4.  -o parent=eth0.50 macvlan50
3、使用 ipvlan 提到 macvlan
1和2依然使用的L3的桥接网络,可使用  iplvan 替代,获取L2的桥接,使用 -o  ipvlan_mode=l2 指定
XML/HTML代码
  1. docker network create -d ipvlan \
  2.  --subnet=192.168.210.0/24 \
  3.  --subnet=192.168.212.0/24 \
  4.  --gateway=192.168.210.254  \
  5.  --gateway=192.168.212.254  \
  6.  -o ipvlan_mode=l2 ipvlan210
4、启动ipv6
如果配置了docker daemon 的启动参数,运行使用ipv6,  可在macvlan网络中,同时使用 ipv4、ipv6双网络堆栈
XML/HTML代码
  1. docker network  create  -d macvlan \
  2.   --subnet=192.168.216.0/24 --subnet=192.168.218.0/24 \
  3.  --gateway=192.168.216.1  --gateway=192.168.218.1 \
  4.  --subnet=2001:db8:abc8::/64 --gateway=2001:db8:abc8::10 \
  5.  -o parent=eth0.218 \
  6.  -o macvlan_mode=bridge macvlan216
macvlan使用
本系列的教程涉及独立 Docker 容器连接到 macvlan 网络的问题。在这种网络下,Docker 宿主机在它的IP之上,允许接受多个 MAC 地址的请求,然后再将这些请求路由至对应的容器里。
本系列教程的目的,是设置好一个桥接好的 macvlan 网络,并把一个容器连接上去。接着设置一个 802.1q 中继的 macvlan 网络,也将一个容器连接上去。macvlan 网络驱动只能在Linux 主机上工作,不支持 Docker Desktop for Mac, Docker Desktop for Windows, 或者是 Docker EE for Windows Server。你需要 3.9 或者更高版本的 Linux 内核。这些例子假设你的以太网网卡是 eth0。 如果你的设备叫别的名字,用对应的名字代替。
桥接例子
在简单的桥接例子里,你的网络流量在 eth0 流通,Docker 会用它的 MAC 地址,把流量路由进你的容器里。对于网络上的网络设备来说,你的容器似乎是物理上连接到网络上的。
创建一个 macvlan 网络并命名为 my-macvlan-net。 修改 subnet, gateway 和 parent 的值为你实际情况下恰当的值。
XML/HTML代码
  1. docker network create -d macvlan \
  2.  --subnet=172.16.86.0/24 \
  3.  --gateway=172.16.86.1 \
  4.  -o parent=eth0 \
  5.  my-macvlan-net
你可以用 docker network ls 和 docker network inspect my-macvlan-net 命令去验证此网络已经存在,并且是一个 macvlan 网络。
启动一个 alpine 容器,并把它连接到 my-macvlan-net 网络。-dit 标志使得容器以后台的形式启动,并允许你后面连接它。--rm 标志意味它在停止后会被删除。
XML/HTML代码
  1. docker run --rm -dit \
  2.  --network my-macvlan-net \
  3.  --name my-macvlan-alpine \
  4.  alpine:latest \
  5.  ash
Inspect 一下 my-macvlan-alpine 容器,注意到 Networks 字段下的 MacAddress 字段:
XML/HTML代码
  1. docker container inspect my-macvlan-alpine
此时可以看到网络详细参数,通过运行几个 docker exec 命令,检查容器内如何看到自己的网络接口。
XML/HTML代码
  1. docker exec my-macvlan-alpine ip addr show eth0
  2. docker exec my-macvlan-alpine ip route
停止容器 (Docker 会自动删除它,因为有 --rm 标志),并删除网络。
XML/HTML代码
  1. docker container stop my-macvlan-alpine
  2. docker network rm my-macvlan-net
802.1q 中继桥接例子
在802.1q中继桥接的例子中,你的流量流经 eth0 的一个子接口(称为 eth0.10),Docker使用其MAC地址将流量路由到你的容器。对于网络上的网络设备来说,你的容器似乎是物理上连接到网络上的。
创建一个叫 my-8021q-macvlan-net 的 macvlan 网络。修改 subnet, gateway 和 parent 的值为你实际情况下恰当的值。 
XML/HTML代码
  1. docker network create -d macvlan \
  2.  --subnet=172.16.86.0/24 \
  3.  --gateway=172.16.86.1 \
  4.  -o parent=eth0.10 \
  5.  my-8021q-macvlan-net
你可以用 docker network ls 和 docker network inspect my-8021q-macvlan-net 命令去验证此网络已经存在,并且是一个 macvlan 网络,有一个父接口 eth0.10。你可以在 Docker 的宿主机上用 ip addr show ,验证接口 eth0.10 存在并且有一个单独的IP地址。
启动一个 alpine 容器并将它连接到 my-8021q-macvlan-net 网络。-dit 标志使得容器以后台的形式启动,并允许你后面连接它。--rm 标志意味它在停止后会被删除。 
XML/HTML代码
  1. docker run --rm -itd \
  2.  --network my-8021q-macvlan-net \
  3.  --name my-second-macvlan-alpine \
  4.  alpine:latest \
  5.  ash
Inspect 一下 my-second-macvlan-alpine 容器,注意到 Networks 字段下的 MacAddress 字段:
XML/HTML代码
  1. docker container inspect my-second-macvlan-alpine
通过运行几个 docker exec 命令,检查容器内如何看到自己的网络接口。
XML/HTML代码
  1. docker exec my-second-macvlan-alpine ip addr show eth0
  2. docker exec my-second-macvlan-alpine ip route
停止容器 (Docker 会自动删除它,因为有 --rm 标志),并删除网络。 
XML/HTML代码
  1. docker container stop my-second-macvlan-alpine
  2. docker network rm my-8021q-macvlan-net
以上为官方教程,可以参考实际情况使用。
 
如何将VLAN接口添加到一个虚拟交换机(VLAN trunks)以便传输多个VLAN的数据(待验证)
要将 VLAN 接口添加到虚拟交换机(VLAN trunk)以传输多个 VLAN 的数据,您需要在 Linux 上使用网络管理工具(通常是 ip 或 ifconfig)来进行配置。以下是一般步骤:
使用 ip 命令配置 VLAN 接口并添加到虚拟交换机:
首先,确保系统上已经加载了 802.1Q VLAN 模块。您可以使用以下命令检查:
XML/HTML代码
  1. lsmod | grep 8021q
如果未加载,您可以使用 modprobe 命令加载它:
XML/HTML代码
  1. sudo modprobe 8021q
创建 VLAN 接口,并将其添加到虚拟交换机(VLAN trunk)。假设您要创建 VLAN 10 和 VLAN 20 并将它们添加到物理接口 eth0 上,可以执行以下命令:
XML/HTML代码
  1. # 创建 VLAN 10 接口并添加到 eth0
  2. sudo ip link add link eth0 name eth0.10 type vlan id 10
  3. # 创建 VLAN 20 接口并添加到 eth0
  4. sudo ip link add link eth0 name eth0.20 type vlan id 20
  5. 启用 VLAN 接口:
  6. sudo ip link set dev eth0.10 up
  7. sudo ip link set dev eth0.20 up
添加 VLAN 接口到虚拟交换机(VLAN trunk)。这通常是通过编辑网络配置文件来完成的。例如,在 Ubuntu/Debian 上,您可以编辑 /etc/network/interfaces 文件:
sudo nano /etc/network/interfaces
然后添加如下行来将 VLAN 接口添加到虚拟交换机。假设虚拟交换机名称为 br0:
XML/HTML代码
  1. auto br0
  2. iface br0 inet dhcp
  3.     bridge_ports eth0.10 eth0.20
保存并退出编辑器。然后重启网络服务或系统以应用更改。
重新启动网络服务或系统以使更改生效:
XML/HTML代码
  1. sudo systemctl restart networking
现在,您已经将 VLAN 10 和 VLAN 20 接口添加到虚拟交换机 br0,这意味着它们可以传输多个 VLAN 的数据。请根据您的具体网络配置和需求进行相应的更改。不同的 Linux 发行版可能有稍微不同的配置方法,因此请根据您的系统查看相关文档以获取详细信息。
 
IPVLAN/MACVLAN 实现 Docker 和物理局域网络真正互联互通(待验证)
利用 ipvlan/macvlan 和 ip route 的一些基础功能,基本上只要认真阅读,想实现 Docker 网络和局域网物理网络互联互通是没啥难度的。通过本文,你可以为每一个 Container 分配一个其专属的局域网 IP,以便其和物理网络的其它服务或客户端轻松通讯,而无需顾虑宿主机端口 - Port 不够映射的问题。
简要说明一下原理:Docker 设计的时候就考虑了跨主机通讯和宿主机网络隔离的安全问题,在 VLAN 模式下只允许同 VLAN 的 MACVLAN/IPVLAN 子接口内部通讯,同时对来自宿主通过父接口到子接口的通讯进行了过滤(阻断),以确保安全。因此可利用子接口可相互通讯的原理,在宿主多配置一个子接口,并多分配一个 IP 地址,同时在路由表配置正确的情况下,容器就能和物理网络完全互通了。
0x00:
先决条件
1、确保宿主机 Linux Kernel 内核版本 ≥ 4.20 (此版本是 Docker Network 对 IPVLAN 模式稳定支持的最低限度版本)
2、一定的 Linux Shell 命令行及 IP Router Config 配置基础
3、宿主需要安装iproute2依赖库
4、能看得懂本文
0x01:
创建一个 IPVLAN/MACVLAM 类型的 Docker Network (根据需要任选其一即可)
XML/HTML代码
  1. # MACVLAN
  2. docker network create \
  3.     --driver=macvlan            `# 指定网络驱动类型为:macvlan` \
  4.     --subnet=10.1.0.0/23        `# 接口所对应的物理网络网域(网段)` \
  5.     --ip-range=10.1.0.0/24      `# 划分一段网段用于给容器分配 IP 地址使用(可选)` \
  6.     --gateway=10.1.1.254        `# 物理网络的网关` \
  7.     --opt parent=eth0           `# 绑定子接口到物理网卡(父接口)` \
  8.     pub                         `# 给此 Docker Network 指派一个名称`
XML/HTML代码
  1. # IPVLAN
  2. docker network create \
  3.     --driver=ipvlan             `# 指定网络驱动类型为:ipvlan ` \
  4.     --subnet=10.1.0.0/23        `# 接口所对应的物理网络网域(网段)` \
  5.     --ip-range=10.1.0.0/24      `# 划分一段网段用于给容器分配 IP 地址使用(可选)` \
  6.     --gateway=10.1.1.254        `# 物理网络的网关` \
  7.     --opt parent=eth0           `# 绑定子接口到物理网卡(父接口)` \
  8.     pub                         `# 给此 Docker Network 指派一个名称` 
# 新建关于 Docker 容器的专用路由表
XML/HTML代码
  1. echo "100     docker" >> /etc/iproute2/rt_tables
  2. ip route flush table docker
0x02:
配置 IPVLAN/MACVLAN 静态路由表(根据需求选择对应的模式)
(步骤 0x02/0x03 二选一即可,使用 0x02 的方法则不需要再继续配置 0x03 的方法,反之亦然)
创建用于配置宿主机关于物理网络及 Docker 网络的静态路由表的脚本(用于开机自启时执行)
docker-network-boot-config.sh
XML/HTML代码
  1. # MACVLAN
  2. ip link add mac0 link eth0 type macvlan mode bridge         # 根据需求创建一个新的 MACVLAN 子接口
  3. ip addr add 10.1.0.1 dev mac0                               # 为子接口手动分配一个静态 IP 地址
  4. ip link set mac0 up                                         # 打开子接口
  5. ip link set eth0 promisc on                                 # 启用父接口网络混杂支持
  6. ip link set mac0 promisc on                                 # 启用子接口网络混杂支持
  7. ip route add default via 10.1.0.1 table docker              # 配置到容器的默认路由表  
  8. ip route add 10.1.0.0/23 dev mac0 src 10.1.0.1 metric 10    # 为子接口配置对应的静态路由表
  9. ip rule add from all to 10.1.0.0/24 table docker            # 配置本地回环到容器的路由规则
XML/HTML代码
  1. # IPVLAN
  2. ip link add ipvl link eth0 type ipvlan                      # 根据需求创建一个新的 IPVLAN 子接口
  3. ip addr add 10.1.0.1 dev ipvl                               # 为子接口手动分配一个静态 IP 地址
  4. ip link set ipvl up                                         # 打开子接口
  5. ip link set eth0 promisc on                                 # 启用父接口网络混杂支持
  6. ip link set ipvl promisc on                                 # 启用子接口网络混杂支持
  7. ip route add default via 10.1.0.1 table docker              # 配置到容器的默认路由表
  8. ip route add 10.1.0.0/23 dev ipvl src 10.1.0.1 metric 10    # 为子接口配置对应的静态路由表
  9. ip rule add from all to 10.1.0.0/24 table docker            # 配置本地回环到容器的路由规则
将创建的 docker-network-boot-config.sh 脚本添加到 Linux 开机自启里(以便每次开机能自动配置)
然后重启 Linux 或执行下docker-network-boot-config.sh(记得 chmod +x)
0x03:
另一种更优雅的子接口配置方式,直接在网卡配置文件里设置(推荐)
XML/HTML代码
  1. nano /etc/network/interfaces  
XML/HTML代码
  1. auto lo  
  2. iface lo inet loopback  
  3. iface lo inet6 loopback  
  4.   
  5.   
  6. auto eth0  
  7. iface eth0 inet static  
  8.         address 10.1.1.0  
  9.         gateway 10.1.1.254  
  10.         netmask 255.255.254.0  
  11.         dns-nameservers 10.1.0.53  
  12.         up ip link set $IFACE promisc on  
  13.   
  14.   
  15. auto mac0  
  16. iface mac0 inet static  
  17.         hwaddress ea:8c:f8:af:89:c2  
  18.         address 10.1.0.1  
  19.         gayway 10.1.1.254  
  20.         netmask 255.255.254.0  
  21.         dns-nameservers 10.1.0.53  
  22.         pre-up ip link add mac0 link eth0 type macvlan mode bridge  
  23.         up ip link set $IFACE promisc on  
  24.         up ip route add default via 10.1.0.1 table docker  
  25.         up ip rule add from all to 10.1.0.0/24 table docker  
  26.         post-down ip link del mac0 link eth0 type macvlan mode bridge  
  27.   
  28.   
  29. auto ipvl  
  30. iface ipvl inet static  
  31.         hwaddress ea:8c:f8:af:89:c2  
  32.         address 10.1.0.1  
  33.         gayway 10.1.1.254  
  34.         netmask 255.255.254.0  
  35.         dns-nameservers 10.1.0.53  
  36.         pre-up ip link add ipvl link eth0 type ipvl  
  37.         up ip link set $IFACE promisc on  
  38.         up ip route add default via 10.1.0.1 table docker  
  39.         up ip rule add from all to 10.1.0.0/24 table docker  
  40.         post-down ip link del ipvl link eth0 type ipvl  
以上未经测试,自行验证。

« 上一篇 | 下一篇 »

发表评论

评论内容 (必填):