blog icon indicating copy to clipboard operation
blog copied to clipboard

在docker中运行openwrt

Open lisaac opened this issue 6 years ago • 34 comments

docker 中运行 openwrt

[toc]

思路

利用 macvlan 方式创建虚拟接口进行配置。 有感于来自恩山 betterman 及 rightwifi2017 两位大佬斐讯 N1 的玩法,也获得两位大佬的帮助,在此感谢两位大佬。 由于 N1 为单网卡,所以配置只能为单臂路由,本案为双网卡 opewnrt

机器拥有双网卡: enp1s0enp3s0 ,本案将 enp3s0 用作 LAN 口,enp1s0 用作 WAN 口。

0. 安装 docker

curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

1. 配置系统环境

#打开网卡混杂模式
ip link set enp1s0 promisc on
ip link set enp3s0 promisc on

#加载 PPPOE 内核模块
modprobe pppoe

2.docker 网络配置

# 为 docker 创建 macvlan 虚拟接口,并链接到 host 网卡
# LAN 口
docker network create -d macvlan \
    --subnet=10.1.1.0/24 --gateway=10.1.1.1 \
    --ipv6 --subnet=fe80::/16 --gateway=fe80::1 \
    -o parent=enp3s0 \
    -o macvlan_mode=bridge \
    dMACvLAN
# WAN 口
docker network create -d macvlan \
    --subnet=192.168.254.0/24 --gateway=192.168.254.1 \
    --ipv6 --subnet=fe81::/16 --gateway=fe81::1 \
    -o parent=enp1s0 \
    -o macvlan_mode=bridge \
    dMACvWAN

3. 创建容器

#导入镜像
docker import https://downloads.openwrt.org/releases/18.06.1/targets/x86/64/openwrt-18.06.2-x86-64-generic-rootfs.tar.gz openwrt:18.06.2

#创建并启动容器
docker run -d \
    --restart unless-stopped \
    --network dMACvLAN \
    --privileged \
    --name openwrt \
    openwrt:18.06.2 \
    /sbin/init

#将第二网卡的 macvlan 挂接到 openwrt
docker network connect dMACvWAN openwrt

4. 配置 openwrt

#进入容器
docker exec -it openwrt /bin/sh

#编辑 / etc/config/network
config interface 'lan'
        option type 'bridge'
        option ifname 'eth0'   # 需要与 docker netwrok 中的虚拟接口匹配(dMACvLAN)
        option proto 'static'
        option ipaddr '10.1.1.254'
        option netmask '255.255.255.0'
        option ip6assign '60'

config interface 'wan'
        option ifname 'eth1'  # 需要与 docker netwrok 中的虚拟接口匹配(dMACvWAN)
        option proto 'dhcp'
        option ip6assign '60'

#重启 openwrt 网络
/etc/init.d/network restart

5. 宿主机出口

由于 docker 网络采用 macvlanbridge 模式,即使宿主机与容器在同一网段,相互之间也是无法通信的。 为了解决这个问题,需利用多个 macvlan 接口之间是互通的原理,在 LAN 口新建一个 macvlan 虚拟接口:

# 使用 ip 命令
ip link add link enp3s0 hMACvLAN type macvlan mode bridge # 在 enp3s0 接口下添加一个 macvlan 虚拟接口
ip addr add 10.1.1.2/24 brd + dev hMACvLAN # 为 hMACvLAN 分配 ip 地址
ip link set hMACvLAN up
ip route del default #删除默认路由
ip route add default via 10.1.1.254 dev hMACvLAN # 设置静态路由
echo "nameserver 10.1.1.1" > /etc/resolv.conf # 设置静态 dns 服务器

# 或者使用 nmcli
nmcli connection add type macvlan dev enp3s0 mode bridge ifname hMACvLAN autoconnect yes save yes

或者,若是在 debian 中可以编辑 /etc/network/interface 并加入:

auto hMACvLAN
iface hMACvLAN inet static
  address 10.1.1.2
  netmask 255.255.255.0
  gateway 10.1.1.254
  pre-up ip link add hMACvLAN link enp3s0 type macvlan mode bridge
  post-down ip link del hMACvLAN link enp3s0 type macvlan mode bridge

