2025-08-21 02:47:31
基本是从大二折腾到现在了。中间先后经历了Win作server,mcsm panel做管理端;ubuntu做系统;esxi当系统做all in one;以及现在,arch做宿主机系统,容器+systemd组合托管所有服务的方案。整体上方案是反复在折腾-稳定中间横跳。
本来最开始ubuntu的时候也是想all in one但是奈何用ubuntu的时候不太熟悉linux各种概念;加上ubuntu绑定snap,以及想试试esxi,遂试了esxi+ubuntu+windows的组合。
其实体验挺好的,虚拟机管理也方便,需要装新系统的时候也能随时从iso新创建一个。奈何一个是nvidia直通太困难了,而且esxi在操作硬件资源的时候还是不太方便所以最后又换掉了。
按理来说这下一步应该是pve,但是我在将大部分服务甚至windows/macos/linux都容器化之后,我发现似乎pve也没什么必要了。一来,容器的性能还是很顶的;二来,windows/linux的虚拟化方案kvm+qemu效果也很不错。而且吧,pve自己也是linux,我不怎么需要pve提供的各种虚拟化、资源池化能力,相反,容器相比vm的轻量级和不错的隔离性以及对资源占用的限制能力都不错,既然pve提供的核心能力用容器化已经可以解决了,那也就没必要再折腾了。其他pve的能力没用过也不清楚,但是应该和esxi的这部分差不多吧。
目前服务器的用处确实比刚开始丰富了太多。首先是mc,然后是代码托管,其他的很多,博客静态站、pt、数据查询服务、在线开发环境code-server、ollama、windows/macos虚拟机、云盘还有云剪贴板等等等等。它们大多数都使用docker-compose托管在服务器中;少部分使用systemd启动,作为基础设施提供一些面向服务器基础需求的服务,比如cloudflared‘
在构建个人 NAS 系统时,我们经常面临一个常见问题:如何将多块硬盘合并成一个统一的存储池,同时保持数据的安全性和访问效率?传统的 RAID 方案虽然稳定,但缺乏灵活性。今天,我将介绍一种基于 UnionFS 的解决方案——MergerFS,它能够智能地合并多个文件系统,并提供 Docker 容器化的网络共享服务。
UnionFS 是一种联合文件系统,它能够将多个目录(分支)透明地叠加成一个统一的视图。这种技术允许你在保持底层文件系统独立的同时,创建一个逻辑上的合并存储空间。
MergerFS 是基于 FUSE 实现的 UnionFS 变体,具有以下特点: - 无数据迁移:直接使用现有文件系统,无需格式化或移动数据 - 灵活扩展:随时添加或移除硬盘 - 策略驱动:可根据多种策略(如剩余空间、文件类型)决定文件存储位置 - 容错性:单块硬盘故障不影响其他硬盘的数据访问
很多用户在配置 MergerFS 时遇到启动失败的问题,根本原因在于系统启动时的挂载顺序。当系统通过 fstab 挂载时,它会并行处理所有挂载点,而 MergerFS 要求所有底层存储必须就绪后才能创建合并视图。
# 典型的 fstab 配置(容易失败)
/dev/nvme0n1p1 /mnt/nvme0 ext4 defaults 0 0
/dev/nvme1n1p1 /mnt/nvme1 ext4 defaults 0 0
/mnt/nvme* /mnt/union fuse.mergerfs defaults,allow_other,cache.files=partial 0 0问题在于:系统可能先尝试挂载 /mnt/union,而此时
/mnt/nvme* 尚未就绪,导致挂载失败。
以下脚本自动生成可靠的服务配置:
#!/bin/bash
# mergerfs-systemd-setup.sh
# 自动创建 systemd 服务来管理 mergerfs 挂载
# 配置变量(根据实际情况修改)
USER_NAME=$(whoami) # 或直接指定用户名
BASE_MOUNTS="/mnt/nvme*" # 底层存储挂载点模式
UNION_MOUNT="/mnt/union" # 合并存储挂载点
MOUNT_OPTS="cache.files=partial,dropcacheonclose=true,category.create=mfs,allow_other,minfreespace=4G"
echo "正在配置 MergerFS Systemd 服务..."
echo "用户: $USER_NAME"
echo "底层存储: $BASE_MOUNTS"
echo "合并点: $UNION_MOUNT"
# 1. 创建 systemd 服务文件
sudo tee /etc/systemd/system/mnt-union.service > /dev/null << EOF
[Unit]
Description=Merge storage drives with mergerfs
Documentation=https://github.com/trapexit/mergerfs
After=local-fs.target
RequiresMountsFor=$BASE_MOUNTS
# 动态生成依赖关系(适用于可变数量的硬盘)
$(for mount in $(eval echo $BASE_MOUNTS); do
if [ -d "$mount" ]; then
escaped_mount=$(systemd-escape -p --suffix=mount "$mount")
echo "Wants=$escaped_mount"
echo "After=$escaped_mount"
fi
done)
# 可选:等待网络服务(如果使用网络存储)
# After=network-online.target
# Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
# 创建挂载点目录(如果不存在)
ExecStartPre=/bin/mkdir -p $UNION_MOUNT
ExecStartPre=/bin/chown $USER_NAME:$USER_NAME $UNION_MOUNT
# 执行 mergerfs 挂载
ExecStart=/usr/bin/mergerfs -o $MOUNT_OPTS $BASE_MOUNTS $UNION_MOUNT
# 清理操作
ExecStop=/bin/fusermount3 -uz $UNION_MOUNT
# ExecStopPost=/bin/rmdir $UNION_MOUNT 2>/dev/null || true
# 用户和权限设置
User=$USER_NAME
Group=$USER_NAME
# 失败时重试
Restart=no
StartLimitInterval=100
StartLimitBurst=5
# 环境变量
Environment="MERGERFS_NOUSAGE=true"
# 安全设置
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=$UNION_MOUNT
[Install]
WantedBy=multi-user.target
EOF
echo "✅ Systemd 服务文件创建完成"
# 2. 清理可能冲突的 fstab 配置
echo "清理 fstab 中的旧配置..."
sudo sed -i '\|'"$UNION_MOUNT"'|d' /etc/fstab
sudo sed -i '/mergerfs/d' /etc/fstab
# 3. 重新加载并启用服务
sudo systemctl daemon-reload
sudo systemctl enable mnt-union.service
echo "✅ 服务配置完成"
echo ""
echo "接下来可以执行以下命令:"
echo "1. 启动服务: sudo systemctl start mnt-union.service"
echo "2. 查看状态: systemctl status mnt-union.service"
echo "3. 查看日志: journalctl -u mnt-union.service -f"
echo "4. 测试挂载: ls -la $UNION_MOUNT"# 完整的 MOUNT_OPTS 配置示例
MOUNT_OPTS="
# 基础选项
allow_other,defaults,auto_unmount
# 缓存策略
cache.files=partial, # 部分文件缓存
dropcacheonclose=true, # 关闭文件时清除缓存
cache.symlinks=true, # 缓存符号链接
cache.readdir=true, # 缓存目录列表
# 存储策略
category.create=mfs, # 新文件创建策略:最多剩余空间
minfreespace=4G, # 最小保留空间(防止写满)
moveonenospc=true, # 空间不足时自动移动文件
# 性能优化
func.getattr=newest, # 属性获取策略
fsname=mergerfs, # 文件系统名称
use_ino=true, # 保留inode号
# 安全选项
direct_io=false, # 禁用直接IO(提高兼容性)
kernel_cache=true, # 启用内核缓存
attr_timeout=3600, # 属性缓存超时(秒)
entry_timeout=3600, # 条目缓存超时(秒)
negative_timeout=3600 # 负结果缓存超时(秒)
"
# 简化版本(推荐日常使用)
MOUNT_OPTS="cache.files=partial,dropcacheonclose=true,category.create=mfs,allow_other,minfreespace=4G"现在我们已经有了稳定的合并存储,接下来通过 Docker 容器提供网络共享服务。
创建 docker-compose.yml 文件:
version: '3.8'
services:
# WebDAV 服务
webdav:
image: bytemark/webdav:latest
container_name: nas-webdav
restart: unless-stopped
environment:
- AUTH_TYPE=Digest
- USERNAME=admin
- PASSWORD=${WEBDAV_PASSWORD:-ChangeMe123}
- SERVER_NAMES=nas.local
ports:
- "8080:80"
volumes:
- /mnt/union:/var/lib/dav/data
- ./webdav-config:/var/lib/dav
user: "${UID:-1000}:${GID:-1000}"
networks:
- nas-network
# SMB/CIFS 服务
samba:
image: dperson/samba:latest
container_name: nas-samba
restart: unless-stopped
environment:
- TZ=${TZ:-Asia/Shanghai}
- USERID=${UID:-1000}
- GROUPID=${GID:-1000}
ports:
- "445:445"
- "139:139"
volumes:
- /mnt/union:/data
- ./samba-config:/etc/samba/external
command: >
-p
-u "admin;${SMB_PASSWORD:-ChangeMe123}"
-u "guest;guest"
-s "public;/data/public;yes;no;no;all;none"
-s "private;/data/private;yes;no;no;admin;admin,guest"
-s "media;/data/media;yes;no;no;all;admin"
stdin_open: true
tty: true
networks:
- nas-network
# NFS 服务
nfs:
image: erichough/nfs-server:latest
container_name: nas-nfs
restart: unless-stopped
privileged: true
environment:
- NFS_EXPORT_0=/mnt/union *(rw,fsid=0,no_subtree_check,async,insecure,no_root_squash)
- NFS_SERVER_THREAD_COUNT=8
- NFS_ENABLE_KERBEROS=false
ports:
- "2049:2049"
- "111:111"
- "32765:32765"
- "32767:32767"
volumes:
- /mnt/union:/mnt/union
- ./nfs-config:/etc/exports.d
sysctls:
- net.core.rmem_max=67108864
- net.core.wmem_max=67108864
networks:
- nas-network
# 管理界面(可选)
filebrowser:
image: filebrowser/filebrowser:latest
container_name: nas-filebrowser
restart: unless-stopped
environment:
- FB_BASEURL=/files
- FB_PORT=8081
ports:
- "8081:8081"
volumes:
- /mnt/union:/srv
- ./filebrowser-config:/database
- ./filebrowser-settings.json:/config/settings.json
user: "${UID:-1000}:${GID:-1000}"
networks:
- nas-network
networks:
nas-network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/24创建 .env 文件:
# NAS 环境配置
TZ=Asia/Shanghai
UID=1000
GID=1000
# 服务密码(首次启动后修改)
WEBDAV_PASSWORD=YourSecurePassword123
SMB_PASSWORD=YourSecurePassword123
# 网络配置
NAS_DOMAIN=nas.local
NAS_IP=192.168.1.100
# 存储路径
UNION_MOUNT=/mnt/union创建 optimize-mergerfs.sh:
#!/bin/bash
# MergerFS 性能优化脚本
echo "应用性能优化设置..."
# 1. 调整内核参数
sudo tee /etc/sysctl.d/99-mergerfs-optimize.conf > /dev/null << EOF
# 提高 FUSE 性能
fs.inotify.max_user_watches=524288
fs.inotify.max_user_instances=1024
# 网络优化(用于网络共享)
net.core.rmem_max=134217728
net.core.wmem_max=134217728
net.ipv4.tcp_rmem=4096 87380 134217728
net.ipv4.tcp_wmem=4096 65536 134217728
net.core.netdev_max_backlog=30000
# 文件系统缓存
vm.vfs_cache_pressure=50
vm.dirty_background_ratio=5
vm.dirty_ratio=10
EOF
# 2. 应用设置
sudo sysctl -p /etc/sysctl.d/99-mergerfs-optimize.conf
# 3. 创建定期清理任务
sudo tee /etc/cron.weekly/clean-mergerfs-cache > /dev/null << 'EOF'
#!/bin/bash
# 清理 mergerfs 缓存
sync
echo 3 > /proc/sys/vm/drop_caches
if [ -d "/mnt/union" ]; then
find /mnt/union -name "*.tmp" -type f -mtime +7 -delete
fi
EOF
sudo chmod +x /etc/cron.weekly/clean-mergerfs-cache