飞牛NFS挂载磁盘完成不同系统PT下载
如题,为什么需要这样操作?
MoviePilot+Emby+qbittorrent组合完成全自动下载协同工作
在我的环境里面, MoviePilot和Emby需要科学网络环境,而多数PT站点会将梯子环境内的下载器识别为盒子,而盒子是无法享受某些福利的
所以我们既要qbittorrent正常保种/下载,又要保证MP和EmbyServer的正常使用.
可以在MP启动时增加代理参数,解决MP的科学需求. 但EmbyServer容器增加代理参数无法正常使用,或者说能实现但很麻烦.
所以如果你的是群晖或者飞牛, 把三个容器都部署在同一台机器上面,对网络的分流设置可能比较麻烦.那可以选择用双系统组合运行的方式来完成配置:
飞牛或者其他任意系统运行qbittorrent, 挂载NFS文件夹.主力存储设备或者主程序宿主设备挂梯子.
具体步骤:
飞牛OS:
#####创建脚本:
nano /usr/local/bin/mount_qb_nfs.sh
######################脚本内容###########
#!/bin/bash
# NFS自动挂载脚本 - 改进版
# 功能:支持多个挂载点、服务检查、内容验证、日志记录
# 日志文件
LOG_FILE="/var/log/mount-nfs-retry.log"
# 挂载配置项:NFS服务器 远程路径 本地挂载点 验证文件夹(可选)
declare -a NFS_ENTRIES=(
"10.2.0.252 /volume3/Media /vol02/Media"
"10.2.0.252 /volume4/QB_temp /vol02/qb_temp"
# "10.3.0.252 /volume1/Media /vol02/media Movies"
)
# 日志函数
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S'): $1" | tee -a "$LOG_FILE"
}
# 检查NFS服务是否可用
check_nfs_server() {
local server=$1
if showmount -e "$server" &>/dev/null; then
return 0
else
return 1
fi
}
# 验证挂载内容
verify_mount() {
local mount_point=$1
local check_folder=$2
# 如果没有指定验证文件夹,跳过验证
[ -z "$check_folder" ] && return 0
if [ -d "$mount_point/$check_folder" ]; then
log "验证成功!找到 $check_folder 文件夹"
return 0
else
log "警告!未找到 $check_folder 文件夹,挂载可能异常"
return 1
fi
}
# 尝试挂载单个NFS路径
mount_nfs_entry() {
local entry=$1
read -r server remote_path mount_point check_folder <<< "$entry"
# 如果验证文件夹为0,则视为未指定
[ "$check_folder" = "0" ] && check_folder=""
log "处理挂载项: $server:$remote_path -> $mount_point"
# 检查NFS服务可用性
if ! check_nfs_server "$server"; then
log "NFS服务 [$server] 未就绪,跳过"
return 1
fi
# 创建挂载点目录
mkdir -p "$mount_point"
# 如果已经挂载,检查是否正常
if mountpoint -q "$mount_point"; then
log "[$mount_point] 已挂载,验证挂载内容..."
if verify_mount "$mount_point" "$check_folder"; then
log "[$mount_point] 挂载正常,验证通过"
return 0
else
log "[$mount_point] 挂载异常,强制卸载..."
umount -f "$mount_point" 2>/dev/null
sleep 2
fi
fi
# 如果已有挂载记录但实际未挂载,先清理
mount | grep -q "$mount_point" && {
log "[$mount_point] 清理残留挂载记录..."
umount -f "$mount_point" 2>/dev/null
sleep 2
}
# 尝试挂载
log "尝试挂载 $server:$remote_path 到 $mount_point"
if mount -t nfs4 "${server}:${remote_path}" "$mount_point" &>> "$LOG_FILE"; then
sleep 2
if mountpoint -q "$mount_point"; then
log "挂载成功 [$mount_point]"
if verify_mount "$mount_point" "$check_folder"; then
log "[$mount_point] 验证通过,挂载正常"
return 0
else
log "[$mount_point] 挂载成功但验证失败,卸载重试..."
umount -f "$mount_point" 2>/dev/null
return 1
fi
else
log "挂载失败 [$mount_point] - mountpoint检查未通过"
return 1
fi
else
log "挂载失败 [$mount_point] - mount命令失败"
return 1
fi
}
# 主函数
main() {
log "========== NFS自动挂载开始 =========="
log "配置的挂载项数量: ${#NFS_ENTRIES[@]}"
local retry_interval=10
local max_retries=3
for entry in "${NFS_ENTRIES[@]}"; do
# 跳过空行和注释行
[[ "$entry" =~ ^[[:space:]]*$ ]] && continue
[[ "$entry" =~ ^[[:space:]]*# ]] && continue
local attempt=1
local success=false
while [ $attempt -le $max_retries ]; do
log "========== 尝试 $attempt/$max_retries =========="
if mount_nfs_entry "$entry"; then
success=true
break
fi
if [ $attempt -lt $max_retries ]; then
log "等待 ${retry_interval} 秒后重试..."
sleep $retry_interval
fi
((attempt++))
done
if [ "$success" = true ]; then
log "挂载项处理成功 ✓"
else
log "挂载项处理失败 ✗ - 已达到最大重试次数"
fi
sleep 1
done
log "========== NFS自动挂载结束 =========="
}
# 运行主函数
main
exit 0
##########授权执行:
chmod +x /usr/local/bin/mount_qb_nfs.sh
创建服务:
nano /etc/systemd/system/mount-qb-nfs.service
##########
[Unit]
Description=Mount NFS from 10.0.0.252:/volume1/QBdownload
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/mount_qb_nfs.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
########持久化/开机自动运行
systemctl daemon-reload
systemctl enable mount-qb-nfs.service
systemctl start mount-qb-nfs.service检查运行状态:
systemctl status mount-qb-nfs.service创建docker自启脚本:
nano /usr/local/bin/wait-nfs-and-start-qbit.sh
########自启docker容器脚本:
#!/bin/bash
# NFS挂载验证并启动 qBittorrent 容器脚本
# 功能:等待NFS挂载成功且验证文件夹存在,容器内也能访问后启动容器
# 配置参数
INITIAL_WAIT=10 # 初始等待时间(秒)
RETRY_INTERVAL=10 # 重试间隔(秒)
MAX_RETRIES=60 # 最大重试次数(0表示无限重试)
MOUNT_POINT="/vol02/Media" # NFS挂载点
REQUIRED_DIR="$MOUNT_POINT/Movies" # 需要验证的文件夹
QBIT_CONTAINER_NAME="qbittorrent" # qBittorrent 容器名称
WORKDIR="/vol1/1000/docker/docker_compose/qBittorrent" # docker compose 工作目录
# 日志文件
LOG_FILE="/var/log/nfs-qbit-startup.log"
# 日志函数
log() {
local message="$(date '+%Y-%m-%d %H:%M:%S'): $1"
echo "$message"
echo "$message" >> "$LOG_FILE"
}
log "========== 开始 NFS 挂载验证和容器启动流程 =========="
# 等待 NFS 挂载服务完成
log "等待 ${INITIAL_WAIT} 秒,让 NFS 挂载服务开始工作..."
sleep "$INITIAL_WAIT"
# 检查挂载点目录是否存在
if [ ! -d "$MOUNT_POINT" ]; then
log "警告:挂载点目录 $MOUNT_POINT 不存在,创建中..."
mkdir -p "$MOUNT_POINT" || {
log "错误:无法创建挂载点目录"
exit 1
}
fi
log "开始检测 NFS 挂载点: $MOUNT_POINT"
log "需要验证的文件夹: $REQUIRED_DIR"
# 重试计数器
attempt=0
# 主循环:等待挂载和验证
while [ $MAX_RETRIES -eq 0 ] || [ $attempt -lt $MAX_RETRIES ]; do
((attempt++))
# 1. 检查宿主机挂载点
if mountpoint -q "$MOUNT_POINT" 2>/dev/null; then
log "[宿主] 挂载点已挂载 (尝试 $attempt)"
# 2. 检查 Movies 文件夹是否存在
if [ -d "$REQUIRED_DIR" ]; then
log "[宿主] $REQUIRED_DIR 文件夹存在"
# 3. 检查容器的运行状态
if [ "$(docker ps -q -f name=^/${QBIT_CONTAINER_NAME}$ 2>/dev/null)" ]; then
log "容器 $QBIT_CONTAINER_NAME 已在运行"
# 4. 用临时容器检测容器内能否看到 Movies 文件夹
log "使用临时容器验证容器内 NFS 可见性..."
if docker run --rm \
-v "$MOUNT_POINT:/media" \
--entrypoint /bin/sh \
busybox:latest -c "[ -d /media/Movies ] && exit 0 || exit 1" 2>> "$LOG_FILE"; then
log "验证成功!容器内可以访问 NFS 内容"
log "========== NFS 验证完成,容器已就绪 =========="
exit 0
else
log "警告:容器内无法访问到 NFS 内容,${RETRY_INTERVAL}秒后重试..."
sleep "$RETRY_INTERVAL"
continue
fi
else
log "容器未运行,准备启动..."
# 尝试启动容器
if [ -d "$WORKDIR" ] && [ -f "$WORKDIR/docker-compose.yml" ]; then
log "使用 docker-compose 启动: $WORKDIR"
cd "$WORKDIR" && \
docker compose up -d &>> "$LOG_FILE" && \
log "Docker Compose 启动命令已执行" || log "Docker Compose 启动失败"
# 等待容器启动
sleep 5
else
log "警告:未找到 docker-compose.yml,尝试启动已有容器"
if docker start "$QBIT_CONTAINER_NAME" &>> "$LOG_FILE"; then
log "容器 $QBIT_CONTAINER_NAME 启动成功"
sleep 5
else
log "容器 $QBIT_CONTAINER_NAME 启动失败"
sleep "$RETRY_INTERVAL"
continue
fi
fi
# 验证容器是否真的启动了
if ! [ "$(docker ps -q -f name=^/${QBIT_CONTAINER_NAME}$ 2>/dev/null)" ]; then
log "容器启动失败,${RETRY_INTERVAL}秒后重试..."
sleep "$RETRY_INTERVAL"
fi
fi
else
log "[宿主] $REQUIRED_DIR 文件夹不存在 (尝试 $attempt),${RETRY_INTERVAL}秒后重试..."
sleep "$RETRY_INTERVAL"
fi
else
log "[宿主] 挂载点未挂载 (尝试 $attempt),${RETRY_INTERVAL}秒后重试..."
sleep "$RETRY_INTERVAL"
fi
done
log "错误:达到最大重试次数 ($MAX_RETRIES),退出"
exit 1
##########授权执行:
chmod +x /usr/local/bin/wait-nfs-and-start-qbit.sh创建服务:
nano /etc/systemd/system/start-qbit-after-nfs.service
#######
[Unit]
Description=Wait for NFS Mount and Start qBittorrent Container
After=mount-qb-nfs.service network.target docker.service
Requires=mount-qb-nfs.service
Wants=docker.service
PartOf=docker.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/wait-nfs-and-start-qbit.sh
RemainAfterExit=yes
StandardOutput=journal
StandardError=journal
SyslogIdentifier=qbit-nfs-starter
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
TimeoutStartSec=600
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable start-qbit-after-nfs.service
systemctl start start-qbit-after-nfs.service检查运行状态:
systemctl status start-qbit-after-nfs.service