利用LXD系统容器打造基于AArch64架构的高性能软路由解决方案

前言

前段时间购入了NanoPi R4S这个带双千兆网口的小玩具,但一直苦于找不到合适的应用场景。正巧先前使用的RM2100的开源驱动在5Ghz频段连接总是不稳定,故打算对目前的网络接入方式进行一个小小的改造,计划采用AC+AP方案,将R4S作为校园网拨号、QOS、带宽监控和代理的主路由,而RM2100使用Padavan提供的闭源驱动,工作在无线接入点模式,以提供稳定的无线连接。在折腾的过程中,由于R4S在内的一众基于AArch64的开发板均无ACPI支持,在尝试KVM虚拟化等过程中遇到了无数的问题,故简单在此记录踩坑经历:D

需求简述

NanoPi R4S搭载的是一颗具有mainline内核支持的瑞芯微RK3399 SOC,FriendlyElec为其移植了基于OpenWrt的FriendlyWrt系统,而OpenWrt的22.03版本也针对该设备提供了mainline的固件支持。但是作为一个拥有6核CPU和4GB内存的设备,R4S上除路由功能之外自然具有部署其它应用的需求。在OpenWrt中部署Docker容器是解决方案之一,但更新OpenWrt版本带来的迁移工作会较为繁琐,且其本身内核的稳定性仍待考究。因此,使用FriendlyElec提供的基于Ubuntu 20.04版本的系统镜像,配合虚拟化技术运行OpenWrt系统,同时将eth0和eth1两个接口直通到guest中就成为了更好的解决方案之一。

踩坑KVM

在Linux上实现虚拟化最直接的方案自然是KVM了。使用kvm_ok命令发现,FriendlyElec编译的内核没有开启KVM选项。

尝试下载FriendElec提供的内核,在config中启用KVM及其相关选项,之后利用瑞芯微的sd_update程序刷写内核文件到对应的raw分区,结果在uboot加载内核部分出现问题,系统无法顺利启动。查阅资料得知与处理器特权等级相关,尝试更新uboot版本等方法无果,遂暂时放弃KVM方案。

试水LXD

在OpenWrt的官方文档中提到将该系统在Docker内运行时会有部分不可用功能。与Docker不同,LXD提供了一种更接近于虚拟机的方案。在LXD主页的Introduction部分中提到:

Application containers vs. system containers – LXD Introduction

You can use system containers to create different user spaces and isolate all processes belonging to each user space, which is not what application containers are intended for.

LXD作为系统容器,利用cgroup特性共享Host的操作系统内核,使得Linux镜像可以作为轻量级容器与Host同时运行。LXD主页通过一张对比图说明了其与Docker等application containers管理器的不同。

LXD Introduction中两种container类型的对比图

因此,在LXD中运行OpenWrt可以在使用其全部功能的情况下避免QEMU软件虚拟化带来的性能损失。

LXD使用snap方式进行分发,使用snap安装其5.5版本:

在创建container的过程中,我所使用的4.19内核版本镜像在procfs的auto mount步骤会发生问题,报错信息如下:

lxc openwrt 20220911080745.614 ERROR    utils - ../src/src/lxc/utils.c:safe_mount:1221 - Device or resource busy - Failed to mount "proc" onto "/var/snap/lxd/common/lxc//proc"

搜索互联网发现没有相关解决方案,故我在Stack Exchange上发布提问,可惜的是直至今日也没有得到回答:( 在尝试多种办法均碰壁的情况下,我尝试更换FriendElec提供了5.15内核版本Ubuntu 20.04镜像,发现新版本内核不会出现该问题,LXD容器可以顺利启动。

容器配置

在LXD中创建了OpenWrt容器之后,需要配置网卡的直通。NanoPi R4S使用了RealTek RTL8211E 和R8111H芯片提供了两个1GBps速率的网口。LXD提供了bridged、macvlan、sriov、ovn、physical、ipvlan、p2p、routed几种NIC类型,在其中有详细介绍。

对于我们的需求,配置参数以实现网卡直通容器:

devices:
  eth0:
    nictype: physical
    parent: eth0
    type: nic
  eth1:
    nictype: physical
    parent: eth1
    type: nic

同时,R4S运行的Ubuntu系统同样需要网络访问,故在device中添加p2p虚拟接口如下:

  veth0:
    host_name: veth1
    nictype: p2p
    type: nic

此时,容器中可以访问到上述几个网络设备:

而在Host侧,与文档中的描述相同,直通的接口均不再显示。

OpenWrt配置

进入OpenWrt的LuCI界面,配置br_lan网桥,桥接R4S上的LAN口和主机Ubuntu系统的veth接口:

将接口中的LAN绑定到该网桥设备上:

至此,OpenWrt的基本配置基本完成。

Host侧静态IP/端口转发配置

为了更容易地访问到Host的Ubuntu系统,我们还需要进行一些额外的配置。首先,需要为其设置静态IP,方便后续端口转发配置时定位该主机。使用systemd-networkd配置如下:

重启systemd-networkd服务后,veth接口便不再从DHCP服务器中请求IP,而是使用固定的192.168.1.2地址。

在Host拥有了固定的IP地址后,可以在OpenWrt中配置端口转发以及防火墙入站规则:

至此,在WAN区域使用5022端口即可直接连接Ubuntu系统的SSH。

总结

使用容器部署OpenWrt,再由容器中的系统反向为Host提供网络接入对我而言是一个比较独特的方案。截至今天,R4S和RM2100已经稳定运行一周有余,而Ubuntu系统中也通过Docker方式部署了Clash、Yacd、Code Server等服务。与先前RM2100作为主路由的情况相比,R4S的性能可以更好地支撑QOS等需求,提供更良好的网络环境。

OpenWrt系统状态页
R4S+RM2100

然而,该方案也存在一定的问题。当容器中的OpenWrt系统未能正常启动时,我们就无法访问Host Ubuntu系统,需要使用USART Debug接口访问主机。但由于USB接口没有直通到容器中,使用USB网卡进行调试可能也是解决方案之一。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