asdff
This commit is contained in:
joy 2025-11-08 14:09:53 +08:00
parent 6012c7962d
commit 526d9983a2
1 changed files with 0 additions and 533 deletions

533
nfs.sh
View File

@ -1,533 +0,0 @@
#!/bin/bash
set -euo pipefail # 严格模式:报错即退出、禁止未定义变量、管道错误传递
##############################################################################
# 常量定义(默认值,可通过参数覆盖)
##############################################################################
DEFAULT_SHARE_DIRS="/opt/data" # 默认共享目录
EXPORTS_FILE="/etc/exports" # NFS配置文件路径
BACKUP_SUFFIX=$(date +%Y%m%d%H%M%S) # 备份文件后缀(时间戳,避免覆盖)
# NFS共享权限模板{DIR}会自动替换为实际共享目录)
# 权限说明rw(读写)、sync(同步写入)、no_root_squash(保留root权限)、no_all_squash(保留用户权限)、insecure(允许非特权端口访问)
NFS_CONFIG_TEMPLATE="{DIR} *(rw,sync,no_root_squash,no_all_squash,insecure)"
TEST_MOUNT_DIR_PREFIX="/mnt/nfs_test_$$" # 临时测试挂载点前缀($$为进程ID确保唯一性
##############################################################################
# 全局变量(通过命令行参数初始化)
##############################################################################
ACTION="" # 操作类型install(安装) / uninstall(卸载)
SHARE_DIRS=() # 共享目录数组(支持多个目录)
OS_TYPE="" # 系统类型(提前检测,避免重复调用)
##############################################################################
# 工具函数(中文注释)
##############################################################################
# 日志输出(带时间戳,便于排查问题)
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
}
# 错误退出(打印错误信息后终止脚本)
error_exit() {
log "ERROR: $1"
exit 1
}
# 检查是否为root用户NFS安装/卸载需要root权限
check_root() {
if [ $EUID -ne 0 ]; then
error_exit "请使用root用户运行脚本执行 sudo -i 或 su - 切换)"
fi
}
# 检测系统发行版返回centos/ubuntu/debian适配不同系统的包管理
detect_os() {
if [ -f /etc/os-release ]; then
. /etc/os-release
case $ID in
centos|rhel) echo "centos" ;;
ubuntu) echo "ubuntu" ;;
debian) echo "debian" ;;
*) error_exit "不支持的系统发行版:$ID仅支持CentOS/RHEL 7+、Ubuntu 18.04+、Debian 9+" ;;
esac
else
error_exit "无法检测系统发行版(缺少/etc/os-release文件"
fi
}
# 目录路径转义(将 / 替换为 \/避免sed命令语法冲突
escape_dir() {
local dir="$1"
echo "${dir//\//\\/}" # 替换所有 / 为 \/
}
# 检查服务是否正在运行
is_service_running() {
local service_name=$1
systemctl is-active --quiet "$service_name" 2>/dev/null
}
# 修复Ubuntu/Debian下NFS服务启动异常核心修复函数
fix_ubuntu_nfs_start() {
log "开始修复NFS服务启动环境Ubuntu/Debian"
# 1. 停止残留服务进程,避免状态冲突
log "清理残留NFS相关进程"
pkill -f nfsd || true
pkill -f rpc.mountd || true
# 2. 确保依赖服务rpcbind启动Ubuntu 18.04+ 部分版本rpcbind默认未启动
log "启动依赖服务rpcbind"
systemctl enable --now rpcbind || error_exit "rpcbind服务启动失败NFS核心依赖"
# 3. 校验/etc/exports配置语法避免配置错误导致服务启动失败
log "校验NFS配置文件语法$EXPORTS_FILE"
if ! exportfs -r; then # 重载配置并检查语法
error_exit "NFS配置文件语法错误请检查 $EXPORTS_FILE 内容(比如目录路径、权限参数是否正确)"
fi
log "NFS配置语法校验通过"
# 4. 重启nfs-kernel-server服务分两步停止→启动避免状态残留
log "重启nfs-kernel-server服务"
systemctl stop nfs-kernel-server || true # 确保服务已停止
sleep 2 # 等待进程清理
if systemctl start nfs-kernel-server; then
log "nfs-kernel-server服务启动成功"
systemctl enable nfs-kernel-server || log "警告设置nfs-kernel-server开机自启失败不影响当前使用"
else
# 启动失败时输出详细日志,便于排查
log "nfs-kernel-server服务启动失败查看详细错误日志"
journalctl -xeu nfs-kernel-server | tail -20
error_exit "nfs-kernel-server服务启动失败见上方错误日志"
fi
}
# 解析命令行参数(处理--install/--uninstall/--share-dirs参数
parse_args() {
if [ $# -eq 0 ]; then
show_help # 无参数时显示帮助信息
exit 0
fi
# 遍历所有传入参数
for arg in "$@"; do
case $arg in
--install)
ACTION="install"
;;
--uninstall)
ACTION="uninstall"
;;
--share-dirs=*)
# 提取--share-dirs后的目录字符串逗号分隔
local dir_str=${arg#--share-dirs=}
# 按逗号分割为数组
IFS=',' read -r -a dir_array <<< "$dir_str"
# 处理目录数组:去重、过滤空值、校验绝对路径
for dir in "${dir_array[@]}"; do
dir=$(echo "$dir" | xargs) # 去除目录名前后的空格
if [ -z "$dir" ]; then
log "警告:跳过空的共享目录(可能是逗号前后多写了空格)"
continue
fi
# 校验是否为绝对路径(必须以/开头)
if [[ ! "$dir" =~ ^/ ]]; then
error_exit "共享目录必须是绝对路径(当前输入:$dir),例如 /opt/data"
fi
# 去重:如果目录已在数组中,不再重复添加
if ! [[ " ${SHARE_DIRS[@]} " =~ " $dir " ]]; then
SHARE_DIRS+=("$dir")
fi
done
;;
-h|--help)
show_help
exit 0
;;
*)
error_exit "无效参数:$arg,请使用 --help 查看正确用法"
;;
esac
done
# 校验必填参数:必须指定--install或--uninstall
if [ -z "$ACTION" ]; then
error_exit "必须指定操作类型:--install安装 或 --uninstall卸载"
fi
# 若未指定--share-dirs使用默认共享目录
if [ ${#SHARE_DIRS[@]} -eq 0 ]; then
SHARE_DIRS=($DEFAULT_SHARE_DIRS)
log "未指定共享目录,使用默认值:${SHARE_DIRS[*]}"
else
log "已指定共享目录列表:${SHARE_DIRS[*]}"
fi
}
# 显示帮助信息(中文说明,方便用户使用)
show_help() {
echo "======================================= NFS一键安装卸载脚本 ======================================="
echo "用法:$0 [选项]"
echo "核心选项:"
echo " --install 安装NFS服务端+客户端并配置共享目录全程使用root权限"
echo " --uninstall 卸载NFS服务端+客户端,清理相关配置(保留数据)"
echo " --share-dirs=DIR1,DIR2 指定共享目录(多个目录用逗号分隔,必须为绝对路径)"
echo " --help/-h 显示当前帮助信息"
echo ""
echo "使用示例:"
echo " 1. 安装NFS使用默认共享目录 /opt/data"
echo " $0 --install"
echo " 2. 安装NFS指定多个共享目录"
echo " $0 --install --share-dirs=/opt/data1,/opt/data2,/mnt/nfs_share"
echo " 3. 卸载NFS清理默认共享目录的配置"
echo " $0 --uninstall"
echo " 4. 卸载NFS清理指定共享目录的配置"
echo " $0 --uninstall --share-dirs=/opt/data1,/mnt/nfs_share"
echo "=================================================================================================="
}
# 打印NFS常用维护命令用户要求新增
print_maintain_commands() {
log "======================================= NFS常用维护命令 ======================================="
log "📊 查看NFS服务状态"
if [ "$OS_TYPE" = "centos" ]; then
log " systemctl status nfs-server"
else
log " systemctl status nfs-kernel-server"
fi
log ""
log "🔄 重启NFS服务"
if [ "$OS_TYPE" = "centos" ]; then
log " systemctl restart nfs-server"
else
log " systemctl restart nfs-kernel-server"
fi
log ""
log "📁 查看已配置的NFS共享目录"
log " exportfs -v"
log ""
log "⚙️ 重载NFS配置修改/etc/exports后执行"
log " exportfs -r"
log ""
log "🖥️ 客户端挂载NFS共享示例"
log " mount -t nfs 服务器IP:/共享目录 本地目标目录mount -t nfs 192.168.1.100:/opt/data /mnt/client_data"
log ""
log "🗑️ 客户端卸载NFS共享"
log " umount 本地目标目录umount /mnt/client_data"
log ""
log "🔥 查看NFS服务日志排查问题"
if [ "$OS_TYPE" = "centos" ]; then
log " journalctl -u nfs-server -f"
else
log " journalctl -u nfs-kernel-server -f"
fi
log "=================================================================================================="
}
##############################################################################
# 安装NFS服务支持多共享目录中文步骤说明
##############################################################################
install_nfs() {
log "开始安装NFS服务端+客户端(系统:$OS_TYPE,共享目录:${SHARE_DIRS[*]}全程使用root权限"
##########################################################################
# 步骤1安装NFS依赖包根据系统类型选择yum或apt
##########################################################################
log "步骤1/6安装NFS相关依赖包"
case $OS_TYPE in
centos)
# CentOS/RHELnfs-utils服务端+客户端、rpcbind端口映射
yum install -y nfs-utils rpcbind || error_exit "YUM安装依赖失败请检查yum源是否正常"
;;
ubuntu|debian)
# Ubuntu/Debiannfs-kernel-server服务端、nfs-common客户端、rpcbind依赖
apt update -y >/dev/null 2>&1 || error_exit "APT更新源失败请检查网络或apt源配置"
apt install -y nfs-kernel-server nfs-common rpcbind || error_exit "APT安装依赖失败"
;;
esac
log "依赖包安装完成"
##########################################################################
# 步骤2创建共享目录并设置全权限777+root属主满足用户要求
##########################################################################
log "步骤2/6创建共享目录并配置全权限${#SHARE_DIRS[@]}个目录root属主"
for dir in "${SHARE_DIRS[@]}"; do
if [ -d "$dir" ]; then
log "共享目录 $dir 已存在,跳过创建"
else
# -p递归创建父目录如/opt/data不存在时自动创建/opt和/opt/data
mkdir -p "$dir" || error_exit "创建共享目录 $dir 失败(权限不足或路径非法)"
log "成功创建共享目录:$dir"
fi
# 设置全权限777保留root属主创建目录时默认就是root无需额外chown
chmod 777 "$dir" || error_exit "设置 $dir 权限为777失败"
log "目录 $dir权限配置完成全权限777属主root:root"
done
##########################################################################
# 步骤3配置/etc/exportsNFS核心配置文件先备份再修改
##########################################################################
log "步骤3/6配置NFS共享自动备份原有配置"
# 备份原有配置文件(添加时间戳后缀,便于回滚)
if [ -f "$EXPORTS_FILE" ]; then
cp "$EXPORTS_FILE" "${EXPORTS_FILE}.bak.${BACKUP_SUFFIX}" || error_exit "备份 $EXPORTS_FILE 失败"
log "已备份原有配置文件:${EXPORTS_FILE}.bak.${BACKUP_SUFFIX}"
fi
# 批量添加/更新共享目录配置(核心修复:使用转义后的目录路径)
for dir in "${SHARE_DIRS[@]}"; do
local escaped_dir=$(escape_dir "$dir") # 转义目录中的 /
# 替换配置模板中的{DIR}为实际目录
local nfs_config=${NFS_CONFIG_TEMPLATE//\{DIR\}/$dir}
# 若该目录已存在配置,先删除旧配置(避免重复)
if grep -q "^${escaped_dir}" "$EXPORTS_FILE" 2>/dev/null; then
log "目录 $dir 的NFS配置已存在更新为最新配置"
# sed命令使用转义后的目录避免语法冲突
sed -i "/^${escaped_dir}/d" "$EXPORTS_FILE" || error_exit "删除 $dir 的旧配置失败"
fi
# 写入新配置到/etc/exports
echo "$nfs_config" >> "$EXPORTS_FILE" || error_exit "写入 $dir 的NFS配置失败"
log "目录 $dir:配置已添加到 $EXPORTS_FILE"
done
##########################################################################
# 步骤4启动NFS服务并设置开机自启优化启动逻辑解决启动失败问题
##########################################################################
log "步骤4/6启动NFS服务并配置开机自启"
case $OS_TYPE in
centos)
# CentOS先启动rpcbind再启动nfs-server
systemctl enable --now rpcbind || error_exit "启动rpcbind服务失败"
systemctl stop nfs-server || true
sleep 2
if systemctl start nfs-server; then
systemctl enable nfs-server || log "警告设置nfs-server开机自启失败"
log "nfs-server服务启动成功"
else
log "nfs-server启动失败详细日志"
journalctl -xeu nfs-server | tail -20
error_exit "nfs-server服务启动失败"
fi
;;
ubuntu|debian)
# Ubuntu/Debian使用修复函数启动服务处理依赖、配置校验、残留清理
fix_ubuntu_nfs_start
;;
esac
# 验证服务是否启动成功
local service_name=$([ "$OS_TYPE" = "centos" ] && echo "nfs-server" || echo "nfs-kernel-server")
if ! is_service_running "$service_name"; then
error_exit "$service_name服务启动失败请检查系统日志journalctl -u $service_name"
fi
log "$service_name服务启动成功(已配置开机自启)"
##########################################################################
# 步骤5开放防火墙端口企业环境必备确保客户端能访问NFS服务
##########################################################################
log "步骤5/6开放防火墙NFS相关端口"
case $OS_TYPE in
centos)
# CentOS使用firewalld
if is_service_running "firewalld"; then
firewall-cmd --permanent --add-service=nfs || error_exit "开放NFS端口2049失败"
firewall-cmd --permanent --add-service=rpc-bind || error_exit "开放rpc-bind端口111失败"
firewall-cmd --permanent --add-service=mountd || error_exit "开放mountd端口失败"
firewall-cmd --reload || error_exit "防火墙重载配置失败"
log "Firewalld已开放NFS相关端口2049、111等"
else
log "Firewalld未运行跳过端口开放若后续客户端无法连接请手动开放端口"
fi
;;
ubuntu|debian)
# Ubuntu/Debian使用ufw
if is_service_running "ufw"; then
ufw allow nfs || error_exit "开放NFS端口失败"
ufw allow 111/tcp || error_exit "开放rpcbind端口111失败"
ufw reload || error_exit "UFW重载配置失败"
log "UFW已开放NFS端口2049和rpcbind端口111"
else
log "UFW未运行跳过端口开放若后续客户端无法连接请手动开放端口"
fi
;;
esac
##########################################################################
# 步骤6测试验证每个共享目录都执行挂载+读写测试,确保可用)
##########################################################################
log "步骤6/6测试所有共享目录的可用性"
for dir in "${SHARE_DIRS[@]}"; do
# 为每个目录创建唯一的临时挂载点(替换/为_避免路径冲突
local test_mount_dir="${TEST_MOUNT_DIR_PREFIX}_$(echo "$dir" | tr '/' '_')"
# 创建临时挂载点
mkdir -p "$test_mount_dir" || error_exit "创建测试挂载点 $test_mount_dir 失败"
# 本地挂载测试使用localhost模拟客户端
log "正在测试挂载localhost:$dir -> $test_mount_dir"
mount -t nfs localhost:"$dir" "$test_mount_dir" || error_exit "目录 $dir 挂载测试失败NFS配置可能有误"
# 读写测试:创建测试文件并验证内容
local test_file="${test_mount_dir}/nfs_test_${BACKUP_SUFFIX}.txt"
echo "NFS测试内容$(date) - 共享目录:$dirroot权限" > "$test_file" || error_exit "目录 $dir 写入测试失败"
if [ -f "$test_file" ] && grep -q "NFS测试内容" "$test_file"; then
log "目录 $dir:读写测试成功(测试文件路径:$test_file"
else
error_exit "目录 $dir:读写测试失败(文件创建或读取异常)"
fi
# 卸载临时挂载点并清理
umount "$test_mount_dir" || error_exit "卸载测试挂载点 $test_mount_dir 失败"
rm -rf "$test_mount_dir" || log "清理测试挂载点 $test_mount_dir 失败(可手动删除)"
done
##########################################################################
# 安装完成提示+常用维护命令
##########################################################################
log "========================================"
log "🎉 NFS服务安装完成"
log "📁 共享目录列表:${SHARE_DIRS[*]}"
log "🔑 共享权限:全权限(读写+同步写入+保留root权限"
log "👤 目录属主root:root全程使用root权限"
log "⚙️ 配置文件:$EXPORTS_FILE(备份文件:${EXPORTS_FILE}.bak.${BACKUP_SUFFIX}"
log "🖥️ 客户端挂载命令mount -t nfs 服务器IP:共享目录 本地目标目录"
log "========================================"
# 打印常用维护命令(用户要求)
print_maintain_commands
}
##############################################################################
# 卸载NFS服务支持多共享目录清理中文步骤说明
##############################################################################
uninstall_nfs() {
log "开始卸载NFS服务端+客户端(系统:$OS_TYPE,清理目录:${SHARE_DIRS[*]}"
##########################################################################
# 步骤1卸载所有NFS挂载点避免服务删除时因挂载占用失败
##########################################################################
log "步骤1/5卸载所有关联的NFS挂载点"
for dir in "${SHARE_DIRS[@]}"; do
local escaped_dir=$(escape_dir "$dir") # 转义目录中的 /
# 匹配所有挂载了该共享目录的挂载点(转义/避免正则匹配错误)
local mount_points=$(mount | grep -E "nfs.*${escaped_dir}" | awk '{print $3}')
if [ -n "$mount_points" ]; then
for mp in $mount_points; do
log "正在卸载挂载点(关联目录:$dir$mp"
# -l强制卸载即使占用-f强制杀死占用进程
umount -lf "$mp" || log "卸载 $mp 失败(可能已被卸载)"
done
fi
done
# 清理剩余的NFS挂载点避免遗漏
local remaining_mounts=$(mount | grep -E "nfs|nfs4" | awk '{print $3}')
if [ -n "$remaining_mounts" ]; then
log "清理剩余的NFS挂载点$remaining_mounts"
for mp in $remaining_mounts; do
umount -lf "$mp" || true
done
fi
log "挂载点清理完成"
##########################################################################
# 步骤2停止NFS相关服务并禁用开机自启
##########################################################################
log "步骤2/5停止NFS相关服务"
case $OS_TYPE in
centos)
systemctl stop nfs-server rpcbind || true
systemctl disable nfs-server rpcbind || true
;;
ubuntu|debian)
systemctl stop nfs-kernel-server rpcbind || true
systemctl disable nfs-kernel-server rpcbind || true
;;
esac
log "NFS相关服务已停止并禁用开机自启"
##########################################################################
# 步骤3清理/etc/exports配置核心修复使用转义后的目录路径
##########################################################################
log "步骤3/5清理指定共享目录的NFS配置"
if [ -f "$EXPORTS_FILE" ]; then
for dir in "${SHARE_DIRS[@]}"; do
local escaped_dir=$(escape_dir "$dir") # 转义目录中的 /
if grep -q "^${escaped_dir}" "$EXPORTS_FILE" 2>/dev/null; then
# sed命令使用转义后的目录避免语法冲突
sed -i "/^${escaped_dir}/d" "$EXPORTS_FILE" || error_exit "清理 $dir 的NFS配置失败"
log "已清理 $dir 的NFS配置"
else
log "$dir 的NFS配置不存在跳过清理"
fi
done
# 若配置文件为空,直接删除(避免残留空文件)
if [ ! -s "$EXPORTS_FILE" ]; then
rm -f "$EXPORTS_FILE" || log "删除空配置文件 $EXPORTS_FILE 失败"
log "已删除空的NFS配置文件"
fi
else
log "NFS配置文件 $EXPORTS_FILE 不存在,跳过清理"
fi
##########################################################################
# 步骤4卸载NFS相关依赖包彻底清理安装文件
##########################################################################
log "步骤4/5卸载NFS相关依赖包"
case $OS_TYPE in
centos)
yum remove -y nfs-utils rpcbind || error_exit "YUM卸载依赖包失败"
;;
ubuntu|debian)
apt purge -y nfs-kernel-server nfs-common rpcbind || error_exit "APT卸载依赖包失败"
# 自动清理无用依赖
apt autoremove -y >/dev/null 2>&1 || true
;;
esac
log "NFS相关依赖包已卸载完成"
##########################################################################
# 步骤5提示共享目录数据处理默认保留避免误删业务数据
##########################################################################
log "步骤5/5共享目录数据处理提示"
for dir in "${SHARE_DIRS[@]}"; do
if [ -d "$dir" ]; then
log "共享目录 $dir 仍存在已保留其中数据属主root:root如需删除请执行rm -rf '$dir'"
else
log "共享目录 $dir 不存在,跳过提示"
fi
done
##########################################################################
# 卸载完成提示+常用维护命令(用户要求)
##########################################################################
log "========================================"
log "🗑️ NFS服务卸载完成"
log "✅ 已清理内容NFS服务、指定共享目录配置、相关依赖包"
log "⚠️ 未清理内容:共享目录数据(需手动删除,避免误删重要文件)"
log "📋 已清理的共享目录列表:${SHARE_DIRS[*]}"
log "========================================"
# 打印常用维护命令(用户要求)
print_maintain_commands
}
##############################################################################
# 主逻辑(脚本入口)
##############################################################################
main() {
check_root # 先检查是否为root用户
parse_args "$@" # 解析命令行参数
OS_TYPE=$(detect_os) # 检测系统类型并保存(避免重复调用)
# 根据操作类型执行对应函数
case $ACTION in
install)
install_nfs
;;
uninstall)
uninstall_nfs
;;
*)
error_exit "无效操作类型:$ACTION(仅支持 install 或 uninstall"
;;
esac
}
# 启动主逻辑
main "$@"