高渐离の屋

一个不起眼的个人小站

0%

从零开始搭建NAS——坑爹的TrueNAS

距离上一篇文章其实已经过了有一阵子了,本来预计是想要很快写出第二篇的,但是由于各种各样的原因就一直拖了下去。

嗯,没错,我其实是在测试 NAS 的稳定性,一定不是太懒的原因。截止到今天(2022-12-4),NAS 已经连续运行 53 天了,在之前因为更新系统等原因不可避免重启了一两次,一直以来确实没出什么大问题。

还是相当稳定的

坑爹的 TrueNAS Core

上次在文章末尾我提到说,我被 TrueNAS Core 狠狠地坑了一把。

TrueNAS 是基于 FreeBSD 构建的操作系统,而作为皇城根下有通天纹的系统,自然是不屑于使用 Docker 的。FreeBSD 自有jails系统。

FreeBSD jail,一种操作系统层虚拟化技术,在 FreeBSD 操作系统中运作。利用这个技术,FreeBSD 的系统管理者,可以创造出几个小型的软件系统,这些软件系统被称为监狱(jails)

作为 Docker 的老前辈,平心而论,jails在 2000 年是具有非常划时代意义的新技术,而现有的容器技术例如 LXC 或者 Docker,也或多或少收到了他的启发。然而今年是 2022 年,jails 在当然的应用环境下已经显得力不从心。直接操作jails非常繁琐,因此 TrueNAS 提供了一个工具iocage,将jails操作简化成了类似docker的操作,还算方便。

网络坑

jails 的网络基于 BPF 实现,作为 eBPF 的前身,jails 可以提供 3 种网络模式:

  • DCHP。这个模式下的 jail 类似虚拟机,容器直接从 DHCP 服务获取 IP 地址,从网络拓扑上可以将 jail 视为独立设备。
  • 端口绑定。直接使用宿主机的网络端口,类似dockerhost模式,区别是前者只能使用一张网卡,而dockerhost可以使用所有网卡。
  • nat。类似 Docker 最常用的模式,使用端口转发。

乍一看好像没什么问题?直接模仿 Docker 无脑 nat 模式不就完了吗,该有的都有不是吗?让我们再来看看我需要部署的服务列表:

服务 功能 需要的端口 结果
Aria2 下载 6800 OK,下载不支持 IPv6
FreeRadius Wifi 鉴权 1812 OK
Qbittorrent BT 下载 51413 不支持 IPv6
Emby 媒体服务器 不重要 不支持 IPv6,不支持硬件加速

可以看到,在最重要的两个下载功能中,端口转发均明确表示不支持 IPv6(本来 V6 设计就不是给你 NAT 的)。此外,由于每个jail都有自己的 IP,众多服务也无法使用一个反向代理统一起来。

驱动坑

虽然我使用的是一块 zen2 的 R5 4400G,在这个 zen4 的年代来看已经不新了。但是很遗憾,他的显卡对于 FreeBSD 来说还是太新了,新到只有在最新的 FreeBSD 13.1 才堪堪提供了支持。而很遗憾的是,TrueNAS Core 的底层版本是 13.0,并且直接在宿主系统上更新包是不受支持的。于是接下来我就开始了徒劳且痛苦的尝试。

首先是尝试更新内核版本,既然freebsd-update不能使用,那我就编译更新内核好了。下载好了内核源码之后,又突然发现宿主系统没有cc编译器。这也难不到我,创建一个新的 jail,在里面安装编译器等工具,随后再将内核源代码挂载进去完成编译即可。

但是这么做的风险极高,首先是因为没有回滚的机会,TrueNAS Core 的系统更新不能用了,此外自己编译内核也非常的灵。而事实上,当我编译完成新的内核后,虽然他识别出了我的 GPU,但是运行vainfo依旧会报错,也不知道原因是什么。

另外由于 TrueNAS Core 和 TrueNAS Scale 共享一个名字,因此你能搜到的所有文档基本上都是 TrueNAS Scale 的,没文档的小众系统,我认为继续在上面投入是不值得的,早日弃暗投明吧。

迁移到 SCALE

TrueNAS 由于系统盘也使用了 ZFS,因此可以非常轻松的再多个操作系统之间迁移,回滚等操作:
一个启动盘上可以有多个OS
只不过毕竟是从 BSD 迁移到 Linux,配置文件还是有不兼容的部分,因此从 Core 迁移至 Scale 被定义为不可逆的过程。

更新过程也非常简单,和路由器刷机差不多。直接去网站的“手动下载”一项中找到.update文件下载,随后在 NAS 的手动更新中应用即可:
下载Update文件 手动更新

更新完后重启,再手动修改一些配置,就顺利变成 Linux 了!

SCALE

更新到了 SCALE 后,由于是熟悉的 Linux,文档也众多于是接下来的流程非常的顺滑,顺利解决了我的问题。めでたしめでたし!

如果你以为是这样,那就太 naive 了。

K8S

世界上怎么会有这么好的事情呢。虽然 TrueNAS SCALE 确实用了 Docker,但是又没完全用。别忘了人家名字里面有个scale,这个scale体现在哪里呢?没错,他给你整了个 K8S,你可以用多个 NAS 组成一个 K8S 集群,实现动态扩容,负载均衡等等功能……

有病吧!ybb