6. 配置客户端 IP&enjoy

后续就是 openwrt 的玩法,除了没有 wifi,其他基本一致。有一点,若需要加载内核模块,则需要在 host 中事先加载

lisaac avatar Jan 10 '19 12:01 lisaac

能否写一下如何在docker中使用openwrt,我没有测试成功

WinterXMQ avatar Jun 04 '19 14:06 WinterXMQ

佩服博主的抽象思维能力,配网络都不用画图。

另外: 第五步中的关于去修改宿主机路由规则的命令: ip route del default #删除默认路由 ip route add default via 10.1.1.254 dev hMACvLAN # 设置静态路由 echo "nameserver 10.1.1.1" > /etc/resolv.conf # 设置静态 dns 服务器

建议是不要动宿主机的路由,删除宿主机的默认路由在很多场景下还是比较危险的,我的做法是: 在宿主机上执行SNAT iptables -t nat -A POSTROUTING -s 10.1.1.0/24 -o ens192 -j MASQUERADE

而后在容器中配置路由: ip route add default via 10.1.1.2 dev br-lan

pingod avatar Jun 05 '19 13:06 pingod

其实觉得如果在容器起来的时候使用--net host 会更加简单,后面加MacVlan网卡和配路由应该都不用弄了,但是没有测试过

pingod avatar Jun 05 '19 13:06 pingod

@WinterXMQ 使用方法和正常的 openwrt 无异,不知道没有测试成功指的是?

@pingod 嗯,用 iptables 也可以,好处是不用改主机默认路由,但是流量会再转发一次。 --net host 我也没测试过,应该是可以的,macvlan 是起到网络虚拟化作用的,对于强迫症应该不喜欢用 host

lisaac avatar Jun 05 '19 22:06 lisaac

我家里的宽带网络是直接DHCP获取公网ip的。我是在双网口群辉Docker跑Openwrt的,打算拿来做主路由。按照博主的教程配置好了以后,插网线到WAN口,但是公网ip就直接被群辉获取了,Openwrt根本无法获取到,请问这种情况,我完全按照上面的教程去做可以啦?

darktitty avatar Jun 24 '19 07:06 darktitty

@darktitty 首先我不确定群晖内核模块是否完全能够支持 Openwrt

群晖需要关闭 DHCP,同时,网线必须对应 Openwrt WAN 侧,并且在群晖中新建一个 macvlan 虚拟接口(对应 Openwrt LAN 侧的那个网卡),这样才能通过 Openwrt 来上网。

lisaac avatar Jun 25 '19 03:06 lisaac

奇怪的是 我执行第五步以后 openwrt就连不上啦 晚点我试试在Debian上搞搞看

darktitty avatar Jun 25 '19 03:06 darktitty

新编译的rootfs.tar.gz拖进docker启动后,web显示不正常:luci web响应速度比较慢,首页网口信息显示“正在收集”无信息显示,工作时间和负载也是空白,能ping通网关。 之前编译的正常,不知道什么原因。

kanshudj avatar Jul 22 '19 08:07 kanshudj

@kanshudj 不清楚原因,应该是镜像的关系,感觉是占用过高?可以查一下 cpu 的占用率

lisaac avatar Jul 26 '19 04:07 lisaac

奇怪的是 我执行第五步以后 openwrt就连不上啦 晚点我试试在Debian上搞搞看

你好,群晖里的docker能访问到吗?试了很多次了, 还是访问不了docker中的openwrt?

ywjdlq avatar Sep 04 '19 09:09 ywjdlq

@darktitty 首先我不确定群晖内核模块是否完全能够支持 Openwrt

群晖需要关闭 DHCP,同时,网线必须对应 Openwrt WAN 侧,并且在群晖中新建一个 macvlan 虚拟接口(对应 Openwrt LAN 侧的那个网卡),这样才能通过 Openwrt 来上网。

请教一下,docker中运行openwrt需要哪些内核模块呢?在群晖里的docker装上了,就是没法访问

ywjdlq avatar Sep 04 '19 09:09 ywjdlq

