最近闲着无聊折腾了下放在客厅里的x86小nas,装了个openwrt作为旁路由用于分流上网。安装openwrt使用的方案既不是格盘重装,也不是exsi或者pve虚拟机安装,而是选择了安装在lxc容器里。本文不是正经教程,仅仅记录折腾时的思考和一些简单的步骤。
为什么不是虚拟机
最大的原因是这台nas已经稳定着omv系统用于nas服务,重装系统是不可能的。虚拟机本身的性能开销也是个大问题,有经验的朋友应该清楚,即使使用了virtio这样的半虚拟化驱动,虚拟机io仍然非常占用cpu。唯一的办法是硬件直通,而即便是硬件直通下,虚拟机的整体开销也比容器大一个数量级。
为什么是lxc
一句话简单科普下的话,lxc就是一个基于cgroup的linux容器技术。有些朋友就要问了,docker也是基于cgroup的,docker也能安装openwrt,为什么不选择鼎鼎有名的docker,而选择没什么人听说过的lxc呢?
一方面是lxc的实现方式。lxc实现了完整的系统容器化,这意味着在lxc容器里有完整的init生命周期和内核信号,完全可以当成一个仅支持linux系统的虚拟机使用。而docker的设计目标则是进程容器化。所谓的进程容器化就是一个容器里只跑一个进程,多进程分别安装在多个容器里。在docker里安装openwrt显然有悖于这一目标,即使可以通过/sbin/init方式来启动容器也会发生很多其他问题。
问题之一是网络支持。docker默认的桥接网络是only-host,不能用于路由。而host模式则直接无法启动openwrt,唯一可选的模式是macvlan。而macvlan有两个问题,其一是实现macvlan需要修改数据包包头并在内核io路径中做了特殊判断,这会带来可见的性能开销。其二是内核里macvlan与主机是单向隔离的,说人话就是容器里可以ping通主机但主机不能ping通容器。解决的办法有二,第一种是通过自定义路由表方式把数据包送出内核,让数据在交换机里转一圈再回来。第二种方式是新建一个macvlan方式的网桥并把主机网卡桥接上去,这样主机与容器处在同一个macvlan网络里,就不存在隔离问题了。这两种方案显然都会造成主机网络性能降低,对性能较低的小主机来说是无法接受的。而lxc则支持最普通的虚拟网桥,可以直接暴露在物理网络上,也可以无隔阂与主机通信。
问题之二是数据持久化问题。docker的设计思路是分层文件系统,容器里发生文件修改实际上是产生了一个新的数据层,这点容器构建来说非常友好,对运行无状态服务来说也没有丝毫问题,但是对openwrt这样时不时更新下软件包、更新下配置文件非常不友好。而lxc则简单粗暴很多,容器直接使用主机的一个文件夹或者块设备,维护与迁移都非常方便。
介于以上几个基本事实,至少在安装openwrt这件事上没有任何选择docker的理由。
如何使用lxc
借助搜索引擎的力量,可以发现openwrt官网上有wiki讲如何在lxc里安装openwrt。但里面的内容有些根本就是错的,建议朋友们不要去看了,浪费时间。
这里简单讲一下操作步骤给朋友们当作参考。首先是创建虚拟网桥。有很多方式可以创建一个虚拟网桥,因为没有绝对标准的方式所以这里不展开讲,只要把物理网卡桥接上了都行。
然后是安装lxc的工具集,同样要根据主机实际情况,debian系统的朋友可以使用apt直接安装。
# apt update && apt install -y lxc
接着在/var/lib/lxc文件夹下创建openwrt文件夹,再在里面创建rootfs文件夹和config文件。一定不能学官网教程上的把文件夹创建在用户文件夹里,那样容器是无法开机自启的。
接着去官网下载主机对应架构的rootfs.tar.gz压缩包,解压到rootfs文件夹里,此时的文件树类似这样。
接着编辑config文件,注释的地方是坑点需要特别注意。
我们还需要在容器启动前编辑容器的网卡配置。新建配置文件/var/lib/lxc/openwrt/etc/config/network,内容大致如下。
最后一步,执行lxc-start -n openwrt启动容器,然后执行lxc-attach -n openwrt进入容器内,使用opkg指令安装管理网页和其他工具。
opkg update && opkg install luci luci-i18n-base-zh-cn
至此局域网内就可以通过浏览器直接访问openwrt的管理网页。如何配制成旁路由分流上网不是本文重点不作赘叙。