虽然我每天都在用 K8S(指自劫云),也喜欢搞起夜级的东西,但是这并不代表我要在家里面整个 K8S 啊!这东西我曾经尝试安装过,浪费了两天两夜最后还是没装好。kubectl那么多参数我从来就没整明白过。

不过幸好 TrueNAS 还是给你提供了一个 GUI 的,可以通过 GUI 管理容器的启停扩容。不过我只是简单的尝试了一下就把他抛弃了:
端口号不让低于9000
我的 8443 怎么办?
经过在网上的一通搜索,似乎不是只有我一个人遇到了这个问题:Containers: Minimum node port 9000?。但是很可惜,这个问题是 K8S 带来的,我没有任何办法修改:

According to the Jira ticket, and https://oteemo.com/2017/12/12/think-nodeport-kubernetes/, this isn’t a limitation with Scale, but with upstream Kubernetes k8s. Since the Scale applications deploy via Helm charts, they inherit the upstream k8s limits. However, I don’t see anything preventing you from running a container via Docker outside k8s.

那我就只能按照建议,直接起 Docker 容器咯。
另外由于部署了 K8S 环境,因此系统的虚拟网卡也被搞得一团乱麻,我们熟悉的docker0消失了,取而代之的是一大堆kube-bridge,kube-dummy-if,dummy0的网卡。直接用docker run命令起来的容器会直接没有网卡上不了网,但是我到此已经精疲力竭,没有心思去研究怎么把 k8s 的网卡挂载进入容器(多半也不支持),于是干脆直接--net=host了。

由于更新系统后这一大堆 docker 容器都会丢失,因此我又专门将启动的命令写到一个脚本里面,这样更新系统的时候可以快速恢复:

1
2
3
4
5
6
7
8
9
10
$ cat restore_docker.sh
#!/bin/sh
# qbittorrent
docker run -d --restart=always --net=host --name qbittorrent -v /mnt/main/Docker/qbittorrent/config:/config -v /mnt/main/User/BT:/downloads -e SavePath=/downloads -e TempPath=/downloads -e HOME=/config -e WEBUI_PORT=3560 linuxserver/qbittorrent:latest
# nginx
docker run -d --restart=always --name nginx --net=host -v /mnt/main/Docker/nginx/nginx:/etc/nginx -v /mnt/main/Docker/nginx/www:/www -v /mnt/main/Docker/nginx/modules:/modules nginx:stable-alpine
# aria2
docker run -d --restart=always --name=aria2 --net=host -v /mnt/main/Docker/aria2/config:/config -v /mnt/main/User/Common\ Download:/downloads gaojianli2333/aria2
# freeradius
docker run -d --restart=always --net=host --name radius -v /mnt/main/Docker/freeradius/raddb:/opt/etc/raddb freeradius/freeradius-server:3.2.0-alpine

gaojianli2333/aria2容器是我自己打包的,Dockerfile 如下:

1
2
3
4
5
FROM alpine:latest

RUN apk add --no-cache aria2

CMD ["aria2c","--conf=/config/aria2.conf"]

内存使用

在切换到 Scale 之后,NAS 可用内存明显变少了,表现为图表中“Services“部分所占内存明显增多。也就是说,本就并不充裕(我没钱做到 1T1G 的内存配置)的 ZFS 专用内存更少了,而这有可能是 Linux 内核本身不如 BSD 精简的原因,也有可能是那个 K8S 的锅。

更加雪上加霜的是,不知道是不是 OpenZFS 2.0 的配置问题,系统默认只会使用 12G 的内存用作 ZFS Cache,这和 Core 版本中空闲内存(也就是“Free”的部分)几乎为零形成了鲜明的对比。

为了解决这个问题,我还必须在Init Script中加上echo 30064771072 > /sys/module/zfs/parameters/zfs_arc_max这么一句来强迫 ZFS 使用尽可能多的内存。

总结

这样看来还真是可笑,不管是 Core 还是 Scale,提供的容器系统最后都没有用上,最终还是回归到了手工管理 Docker 上。只是这样 NAS 系统提供的功能其实就只有 ZFS 和报警功能了,如果你不用 ZFS 或者你可以手操 ZFS,那你完全可以用裸的 Linux 比如 Ubunut 或者 Arch,不必硬凹 NAS 系统。Scale 提供的 K8S 功能不能说完全没用,但是对于我的需求来说显然太过多余了,不过群晖等系统提供的 Docker 多半也有各种各样的问题(例如 IPv6)。

硬件变化

另外在这几个月中,我的 NAS 也做了一些硬件上的改动。我的主板提供了一根 PCIE X16 的插槽,而这一插槽长期被 X4 的TL-NT521占用未免有点可惜。因此我将其替换成了一张X540-T2的 FLR 卡,并搭配拆分卡弄出了 2 个额外的 M2。
拆分卡
这一套下来竟然只要 200 块,显得花 400 买全新 TPLink 的自己好像是个傻子,洋垃圾万岁!于是我又用卖掉TL-NT521换的钱添加了一张垃圾 SSD,作为阵列的 L2 ARC 使用,目前来看整体命中率还是挺高的。
命中率
剩下那个槽位因为我本身内存不足,因此再添置缓存也没有多大意义,或许以后可以考虑插一个 M2 转 SATA 的卡,加点硬盘。

では、諸君は。