基于LXC容器的Openwrt搭建
前期工作
环境和机器配置:
- 机器:5105v4 i226-v版本
- pve: 7.1.2,内核Linux 5.13.19-2-pve
准备工作:
- 将网线连接到pve管理口,如果已安装openwrt,然后关闭原openwrt虚拟机,删除直通的网卡。
- 准备一份没有引导的openwrt固件包,可以是img也可以是tar.gz,但一定是没有引导的包,可以看文件名中包含rootfs字符,比如openwrt-x86-64-generic-ext4-rootfs.img或openwrt-21.02.0-x86-64-rootfs.tar.gz(前者是我自己编译的,重点在于rootfs)。
PVE直通配置
连接到PVE,输入命令:
nano /etc/default/grub
找到下面这一行:
GRUB_CMDLINE_LINUX_DEFAULT="quiet"
然后添加intel_iommu=on
,这是英特尔的直通配置,AMD需要自行查找配置命令:
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on"
然后更新引导:
update-grub
修改nano /etc/modules内核模块文件,添加直通的驱动,让系统启动的时候载入这些驱动:
vfio
vfio_iommu_type1
vfio_pci
vfio_virqfd
执行命令来更新内核:
update-initramfs -u -k all.
创建基础环境文件包
tar.gz格式
如果包后缀为tar.gz,则通过scp直接上传至pve,以下[]
内的字符根据自己情况进行替换(包括[和]
符号),然后跳至下一章节:
scp [固件路径.tar.gz] root@[pveIP地址]:/var/lib/vz/template/cache
img格式
上传固件:
scp [固件路径.img] root@[pveIP地址]:/root
这里需要注意,如果你的固件包是带squashfs字符,比如openwrt-x86-64-generic-squashfs-rootfs.img,你需要按照下面的方式进行解压。 安装解压包:
apt install squashfs-tools
解压镜像文件:
unsquashfs [固件路径.img]
解压完成后你在同级目录下会得到squashfs-root文件夹,然后进入该文件夹,跳至3步骤。 如果你是不带squashfs字符,比如openwrt-x86-64-generic-ext4-rootfs.img,则需要通过挂载镜像,得到内部文件,首先创建一个挂载点(下面操作在root目录中进行):
mkdir op
然后挂载镜像:
mount -t ext4 -o loop [固件路径.img] /root/op
然后进入/root/op,跳至3步骤(完成后,通过使用umount /root/op进行卸载镜像)。
打包为pve的CT模板包:
进入上述2步骤中得到的文件夹中,然后使用下列命令进行打包,得到的文件下文称为op-ct模版:
tar zcf /var/lib/vz/template/cache/[固件名称].tar.gz ./*
创建容器
准备工作做完后,就开始创建lxc容器,通过下列命令进行创建:
pct create 110 local:vztmpl/openwrt-x86-64-generic-ext4-rootfs.tar.gz --rootfs local-lvm:2 --ostype unmanaged --hostname openwrt-ct --arch amd64 --cores 2 --memory 1024 --swap 0 -net0 bridge=vmbr0,name=eth0
这里详细说明一下每个参数的意思,使用的时候需要根据自己的情况进行更改:
pct create:容器创建命令
110:容器ID,可根据自己情况设定
local:vztmpl/openwrt-x86-64-generic-ext4-rootfs.tar.gz: 为第三步骤所得到的固件包名称
--rootfs:模版为rootfs文件
local-lvm:2 :后面的数字代表分配的磁盘大小,比如我这里设置的为2,即为即将创建的容器分配2G的大小
--ostype unmanaged:操作系统类型,这里没有填写指定的操作系统(不会影响)
--hostname openwrt-ct:主机名,也就是虚拟机名称
--arch amd64:设置为64位
--cores 2:分配给容器的核心数(我不知道这里是不是和docker一样,为最大限制)
--memory 1024:分配给容器最大的内存数量
--swap 0:交换分区设置为0
-net0 bridge=vmbr0,name=eth0:网卡,这里一定要设置,不然你的op没有办法连接到pve的虚拟交换机。
按照上述命令执行完成后,应该会得到如下的内容:
root@pve:/var/lib/vz/template/cache# pct create 110 local:vztmpl/openwrt-x86-64-generic-ext4-rootfs.tar.gz --rootfs local-lvm:2 --ostype unmanaged --hostname openwrt-ct --arch amd64 --cores 2 --memory 1024 --swap 0 -net0 bridge=vmbr0,name=eth0
Logical volume "vm-110-disk-0" created.
Creating filesystem with 524288 4k blocks and 131072 inodes
Filesystem UUID: 15d6753a-ceb2-45d3-9dca-903f97f0f197
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912
extracting archive '/var/lib/vz/template/cache/openwrt-x86-64-generic-ext4-rootfs.tar.gz'
Total bytes read: 143063040 (137MiB, 86MiB/s)
网卡直通
编辑lxc容器的配置文件,进行网卡直通:
vim /etc/pve/lxc/[容器ID].conf
在最下面添加以下内容:
# openwrt.common.conf是PVE自带的openwrt配置文件示例,内含一些基本设置
lxc.include: /usr/share/lxc/config/openwrt.common.conf
# /dev/ppp pppoe拨号等功能需要用到
lxc.cgroup.devices.allow: c 108:0 rwm
# 钩子脚本,用于添加 /dev/ppp等设备
hookscript: local:snippets/hookscript.pl
# 这里是网卡直通重要的部分。
lxc.net.1.type: phys
lxc.net.1.link: enp3s0
lxc.net.1.flags: up
lxc.net.2.type: phys
lxc.net.2.link: enp4s0
lxc.net.2.flags: up
lxc.net.3.type: phys
lxc.net.3.link: enp5s0
lxc.net.3.flags: up
需要注意,网卡直通部分里面的网卡名字,需要根据pve控制面板选择【pve】-【系统】-【网络】中查看,其中一定避免管理口,我这里是enp2s0为管理口,所以没有直通,而是在启动容器的时候,作为桥接接进来了。我的软路由为5105四口,所以这里排除了管理口,我直通了2-4网口。 除此之外,lxc.cgroup.devices.allow: c 108:0 rwm为ppp字符设备的主次设备编号,其中108为ppp设备主编号,0为设备次编号,获取这个编号可以通过ls -al /dev/ppp获取,大致返回如下的内容。
root@pve:~# ls -al /dev/ppp
crw------- 1 root root 108, 0 Sep 9 21:07 /dev/ppp
创建pve容器启动时的钩子脚本,用于配置ppp设备的添加等。
mkdir /var/lib/vz/snippets
cp /usr/share/pve-docs/examples/guest-example-hookscript.pl /var/lib/vz/snippets/hookscript.pl
vim /var/lib/vz/snippets/hookscript.pl
然后修改内容:
在第36行可以找到以下内容
# Second phase 'post-start' will be executed after the guest
# successfully started.
print "$vmid started successfully.\n";
修改为
# Second phase 'post-start' will be executed after the guest
# successfully started.
system("lxc-device add -n $vmid /dev/ppp");
system("lxc-device add -n $vmid /dev/net/tun");
print "$vmid started successfully.\n";
设置防火墙
在pve管理界面,选择创建的容器,然后切换至防火墙页面,点击添加,然后添加两次,每次只需要改动方向in和out和勾选启用。按照下面的教程中,设置端口好像报错,但不设置设备接入后又无法联网,但这样添加后,即可联网。
重启
重启整个pve,如果不重启直接启动容器,这个网卡会提示找不到,具体原因暂不知道。重启后,即可启动容器,按照正常的openwrt配置即可。
其他
这里配置openwrt的时候需要注意,因为网卡是直通的,所以网卡名可能和虚拟机不一样,虚拟机中是eth0-3,而在容器里面,除了指定的eth0(管理口,也是网口1),剩余的网口名称为enp3s0、enp4s0、enp5s0,也就是对应的2、3、4口(我的环境下),所以根据自身情况选择对应的网口分配wan和lan口进行。
在设置完wan口和防火墙后,openwrt拨号设置后,你需要重启pve,才能生效。我猜测这是因为拨号配置是挂载的pve的,所以pve将配置文件载入到内存中,即使重启容器也还是从pve内存中读,应该有其他方法在pve中重载入配置文件,但目前我没有找到。
参考
- https://www.right.com.cn/forum/thread-8218119-1-1.html
- https://blog.csdn.net/kangzeru/article/details/115373587
- https://4xu.net/posts/koolshare-2.html/
- https://pvecli.xuan2host.com/lxc-network-bypass/
- https://39.108.190.212/archives/42.html