服务器折腾小记

xeonds

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‘

UnionFS折腾

在构建个人 NAS 系统时,我们经常面临一个常见问题:如何将多块硬盘合并成一个统一的存储池,同时保持数据的安全性和访问效率?传统的 RAID 方案虽然稳定,但缺乏灵活性。今天,我将介绍一种基于 UnionFS 的解决方案——MergerFS,它能够智能地合并多个文件系统,并提供 Docker 容器化的网络共享服务。

什么是 UnionFS 和 MergerFS?

UnionFS 基础

UnionFS 是一种联合文件系统,它能够将多个目录(分支)透明地叠加成一个统一的视图。这种技术允许你在保持底层文件系统独立的同时,创建一个逻辑上的合并存储空间。

MergerFS 的优势

MergerFS 是基于 FUSE 实现的 UnionFS 变体,具有以下特点: - 无数据迁移:直接使用现有文件系统,无需格式化或移动数据 - 灵活扩展:随时添加或移除硬盘 - 策略驱动:可根据多种策略(如剩余空间、文件类型)决定文件存储位置 - 容错性:单块硬盘故障不影响其他硬盘的数据访问

问题分析:为什么 fstab 挂载会失败?

很多用户在配置 MergerFS 时遇到启动失败的问题,根本原因在于系统启动时的挂载顺序。当系统通过 fstab 挂载时,它会并行处理所有挂载点,而 MergerFS 要求所有底层存储必须就绪后才能创建合并视图。

传统 fstab 方案的局限性

# 典型的 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* 尚未就绪,导致挂载失败。

解决方案:使用 Systemd 服务精确控制挂载顺序

1. 创建智能化的 Systemd 服务

以下脚本自动生成可靠的服务配置:

#!/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"

2. MergerFS 配置选项详解

# 完整的 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 容器化:WebDAV + SMB + NFS 三合一共享

现在我们已经有了稳定的合并存储,接下来通过 Docker 容器提供网络共享服务。

Docker Compose 配置

创建 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