@ywjdlq 我折腾了好久没成功 都放弃啦…

darktitty avatar Sep 04 '19 09:09 darktitty

@ywjdlq 没有在群晖中使用过,由于群晖内核裁剪的比较厉害,我有空的时候装个黑群晖试一下

lisaac avatar Sep 05 '19 05:09 lisaac

@lisaac 尝试过了吗?我看openwrt内核都到4.15了,群晖的3.10

ywjdlq avatar Sep 19 '19 08:09 ywjdlq

@ywjdlq 还没,最近在忙其他项目,抽空试一下

lisaac avatar Sep 20 '19 14:09 lisaac

@ywjdlq 抽空刚刚在虚拟机黑裙中试了一下,是可以进luci界面的,没有做过多测试 如果是单网口,可能需要先停用firewall:
/etc/init.d/firewall sotp

lisaac avatar Sep 21 '19 05:09 lisaac

docker 中的openwrt 外网和网关都不通。。

manooog avatar Mar 21 '20 13:03 manooog

成功配置双网卡。但添加第三个网卡作为第二LAN口后,wan口就无法pppoe拨号了。 操作方法是docker中新建第三个macvlan网络,用了不同的网段,绑定第三个网卡,之后将新的macvlan链接到openwrt的容器。 求教了,多谢。

deepline1986 avatar Mar 24 '20 00:03 deepline1986

@deepline1986 感觉应该不会有问题,无法拨号具体表现是什么? 另外可以试一下在宿主建立bridge-lan,然后在bridge-lan上建macvlan,挂进docker

lisaac avatar Mar 24 '20 02:03 lisaac

@deepline1986 感觉应该不会有问题,无法拨号具体表现是什么? 另外可以试一下在宿主建立bridge-lan,然后在bridge-lan上建macvlan,挂进docker

@lisaac 在宿主机给容器连接第二个lan口的macvlan,分两种情况。

  1. 在openwrt中添加lan的interface,完成后,新lan口工作正常,上网,但重启宿主机后wan口拨号失效。
  2. 不在openwrt中添加lan的interface,直接重启宿主机,之后wan口同样拨号失效。 wan拨号的错误信息如下。
Protocol: PPPoE
RX: 0 B (0 Pkts.)
TX: 0 B (0 Pkts.)
Error: Connection attempt failed

在宿主机给容器断开第二个lan口的macvlan,重启宿主机,wan口拨号恢复正常。

另外,请问宿主机建立bridge-lan,是分割wan口和lan口,还是别的理解?谢谢。

deepline1986 avatar Mar 24 '20 04:03 deepline1986

@deepline1986 由于没有环境,没有测过,按道理来讲,应该不会出现这个问题,如果有结果请 po 出来,谢谢。

另外,关于网桥的方案,我也没测试过,只是一个想法: 在宿主机上在两个lan口上建立bridge-lan,然后把bridge-lan看成双网口方案中的lan口,按照双网口方案进行部署

lisaac avatar Mar 24 '20 04:03 lisaac

@deepline1986 由于没有环境,没有测过,按道理来讲,应该不会出现这个问题,如果有结果请 po 出来,谢谢。

另外,关于网桥的方案,我也没测试过,只是一个想法: 在宿主机上在两个lan口上建立bridge-lan,然后把bridge-lan看成双网口方案中的lan口,按照双网口方案进行部署

@lisaac 已经找到问题了,根据测试结果显示,openwrt内ethX的排序,是按照连接中的macvlan网络的命名的顺序来的。 例如四个物理网卡,对应四个macvlan网络,我们希望发生下面这样的配对

计划:
    网卡1 => dMACvLAN1 => eth0
    网卡2 => dMACvWAN => eth1
    网卡3 => dMACvLAN3 => eth2
    网卡4 => dMACvLAN4 => eth3

实际添加之后,如果重启系统,openwrt会基于中间的dMACvXXXX来排序。 因为第二个dMACvWAN,第6个字母是“W”而不是“L”。 结果左边两项按照中间这列排序之后,物理网卡和ethX是下面这样的对应关系。

