简介:一套面向 Samba 4(AD-DC)运维与部署场景的 Shell 脚本合集,内容源自 Debian Jessie 与 Stretch 服务器上的日常实践,适合具备 Linux 基础、需要搭建或维护 Samba 域控及成员服务器的系统管理员参考使用。内容围绕备份、权限核查、sysvol ACL 设置、域信息查询与排错采集等任务展开;读者可获得可直接改造的备份与检查脚本、SePrivileges 与 sysvol ACL 核查思路,以及多份覆盖最小化 AD 搭建、成员文件服务器配置、Ubuntu 18.04 AD-DC 完整流程的 howto 文本,便于对照复现实验环境、定位配置问题。压缩包共 25 个文件、约 71KB,以 12 个 .sh 脚本为主体,配合 9 个 .txt 操作记录与检查清单、3 个 .md 说明文档,另含一份 backup_samba4 备份脚本;目录按主题分层,便于取用。已有 250 人学习。
1. 一台 Samba 4 域控的日常:照单执行一遍巡检和备份,比临时翻手册更可靠
接手一台跑 Samba 4 的域控,最怕的不是宕机,而是半死不活:samba-tool还能跑,smbd偶尔抽风,sysvol 里的组策略不知道哪天被谁改过,真出事想回滚,才发现上一次可用备份是三周前。这套 Shell 脚本集合解决的就是这种日常:一台 Debian 机器,ssh 上去,执行一条命令,把域控健康信息抓成一份纯文本报告;再挂一条 cron,把 sysvol 和 AD 数据按天备份下来,带校验、带保留策略。作者在 Debian Jessie 和 Debian Stretch 上实测过,脚本里samba-info负责巡检,backup-script负责备份,另有若干 howtos 说明每个动作背后的原因。适合正在维护 Samba 4 AD DC、又不想上重型监控系统的中小规模环境;也适合准备把手工操作写成自动化,却不确定该检查哪些点的人。
2. 脚本集合的架构:五个脚本各管一件事,配置收敛到一个文件
拿到一堆.sh之后,先别急着跑,可以把每个文件打开看它在干什么。这套脚本组织不复杂,属于很典型的做法:按动作切成几个独立入口,公共函数抽到lib,可变参数用环境变量或配置文件统一传入。好处是每段逻辑都能单独执行、单独验证,出问题时不用整条流水线一起排查。
2.1 目录结构与脚本职责划分
按常见组织方式,目录大致如下:
samba4-scripts/ ├── samba-info.sh # 巡检:服务、配置、域、复制、sysvol ACL ├── backup-script.sh # 备份:sysvol + AD 数据 + 配置清单 ├── restore-check.sh # 恢复演练:把备份还原到隔离实例 ├── sysvol-sync-check.sh # 多台 DC 场景下比对 sysvol 内容 ├── lib/ │ └── common.sh # 日志、权限校验、版本探测、钩子 └── etc/ └── samba-scripts.conf # 路径、保留天数、备份根目录职责划分清楚之后,定时任务的安排就好定了。巡检类脚本只读不写,跑得也快,可以每 15 分钟一次,输出直接落到/var/log/samba-info/;备份类脚本要扫全量 sysvol,遇到大 GPO 目录会跑几分钟,放凌晨执行;恢复演练脚本对生产环境零依赖,可以每周手动跑一次。
| 脚本 | 是否只读 | 典型耗时 | 建议调度 |
|---|---|---|---|
samba-info.sh | 只读 | 3~10 秒 | cron 每 15 分钟 |
backup-script.sh | 写备份目录 | 1~10 分钟 | cron 每日凌晨 |
sysvol-sync-check.sh | 只读 | 随 sysvol 体积增长 | cron 每小时 |
restore-check.sh | 写临时目录 | 分钟级 | 手动或每周 |
表里“只读”这一列值得留意:凡是会改状态的命令,比如samba-tool ntacl sysvolreset,都不该出现在巡检脚本里。它会把整个 sysvol 的 ACL 按当前配置重刷一遍,跑错一次就得靠备份恢复。巡检脚本只做检查、只做输出,判断留给人。
2.2 Debian Jessie 与 Stretch 的版本差异怎么兜住
两个发行版带的 Samba 大版本不同,这是这套脚本最需要处理的事。Jessie 上是 Samba 4.2 系列,Stretch 上是 4.5 系列,中间差着好几个小版本,子命令的有无、输出格式的细节都可能不一样。最典型的是samba-tool domain backup(online / offline 两个子命令),4.5 之前的版本里可能根本没有,直接调用会报invalid choice。
与其在脚本里写一堆if判断版本号,我一般会把差异收敛到lib/common.sh里的两个函数:
# lib/common.sh 片段:把版本差异关在一个地方,业务脚本只管调用 samba_version() { # samba-tool --version 输出形如 "Version 4.5.16-Debian",取最后一段再截主次版本 samba-tool --version 2>/dev/null | awk '{print $NF}' | cut -d. -f1,2 } have_subcmd() { # $1 传子命令路径,例如 "domain backup";支持则返回 0 samba-tool $1 --help >/dev/null 2>&1 }samba_version()抓的是samba-tool --version输出的最后一段,再按点号截前两段,得到4.5这种形式,够用来做粗粒度判断。have_subcmd()更省事:直接用--help试一下,命令存在则退出码为 0,不存在则非 0,比硬编码版本号更可靠,因为发行版打包时可能打过补丁。业务脚本里就变成if have_subcmd "domain backup"; then ... else ... fi,分支只写一次。
提示:
samba-tool的参数解析在出错时也返回非 0,所以have_subcmd只能用来判断“这个子命令认不认”,不能用来判断“参数对不对”。真要校验参数,得把2>&1的内容一起看。
2.3 统一的配置约定:环境变量、退出码、日志
脚本之间要能组合,就得有统一约定。这套脚本的做法是:所有可变路径走环境变量,带默认值;日志统一带时间戳;致命错误统一走一个die。
# lib/common.sh 片段:日志与退出约定 LOG_TAG="${LOG_TAG:-samba-scripts}" log() { printf '[%s] %s %s\n' "$(date '+%F %T')" "$LOG_TAG" "$*"; } die() { log "ERROR: $*"; exit 1; } require_root() { [ "$(id -u)" -eq 0 ] || die "需要 root 权限,当前 uid=$(id -u)" } load_conf() { # 配置文件存在就 source,不存在就用脚本里的默认值继续跑 local f="${SAMBA_SCRIPTS_CONF:-/etc/samba-scripts.conf}" [ -r "$f" ] && . "$f" : "${BACKUP_ROOT:=/srv/backup/samba}" : "${KEEP_DAYS:=14}" : "${REPORT_DIR:=/var/log/samba-info}" }log()里的时间戳用%F %T,好处是日志按字典序排就是时间序,grep和sort都不用额外处理。load_conf()里那几个: "${VAR:=默认值}"是 Shell 的参数展开写法:变量为空或未定义时才赋值,已经设过的保持不动。这样命令行BACKUP_ROOT=/data/bak ./backup-script.sh的优先级高于配置文件,配置文件又高于脚本默认值,调试时非常顺手。
退出码也做了分级,0表示全绿,1表示参数或环境错误(比如不是 root),2表示检查发现问题但不致命(比如某个服务没起)。这样 cron 里可以写samba-info.sh || mail -s "DC 异常" ops@example—— 注意这里的邮箱地址换成你自己的,别照抄。脚本本身不负责告警,只负责把状态如实反映到退出码上。
3. 核心脚本拆解:samba-info 如何一次性收集域控健康信息
巡检脚本的价值不在于跑得多快,而在于“看一眼就知道有没有问题”。所以它的输出结构比实现技巧更重要:分节、有标题、每节内容短、异常项一眼可见。下面按执行顺序拆。
3.1 先固定输出框架:section 分节加 tee 双写
整份报告要同时进文件和终端,方便手工跑的时候边跑边看。用exec把标准输出整体重定向到tee,后面所有echo、命令输出都会自动双写,不用在每行后面挂管道。
#!/bin/bash # samba-info.sh —— Samba 4 域控健康巡检 set -uo pipefail # 注意:故意不加 -e,见下文说明 REPORT_DIR="${REPORT_DIR:-/var/log/samba-info}" STAMP="$(date +%Y%m%d-%H%M%S)" OUT="$REPORT_DIR/samba-info-$STAMP.txt" TMP="$(mktemp -d)" trap 'rm -rf "$TMP"' EXIT mkdir -p "$REPORT_DIR" exec > >(tee -a "$OUT") 2>&1 section() { printf '\n===== %s =====\n' "$1"; } section "host" hostname -f uptime cat /etc/debian_version 2>/dev/null || echo "debian_version 不可读"set -uo pipefail里没有-e,这是有意的。巡检脚本的使命是把所有检查项都跑完,而不是遇到第一个非零退出码就停。比如systemctl is-active在服务停止时返回 3,samba-tool drs showrepl在单机部署时也可能返回非零,加了-e整份报告会在第三节断掉,剩下的检查全没了,这在排障时是最难受的。
exec > >(tee -a "$OUT")这句用了进程替换:>(...)把一个命令包装成文件描述符,写进去的内容会流到tee。2>&1让错误输出也走同一条路。trap 'rm -rf "$TMP"' EXIT保证临时目录一定会被清掉,哪怕脚本中途exit。
3.2 服务与配置层:systemctl、testparm 抓关键项
服务状态这一节要处理一个兼容问题:不同版本、不同安装方式下,AD DC 的 unit 名可能是samba-ad-dc.service,也可能是samba.service。别硬编码,遍历一遍并判断 unit 是否存在。
section "services" for svc in samba-ad-dc samba smbd nmbd winbind; do if systemctl list-unit-files "${svc}.service" >/dev/null 2>&1; then state="$(systemctl is-active "${svc}.service" 2>/dev/null || true)" printf '%-14s %s\n' "$svc" "$state" fi donesystemctl is-active在服务未激活时返回非零,所以后面跟了|| true,避免pipefail之外的因素影响循环。list-unit-files用来判断 unit 存不存在,比systemctl status干净,不会因为服务不存在而吐一堆红字。
配置层用testparm -s把smb.conf连同 include 一起展开,然后只抓 AD DC 场景下最关键的几项。整份配置贴出来没有意义,几百行里真正影响域控行为的就那么几个。
section "smb.conf" testparm -s 2>/dev/null | grep -Ei \ '^\s*(server role|server services|dns forwarder|realm|workgroup|netbios name|interfaces)\s*=' \ || echo "未匹配到关键参数,检查 smb.conf 是否可读"-s表示只输出非默认值,-E让 grep 支持扩展正则,-i忽略大小写。如果这一节是空的,通常意味着testparm读不到配置——权限问题,或者SMB_CONF指向了错误路径,先查这个。
3.3 目录层:samba-tool 抓域、复制、DNS、sysvol ACL
这一节是巡检的核心。四类信息:域功能级别、复制状态、DNS 记录、sysvol 上的 ACL 是否与 AD 中记录的一致。每一条都用if包起来,失败就记一行,不影响后面。
section "domain-level" samba-tool domain level show 2>&1 || log "domain level 读取失败" section "replication" if samba-tool drs showrepl > "$TMP/repl.txt" 2>&1; then grep -E '^(DSA|Last success|Last failure|NUMBER_OF_FAILURES)' "$TMP/repl.txt" | head -40 else log "单机部署或复制未配置,drs showrepl 返回非零,已跳过" fi section "sysvol-acl" if samba-tool ntacl sysvolcheck > "$TMP/ntacl.txt" 2>&1; then echo "sysvol ACL 校验通过" else echo "sysvol ACL 与 AD 记录不一致:" head -20 "$TMP/ntacl.txt" fidrs showrepl在只有一台 DC 的环境里没有复制伙伴,输出为空或者直接报错,这不代表故障,所以走else分支记一行日志就够。ntacl sysvolcheck会把 sysvol 目录树上的实际 ACL 和 AD 里存的nTSecurityDescriptor做比对,返回非零说明有文件被人手工改过权限,或者从别的机器拷过来时权限丢了。这时候要做的是看具体是哪些路径,而不是直接跑sysvolreset——那条命令会以 AD 记录为准重刷全部 ACL,如果 AD 里的记录本身有问题,等于把错误放大一遍。
注意:
sysvolcheck在大目录树上会明显变慢,尤其是 GPO 里塞了大量文件的环境。日常巡检可以只查根目录,完整的 ACL 校验放到每周的低峰时段。
3.4 输出的可读性:纯文本报告加退出码分级
所有检查跑完之后,脚本要做两件事:统计异常项数量,以及把报告路径打印出来,方便直接贴进工单。
section "summary" WARN="$(grep -c '^\[.*\] ERROR' "$OUT" 2>/dev/null || echo 0)" echo "报告文件:$OUT" echo "异常条数:$WARN" # 退出码分级:0 全绿,2 有异常但仍可服务 [ "$WARN" -eq 0 ] && exit 0 || exit 2这里统计的是脚本自己写进日志的ERROR行,数量本身不代表严重程度,但能让值班的人第一时间知道“这次要不要看”。退出码只分两级,不再细分,因为 cron 和监控系统只关心“要不要叫人”。真要看细节,打开报告文件比解析退出码快得多。
4. backup-script 逐段讲:sysvol 与 AD 数据库的一致性备份
备份脚本是这套工具里唯一会“写东西”的部分,也是最容易出问题的部分。核心难点是活:一边是运行中的 Samba 进程在写sam.ldb以及 sysvol 里的 GPO,一边是你在拷贝文件。如果不管一致性,拷出来的可能是一个语义上根本不存在的中间状态,恢复的时候各种诡异报错。
4.1 备份对象盘点:三份东西一份都不能漏
在动手写代码之前,先确认要备什么。Samba 4 AD DC 的完整状态由三部分组成:
| 备份对象 | 默认路径 | 内容 | 怎么备 |
|---|---|---|---|
| sysvol | /var/lib/samba/sysvol | GPO 模板、脚本、ACL | tar --acls --xattrs |
| 私有目录 | /var/lib/samba/private | sam.ldb、密钥、DNS 数据 | samba-tool domain backup或冷备 |
| 配置 | /etc/samba/smb.conf及 include | 域参数、共享定义 | 直接cp -a |
常见的漏项有两种:只备了 sysvol,恢复时发现域内对象全没了;或者只备了private,恢复后 GPO 一个都不生效。还有一种更隐蔽:sysvol 里存了 GPO 的权限信息,用rsync拷到 ext4 之外的文件系统、或者拷到不支持 POSIX ACL 的存储上,ACL 会被悄悄丢掉,恢复时看着文件都在,sysvolcheck却报一大堆错。
4.2 动手写:backup-script.sh 的完整骨架
先建立环境和路径,做好防呆校验。这一段最容易被跳过,但跳过之后的后果往往是磁盘被一份递归打包的文件撑爆。
#!/bin/bash # backup-script.sh —— Samba 4 域控一致性备份 set -euo pipefail umask 077 BACKUP_ROOT="${BACKUP_ROOT:-/srv/backup/samba}" KEEP_DAYS="${KEEP_DAYS:-14}" STATE_DIR="${STATE_DIR:-/var/lib/samba}" STAMP="$(date +%Y%m%d-%H%M%S)" DEST="$BACKUP_ROOT/$STAMP" # 防呆:备份根目录绝不能落在被备份的目录里,否则 tar 把自己套进去 case "$(readlink -f "$BACKUP_ROOT")/" in "$(readlink -f "$STATE_DIR")"/*) echo "备份目录位于 $STATE_DIR 之下,请改到独立挂载点" >&2 exit 1 ;; esac mkdir -p "$DEST" trap 'echo "备份中断,残留目录:$DEST" >&2' ERRumask 077保证备份文件默认只有 root 可读——private目录里有密钥材料,权限松了等于把钥匙放在门口。readlink -f先把两边都转成绝对路径再比对,防止用相对路径或软链接绕过检查。trap ... ERR在set -e触发退出时打印残留目录,便于人工清理,这个细节在生产上很有用:跑到一半磁盘满的情况真的会发生。
接着备配置和 sysvol。sysvol 用tar而不是rsync,关键就在 ACL 参数上。
# 1) 配置和版本信息,恢复时要靠它对上号 cp -a /etc/samba/smb.conf "$DEST/smb.conf.bak" samba-tool --version > "$DEST/samba-version.txt" 2>&1 # 2) sysvol:必须保留 ACL 和扩展属性,GPO 权限丢了等于白备 tar --acls --xattrs --numeric-owner -cpf "$DEST/sysvol.tar" \ -C "$(dirname "$STATE_DIR")" "$(basename "$STATE_DIR")/sysvol" sha256sum "$DEST/sysvol.tar" > "$DEST/sysvol.tar.sha256"--acls打开 POSIX ACL 保存,--xattrs保留扩展属性,--numeric-owner不在包里存用户名而是存 uid/gid,这样在目标机器上用户名对不上也不影响恢复。-C切换目录再打包,包里路径就变成samba/sysvol/...这种相对形式,解压时不至于把绝对路径铺到根上——这个坑很多人在恢复演练时才第一次撞见。
然后处理 AD 数据库。首选让 Samba 自己保证一致性,也就是samba-tool domain backup,但前面说过,旧版本可能没有这个子命令。
# 3) AD 数据:优先用在线备份,让 Samba 自己处理一致性 if samba-tool domain backup --help >/dev/null 2>&1; then samba-tool domain backup online \ --server=127.0.0.1 \ --targetdir="$DEST" \ --no-secrets log "在线备份完成:$(ls "$DEST"/*.tar.bz2 2>/dev/null | head -1)" else # 4.5 及更早的版本没有该子命令,退回维护窗口冷备 log "当前版本不支持 domain backup,改用冷备流程" systemctl stop samba-ad-dc 2>/dev/null || systemctl stop samba tar --acls --xattrs -cpf "$DEST/private.tar" -C "$STATE_DIR" private systemctl start samba-ad-dc 2>/dev/null || systemctl start samba sha256sum "$DEST/private.tar" > "$DEST/private.tar.sha256" fi--server=127.0.0.1走本机,不用额外的网络凭证;--targetdir指定输出目录;--no-secrets表示包里不含密钥材料,安全性更好,但如果目标是整机裸恢复,就得去掉这个开关,否则域内信任关系恢复不了。冷备分支里停再起服务,窗口越短越好,所以只打private目录,sysvol 已经在前面备过了。
最后写清单和执行保留策略。
# 4) 清单文件:恢复时第一眼要看的东西 { echo "hostname=$(hostname -f)" echo "stamp=$STAMP" echo "debian=$(cat /etc/debian_version 2>/dev/null)" echo "samba=$(samba-tool --version 2>/dev/null | awk '{print $NF}')" echo "sysvol_sha256=$(cut -d' ' -f1 "$DEST/sysvol.tar.sha256")" } > "$DEST/manifest.txt" # 5) 保留策略:只删到期的,且至少留最近两份 find "$BACKUP_ROOT" -mindepth 1 -maxdepth 1 -type d -name '20*' \ -mtime +"$KEEP_DAYS" -print0 | sort -z | head -z -n -2 | xargs -0 -r rm -rf log "备份完成:$DEST"manifest.txt里记了主机名、Debian 版本、Samba 版本和 sysvol 的校验和。恢复时先看这个文件,能避免把 Stretch 的备份往 Jessie 上灌。保留策略那行有点绕:find找出超过保留天数的目录,sort按名字排序(也就是按时间),head -n -2去掉最后两个,剩下的才交给rm。效果是无论配置多激进,最近两份永远留着。
4.3 保留策略与定时任务:cron 里最容易翻车的地方
脚本手工跑通,搬到 cron 里挂掉,是这类运维脚本的经典剧本。原因通常不在脚本本身,而在环境:cron 的PATH很短,HOME是/root,.bashrc里的环境变量一概不生效。所以 crontab 里要把路径写全,环境变量显式传进去。
# /etc/cron.d/samba-backup SHELL=/bin/bash PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 30 2 * * * root BACKUP_ROOT=/srv/backup/samba KEEP_DAYS=21 /opt/samba4-scripts/backup-script.sh >> /var/log/samba-backup.log 2>&1PATH这一行不能省,samba-tool装在不同发行版的位置不一样,靠继承的默认PATH有概率找不到。BACKUP_ROOT和KEEP_DAYS直接写在命令行上,比依赖配置文件更直观,也避免了load_conf在 cron 环境下读不到文件的可能性。日志用>>追加,配合 logrotate 按周切割。
提示:先在 cron 里把时间设成几分钟后跑一次,等它真的执行完再改成凌晨。直接等到第二天看结果,出问题时连日志在哪都得猜。
4.4 恢复演练:把备份还原到一个隔离实例
没验证过的备份等于没有备份。演练脚本做的事情很单纯:拿一份备份,还原到一个隔离的目录里,起一个不同名字的实例,看它能不能正常起来。
# restore-check.sh 核心步骤:还原到隔离实例,不碰生产 BACKUP_FILE="$(ls -t /srv/backup/samba/*/samba-*.tar.bz2 | head -1)" TARGET_DIR=/srv/test-dc samba-tool domain backup restore \ --backup-file="$BACKUP_FILE" \ --targetdir="$TARGET_DIR" \ --newservername=testdc \ --configfile="$TARGET_DIR/etc/smb.conf" # 用独立端口和 socket 目录启动,避免和生产打架 samba -s "$TARGET_DIR/etc/smb.conf" \ --foreground --no-process-group \ --option="interfaces=127.0.0.2" \ --option="bind interfaces only=yes"--backup-file指向在线备份产出的 tar.bz2,--newservername必须和原主机名不同,否则还原出来的实例会认为自己就是原 DC,一旦接入网络会引发复制层面的混乱。用127.0.0.2这个回环地址段的第二个地址,是为了让测试实例监听在一个不冲突的 IP 上。起起来之后,用samba-tool domain info 127.0.0.2和samba-tool user list验证数据在不在,跑完就关掉。
5. 避坑与排查:在 Debian 上跑这套脚本最容易翻车的五处
下面五条都是实际运行时撞过的,按“现象、原因、解决”写,遇到类似症状可以直接对号入座。
5.1 脚本中途静默退出、报告只写了一半
现象:samba-info.sh跑完发现报告停在services那一节,后面全没了,退出码是 3。
原因:脚本开头写了set -e,而systemctl is-active对未激活的服务返回 3,触发了立即退出。同类问题还有samba-tool drs showrepl在单机环境返回非零。
解决:巡检类脚本去掉-e,改成set -uo pipefail,并对每个可能非零的命令显式|| true或放进if里。备份类脚本保留-e,因为它一旦出错就该停,不能继续写不完整的备份。
5.2 恢复之后 GPO 全不生效,sysvolcheck报一堆错
现象:备份看着完整,恢复后文件都在,但域内策略不下发,samba-tool ntacl sysvolcheck报权限不一致。
原因:备份时用的tar没带--acls --xattrs,或者备份目标不是支持 POSIX ACL 的文件系统,ACL 在拷贝过程中被丢掉。
解决:备份时固定tar --acls --xattrs --numeric-owner,备份根目录确认挂在 ext4、xfs 这类支持 ACL 的本地磁盘上,别直接往网络挂载里写。恢复后先跑一遍sysvolcheck确认,再谈别的。
5.3 磁盘一夜之间被撑满,备份目录体积暴涨
现象:凌晨跑完备份,第二天监控告警磁盘使用率 100%。
原因:BACKUP_ROOT配到了/var/lib/samba下面,tar在打包 sysvol 时把正在写入的备份文件也打了进去,递归膨胀。
解决:备份根目录必须放在独立挂载点,脚本开头用readlink -f做前缀比对,命中就退出。这条检查加上之后,同类问题再没出现过。
5.4 cron 里跑失败,手工跑正常
现象:终端执行一切正常,crontab 里执行报samba-tool: command not found或者读不到smb.conf。
原因:cron 环境的PATH极短,HOME也不同,~/.bashrc里的环境变量和别名全部不生效。
解决:crontab 顶部显式写SHELL和PATH,脚本里所有外部命令用绝对路径,或者至少在lib/common.sh里做一次command -v校验,缺什么直接die报出来,别让它跑到一半才失败。
5.5 备份文件权限过松,密钥材料裸奔
现象:安全扫描报告备份目录下存在全局可读文件。
原因:脚本没设umask,tar沿用当前 shell 的默认权限,private目录里的密钥文件被解出来是 644。
解决:脚本开头加umask 077,备份根目录本身设成700,并定期用find "$BACKUP_ROOT" -perm -o+r扫一遍。这件事没有后悔药,只能提前做。
6. 二次开发:把脚本改成你自己的巡检和备份流水线
这套脚本的结构留了足够的改造空间,改的时候不用动主干,只要在几个固定位置挂东西。
| 改造点 | 改法 | 验证方式 |
|---|---|---|
| 加检查项 | 在samba-info.sh里新增一个section块 | 单独跑脚本,看报告里有没有这一节 |
| 加告警 | 在退出码分级处接 webhook 或邮件 | 手动制造一个异常,看有没有收到 |
| 换备份介质 | 改BACKUP_ROOT,或在manifest.txt生成后加一步推送 | 从远端拉回来解压比对校验和 |
| 加钩子 | 在lib/common.sh里用run_hook埋点 | 放一个只echo的测试钩子跑一遍 |
钩子这部分很值得抽出来,因为它让“改脚本”变成“加文件”,升级主干时不用重新合并代码:
# lib/common.sh 片段:约定式钩子,存在且可执行才调用,失败不影响主流程 run_hook() { local name="$1"; shift local f="/etc/samba-scripts/hooks/${name}.sh" if [ -x "$f" ]; then log "执行钩子 $name" "$f" "$@" || log "钩子 $name 返回非零,已忽略" fi } # backup-script.sh 里在打包完成后调用 # run_hook post-backup "$DEST"run_hook只认/etc/samba-scripts/hooks/下的固定命名,post-backup、pre-restore、on-error这类名字一看就知道在什么时机触发。钩子失败只记日志不中断,是因为钩子通常做的是“推送、通知、打标签”这类外围动作,不该反过来把主流程带崩。
验证方法我建议做成一个固定的三步:先手动跑一次backup-script.sh,确认manifest.txt和校验和都在;然后从 sysvol 里删一个小文件,跑一次restore-check.sh,看还原出来的实例里那个文件在不在;最后把整条链路挂到 cron 上,等它自己跑一轮。三步都过了再上生产,比事后补救省事太多。
从那以后我每次改这套脚本,都强制走一遍“删一个文件、跑备份、从备份里捞回来”的验证,哪怕只改了一行echo。血泪经验是:运维脚本的 bug 不会当场报错,它会在你最需要备份的那天出现。希望帮到你。
本文还有配套的精品资源,点击获取