Linux Mascot

选择Docker容器的原因

Docker容器是现今非常流行的虚拟化方案,Docker容器虚拟化与传统虚拟化有着很大的区别。与传统虚拟化相比,Docker容器直接调用宿主机的内核,执行效率比传统虚拟化更高占用的系统资源更少。因此尝试用Docker容器运行Openwrt,作为二级网关(旁路由)甚至作为主路由使用也可,达到充分发挥利用设备性能的目的。

需要的硬件及资源

备注:本文基于Archlinux,其他Linux发行版可能不适用。

安装方法及步骤

1)运行下记命令安装docker

1
sudo pacman -Sy docker

2)把当前用户添加到docker用户组

1
usermod -aG docker $USER 

3)启动docker并添加到开机启动项

1
sudo systemctl start docker && sudo systemctl enable docker

4)注销并重新登入当前用户后就可正常使用docker命令了

5)打开网卡的混杂模式并加载pppoe和xt_TPROXY模块。(建议设置开机自动打开网卡混杂模式及加载pppoe和xt_TPROXY模块。)

手动打开网卡混杂模式运行下记命令:

1
sudo ip link set enp2s0 promisc on

手动加载pppoe和xt_TPROXY模块运行下记命令:

1
sudo modprobe pppoe && sudo modprobe xt_TPROXY

设置开机自动打开网卡混杂模式
创建/etc/systemd/system/promisc.service并添加下记内容(打开网卡混杂模式):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit]
Description=net interface management
After=network.target

[Service]
User=root
Type=oneshot
ExecStart=/usr/bin/ip link set enp2s0 promisc on
#ExecStart=/usr/bin/ip link add mac0 link enp2s0 type macvlan mode bridge
#ExecStart=/usr/bin/ip link set mac0 up
TimeoutSec=0
#StandardIput=tty
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

添加保存后运行下记命令添加到开机启动项

1
sudo systemctl enable promisc.service

设置开机自动加载pppoe及xt_TPROXY模块
创建/etc/modules-loaded/pppoe.conf并添加下记内容

1
2
pppoe
xt_TPROXY

6)导入Openwrt Rootfs到Docker本地镜像并创建添加Docker网络
导入镜像运行下记命令:

1
docker import https://downloads.openwrt.org/releases/18.06.8/targets/x86/generic/openwrt-18.06.8-x86-generic-generic-rootfs.tar.gz openwrt

创建docker网络运行下记命令:

1
docker network create -d macvlan --subnet=192.168.0.0/24 --gateway=192.168.0.1 -o parent=enp2s0 macnet

到此前期准备工作完毕。

7)执行下记命令通过docker容器运行Openwrt

1
docker run --restart always -d --network macnet --device /dev/ppp --hostname OpenWRT --cap-add NET_ADMIN --name alpha openwrt /sbin/init

8)修改Docker容器中Openwrt的网络配置
经过上面的一系列操作,Openwrt已经运行在Docker容器中了,但是我们还是无法通过浏览器访问Openwrt的WebUI。因为官方Openwrt的默认LAN IP地址是192.168.1.1,我们需要修改Openwrt的LAN IP地址(和我们的主路由同一网段)并重启Openwrt的网络才能正常访问。要修改Docker容器中Openwrt的网络配置我们就需要进入Docker容器的交互模式。
运行下记命令进入Docker容器中Openwrt的交互模式

1
docker exec -it alpha /bin/sh

进入交互模式后,下面的操作都是在Openwrt中进行。
用vi编辑器打开/etc/config/network并修改里面的LAN IP地址,保存运行下记命令重启Openwrt的网络服务。
我这边主路由的IP地址是192.168.0.1,所以我把Openwrt的LAN IP设为192.168.0.2

1
/etc/init.d/network restart

Openwrt的网络重启后输入exit退出交互模式,就可以通过浏览器访问192.168.0.2进入Openwrt的WebUI。

9)宿主机的网络配置
此时还有一个问题,由于Docker容器使用的是macvlan网络,宿主机和容器之间的通讯是隔断的,宿主机上无法访问Openwrt的WebUI。
需要在宿主机上创建一个虚拟的网络接口才能实现与容器的通讯。
手动添加可用下记命令,每次重启后要重新添加。

1
ip link add mac0 link enp2s0 type macvlan mode bridge && ip link set mac0 up

如果要每次开机自动添加,可修改前面的/etc/systemd/system/promisc.service,改成和下面的内容一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit]
Description=net interface management
After=network.target

[Service]
User=root
Type=oneshot
ExecStart=/usr/bin/ip link set enp2s0 promisc on
ExecStart=/usr/bin/ip link add mac0 link enp2s0 type macvlan mode bridge
ExecStart=/usr/bin/ip link set mac0 up
TimeoutSec=0
#StandardIput=tty
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

由于Archlinux默认是用systemd-networkd来管理网络的,因此还需要在/etc/systemd/network文件夹创建一个网络配置文件20-wired.network,这样新建的虚拟接口才能获取IP地址。20-wired.network内容如下:

1
2
3
4
5
6
7
8
9
[Match]
Name=mac0

[Network]
DHCP=ipv4
#Address=192.168.0.254/24
#Gateway=192.168.0.1
#DNS=192.168.0.1
#DNS=8.8.8.8

10)旁路由的网络设置
Docker容器中的Openwrt用作旁路由时,LAN接口的需要关闭DHCP服务。还需要添加下面的防火墙规则(网络->防火墙->自定义规则):

1
iptables -t nat -I POSTROUTING -o eth0 -j MASQUERADE

扩展知识

在Docker中创建自定义网关和掩码的桥接网络

1
docker network create -d bridge --subnet 192.168.0.0/24 --gateway 192.168.0.1 apps

假如你的主机有两个或两个以上网口,可以为每个网口都创建docker的macvlan网络并添加到容器中。
为容器添加网络可以运行下记命令

1
docker network connect NETWORK CONTAINER

NETWORK为要给容器添加的网络的名称,CONTAINER为要添加网络的容器名称。