硬件
目前使用的是天钡 WTR R1,配置如下:
-
CPU: Intel N100
-
内存:16G
-
硬盘:256G 固态做系统盘,4T+16T 机械做数据盘
系统
PVE
PVE是一个可以运行在裸机上的开源虚拟机系统,基于debian和qemu/kvm,同时提供了方便的web和cli界面。官网:https://pve.proxmox.com/。
虚拟机配置
目前我的主力nas系统是一个叫做OpenMediaVault的系统,相比于命令行,它提供了一个简单的管理nas的图形界面,方便快速配置一些服务。
这里我贴上在pve里面的虚拟机配置,就不一一细讲了:
其中配置比较麻烦的是最下面的PCI设备,这是将显卡直通到了虚拟机里,需要启用IOMMU等功能,我也是一知半解地搞好了,有需要的可以搜索关键字“PVE显卡直通”查详细资料。
官网的资料:PCI(e)_Passthrough、PCI_Passthrough。
磁盘
物理磁盘上,目前我有两块机械硬盘(4T+16T),一块固态(256G),没有组raid,纯手工管理。
固态上主要用于放置虚拟系统的虚拟盘,因此其中跑的各种服务的数据库也在固态上放着,能加快服务的访问。
机械盘里面主要存数据,比如下载的电影电视、备份的照片与文件等等。
通常,使用pve时每个系统会挂在各自的硬盘,但是对我来说,各个系统之间数据共享是很重要的,例如我在群晖(单独的系统)上备份的照片,需要立即在samba、nfs、nextcloud等地方(nas系统)能看到,这就需要它们之间能够共享同一个目录。
所以最终我选择的方案是:宿主机挂载物理硬盘,然后通过9pfs/virtiofs等文件系统分享给虚拟系统。 这两个文件系统都可以实现虚拟机内外共享目录,其原理是转发虚拟机内的文件系统操作到宿主机,不过不需要走网络请求,本地传输理论上会快一些。
不过pve自身并不支持这两个方案,所以需要在conf文件中手动修改qemu的命令行参数,会有一点麻烦。
这两个使用和配置起来有些差异,最终我选择了virtiofs。
9pfs(弃用)
之前看韦易笑大佬的文章配置的,所以一开始我使用的9pfs,但是用过一段时间之后,发现有一些比较影响使用的问题:
- 性能问题
经过一段时间的使用,发现通过9pfs挂载的目录性能很成问题,7zip解压、rsync同步等都很慢,就连nextcloud的速度也会变得很慢,可能是随机读写慢?这点有点无法接受。
- 不支持nfs
之前预计是在虚拟机的nas系统中启用nfs和samba,但是发现9pfs不支持nfs。
- sqlite无法读取,影响jellyfin的运行,原因是在默认的参数下,mmap无法在9pfs中调用:
通过给挂载参数中添加cache=mmap解决。
-
参考
virtio-fs(选这个)
virtiofs配置稍微麻烦一点,但性能要比9pfs好很多(同样一个zip文件,肉眼可见大概比9pfs快2-3倍左右),同时限制也更少(直接支持nfs、mmap)。
virtiofs并不是qemu内置支持的,而是需要运行一个后台进程virtiofsd。这个后台进程需要跟着虚拟机启动时开启,虚拟机关闭时关闭,所以可以通过pve的hookscript来实现:
- 在
/var/lib/vz/snippets
目录下新建文件nas-hookscript.sh
,添加以下内容:
#!/bin/sh
vmid=$1
phase=$2
case $phase in
pre-start)
echo pre-start vmid=$vmid phase=$phase
systemd-run -G --unit=virtiofsd /usr/libexec/virtiofsd --shared-dir /mnt --socket-path /run/virtiofs-sea.sock --announce-submounts --inode-file-handles=mandatory --syslog
;;
esac
其中,—shared-dir参数需要替换成需要的目录。
然后通过qm set 102 --hookscript local:snippets/nas-hookscript.sh
命令,将该脚本设置为虚拟机的hookscript,这里的102是虚拟机id。
这里使用systemd-run是因为hookscript需要立即退出,所以里面运行的daemon进程必须得是double-fork之后的,不能阻塞hookscript,而systemd-run默认会让进程以服务的形式运行,同时也支持将日志重定向到journald(这里通过—unit=virtiofsd
选项将这条命令作为一个具名的临时服务运行了)。
virtiofsd命令会等待第一个客户端连接(也就是虚拟机启动后),第一个客户端断开连接后virtiofsd会结束进程。
- 打开pve的conf文件,目录一般在
/etc/pve/qemu-server
中,文件名是$虚拟机ID.conf
,在里面添加如下一行:
args: -chardev socket,id=char0,path=/run/virtiofs-sea.sock -device vhost-user-fs-pci,queue-size=1024,chardev=char0,tag=sea -object memory-backend-file,id=mem,size=6G,mem-path=/dev/shm,share=on -numa node,memdev=mem -m 6G
其中,两个6G
按照需要设置,它们的大小其实就是你要给虚拟机的内存大小(-m会覆盖pve的设置)。
/run/virtiofs-sea.sock是上面virtiofs监听的sock文件。
还有一点是这里要用/dev/shm
做共享内存,/dev/shm
默认是物理内存的一半,可能会不够用,可以在fstab中添加一行tmpfs /dev/shm tmpfs defaults,size=8G 0 0
适当增加shm的大小。
至于为什么要配置这一大堆内存相关的东西(numa、shm之类的)我目前不太清楚,官方文档暂时是这样推荐的,后面在慢慢了解吧。
- 添加完之后重启虚拟机即可。不出意外的话,通过
systemctl status virtiofsd
可以看到daemon正常启动了,日志里面也会有Client connected, servicing requests
的提示。这时候就可以进入虚拟机系统挂载文件系统了,在fstab中添加:
sea /mnt virtiofs rw 0 0 # 这里的sea是在qemu命令中设置的tag名
执行mount -a
进行挂载即可。
这里要注意tag不能是mnt,会导致各种报错,不确定什么原因……
-
参考
https://virtio-fs.gitlab.io/howto-qemu.html
https://forum.proxmox.com/threads/virtiofsd-in-pve-8-0-x.130531/
OpenMediaVault
OpenMediaVault是一个开源的nas系统,同样是基于debian。使用一段时间下来发现它提供的主要功能就是一个图形化的web界面,在里面可以快速配置邮箱、定时任务、nfs、samba等服务,也能查看监控等,更多其余的服务还是得自己配置docker。
(下面会把OpenMediaVault简写为omv。)
问题
这里记录一下使用时遇到的几个问题。
/dev/dri
权限问题
omv中默认的dri目录内的权限是660,非root非render组的用户无法访问,但是由于我的很多服务都没有直接使用root账户跑,在docker里面也不方便加组,所以就需要改下udev的规则,将/dev/dri/
的权限改为666。
修改文件/lib/udev/rules.d/50-udev-default.rules
,在其中找renderD*字样,将那一行的MODE改为"0666",然后重启即可:
- (使用9pfs时遇到,virtiofs不会遇到)omv里面的qbittorrent/nextcloud等服务提示打开文件过多,一开始以为是omv里面的ulimit设置的太小,只有1024,但是后面排查下来,发现只有通过9pfs挂载的目录会出现这个问题,所以去查了pve的ulimit,也只有1024,同时查看当前虚拟机的kvm进程的打开文件数量,刚好到了1024,所以实际的原因是9pfs要使用的文件描述符不够了。
需要在pve宿主机上面增加ulimit数量:
- 打开
/etc/security/limits.conf
,加两行内容:
```text
root - nofile 128000
* - nofile 128000
```
- 打开
/etc/systemd/system.conf
,添加一行内容:
```纯文本
DefaultLimitNOFILE=128000:524288
```
然后重启pve即可。
软件
接下来简单介绍下系统中部署的软件与服务。
关于数据存放
目前大部分服务都是在docker中部署的,docker容器需要保存的数据一般不会太大,目前跑的8个容器,需要保存和备份的数据总共也就4G,其中大头是nextcloud和jellyfin的数据库,所以将这些数据都放到固态上,不会有多少存储压力,还能显著提高这些服务的访问速度。
至于媒体文件、网盘内容文件等,则放到机械盘上面,速度通常不会影响太多。
nginx和域名
- 跑在docker中,代理omv的主页。 omv默认有自己的nginx,不过是在omv宿主机上,不方便管理,因此我把omv的nginx监听到了其他端口上,然后单独跑了个nginx容器,用容器里面的nginx做主服务器,nextcloud、jellyfin以及omv等服务跑在这个服务后面。
certbot/ddns
- 自己用python造的轮子,支持阿里的dns服务,定时检查来实现ddns。
- 证书更新则使用certbot-cli的hook完成dns-challenge,运行一遍之后,certbot可以自己记下命令,特别方便。
root@nas ~/d/ddns cat certbot-cert.sh | tail -n 10
sudo certbot -d $DOMAIN --manual \
--preferred-challenges dns \
--renew-by-default \
certonly \
--manual-auth-hook "$PWD/certbot-hook.py -c $ALI_CONFIG" \
--manual-cleanup-hook "$PWD/certbot-hook.py -c $ALI_CONFIG" \
--cert-name $DOMAIN \
--non-interactive \
--agree-tos --email xxx
root@nas ~/d/ddns cat certbot-hook.py | tail -n 15 | head -n 11
init_ali_client(config['access_key'], config['access_key_secret'])
is_cleanup = os.environ.get('CERTBOT_AUTH_OUTPUT', None) is not None
domain = '_acme-challenge.' + os.environ['CERTBOT_DOMAIN']
value = os.environ['CERTBOT_VALIDATION']
if not is_cleanup:
update_dns_record(domain, value, allow_add=True, type_='TXT')
print(f'updated record for domain {domain}')
else:
delete_dns_record(domain=domain, type_='TXT')
print(f'deleted record for domain {domain}')
PT服务:qbittorrent
媒体库:Jellyfin Plex
文件管理与共享:samba + nfs + nextcloud
文件同步
- Syncthing
- 阿里云邮箱+自定义域名
监控:graphite采集数据,grafana展示数据
- 部署到另外一台虚拟机上,避免nas系统挂掉的问题
备份
定时备份
rsync备份命令:~~~~rsync -r --links /root/docker /mnt/sea/docker-backup/ --exclude 'docker/qbittorrent/data/config/qBittorrent/ipc-socket'
~~~~,将命令添加到crontab中即可。备份所需要的时间比较长,通常得四五分钟的样子。备份期间,CPU占用大概在10%-20%,主要应该是rsync在校验数据。考虑到目前设置的每周执行一次,这个速度与CPU使用率还可以接受。- zip备份命令:
zip -ryq /mnt/sea/docker-backup.zip /root/docker/ -x 'docker/qbittorrent/data/config/qBittorrent/ipc-socket'
。切换到zip的原因是方便上传到对象存储、网盘等地方,同时也能压缩一次,减小一些体积。而且使用时发现zip的-f
选项增量更新时,速度要比rsync快不少,大概30s左右就可以结束运行,不过运行时的CPU使用率就比较高,大概在50%左右。理论上,如果使用-0
选项,也就是不压缩的话,速度应该可以更快一些。
需要备份的数据
- docker数据
网络
- openwrt