实际:
    网卡1 => dMACvLAN1 => eth0
    网卡3 => dMACvLAN3 => eth1
    网卡4 => dMACvLAN4 => eth2
    网卡2 => dMACvWAN => eth3

那么原先基于eth1并作用在物理网卡2的pppeo拨号配置,就被转移到物理网卡3上面,那么自然就没有拨号对象了。 也就是说macvlan的命名排序,和物理网口顺序一致,才能保证物理口和eth逻辑口顺序一致。

👍感谢分享

deepline1986 avatar Mar 24 '20 07:03 deepline1986

这种方式 openwrt 的端口转发好像不行啊,是不是必须在 docker run 的是时候设置宿主机 -p 参数?

bestK avatar Mar 31 '20 18:03 bestK

尝试了下--net host,是无法使用的,至少本人测试的时候docker container一起来,宿主机网络就混乱造成重启,总结了一下

  1. 使用 --net host的时候是无法使用--ip指定ip地址的user specified IP address is supported on user defined networks only.
  2. openwrt 作为旁路必须设置的ip和网关,net host 与主机共享network space,所以两者冲突 以上是我的测试结果,当然也有可能是我的宿主机跑的armbian版本太低有bug,如果有其他大佬测试出来麻烦分享下经验!

rilyuuj avatar Apr 05 '20 05:04 rilyuuj

遇到一个问题: 先说背景,N1刷armbian ubuntu18.04,docker下以macvlan模式部署openwrt。刚开始是OP和宿主机N1(ubuntu)无法ping通。按照你的思路在eth0上建立了虚拟网卡mac0,在interfaces文件里加入代码,重启后OP和N1(ubuntn)确实是可以ping通了。但是有一个问题,N1(ubuntu)的mac是固定写在interfaces文件里面,主路由给N1(ubuntu)分配静态ip。mac0虚拟网卡也自动配备了mac地址,但是主路由在读取mac0的mac地址的时候,生成了两个host,一个是N1(ubuntu),另一个是mac0,并且这两个mac是一样的。这就导致了N1(ubuntu)只有一个ip地址,但是却有两个mac地址,主路由一直在不停的切换,导致发热增大,后面只能重启。即使把mac0绑定静态ip锁住mac码,主路由还是读出N1有两个mac。小白一个,实在搞不明白,请求帮助,谢谢。

CC342 avatar Jun 16 '20 02:06 CC342

我搞了另一个做法 网卡A上的macvlan作为单臂路由lan口,和单网卡配置方式一样 网卡B通过DHCP或者其他方式指定网关为macvlan的ip 宿主机指定其他接口的网桥接口docker0网段,SNAT到网卡B上 宿主机自己默认网关使用网卡B 不过这段我还没试。。。这样宿主机倒是不用改网桥

origalin avatar Dec 09 '20 12:12 origalin

在容器中做tproxy可能够呛,我在podman里部署带tproxy的v2,结果提示权限不足,root下启动容器也一样… 而且openwrt本身也要部署一些防火墙规则,在容器中怕不是要把人头搞大…

daiaji avatar Jan 09 '21 03:01 daiaji

遇到个奇怪的问题,我有4个网口A,B,C,D, 网口A在容器内是eth0作为wan,网口B,C,D分别为eth1, eth2, eth3,这3个网口在openwrt里面被桥接到br-lan,奇怪的是只有B网口接上电脑能上网(其余C,D网口表现为访问不到网关,tcp udp ping均不行)。 如果我把B网口去掉不挂进容器,只用C,D两个网口桥接到br-lan,也只有C网口能够上网,D网口无法连接网关跟上面表现一致,百思不得解😭

lazywen avatar Oct 24 '21 16:10 lazywen

非要跑macvlan的话果然要特权模式,不知道能不能用普通的网桥。

daiaji avatar Oct 25 '21 01:10 daiaji

非要跑macvlan的话果然要特权模式,不知道能不能用普通的网桥。

可以的,--cap-add NET_ADMIN,如果需要拨号的话宿主机先加载pppoe模块, 再加上 --device /dev/ppp,可以避免使用特权模式

lazywen avatar Oct 25 '21 01:10 lazywen