自动化部署脚本核心是主动防御:以set -euo pipefail为守门员,关键步骤后显式错误拦截,前置环境检查与状态快照,日志与调试分离,严格权限与路径安全管控。

编写带有完善错误处理机制的自动化部署脚本,核心不是让脚本“跑起来”,而是确保它在任何异常下都能及时暴露问题、停止危险操作、留下可追溯线索。重点在于主动防御,而非事后补救。
用 set -euo pipefail 做全局守门员
脚本开头必须加上这行:
set -euo pipefail
它的作用是:
- -e:任一命令返回非零退出码,脚本立即终止(避免“上一步失败,下一步还硬干”)
- -u:引用未定义变量时报错退出(防止 $USER_DIR 写成 $USRE_DIR 这类低级错误静默执行)
-
-o pipefail:管道中任意一环失败,整个管道返回失败(比如
curl ... | tar -xzf -中 curl 失败,tar 不该继续)
关键步骤后加显式错误拦截
仅靠 set -e 不够——有些命令失败不报错(如 rsync 传输部分文件失败返回 23),或你需要记录更具体的上下文。每步重要操作后手动检查:
git pull origin main || { echo "ERROR: 代码拉取失败,行号 $LINENO" >&2; exit 1; }
mvn clean package -DskipTests || { echo "ERROR: 构建失败,当前目录 $(pwd)"; exit 1; }
这样能确保:
- 错误信息带行号和当前路径,定位快
- stderr 输出重定向到终端/日志,不被吞掉
- exit 1 强制中断,不往下执行停服务、删旧包等高危动作
前置检查 + 状态快照,防“带病部署”
部署前验证环境是否就绪,比部署中崩溃更有价值:
- 检查服务是否已运行:
systemctl is-active --quiet nginx || { echo "nginx 未运行,跳过重启"; } - 检查磁盘空间:
[ $(df -B1G /opt | awk 'NR==2 {print $4}') -lt 2 ] && { echo "警告:/opt 剩余空间不足 2GB"; exit 1; } - 记录部署前状态:
echo "部署前时间: $(date)" >> /var/log/deploy.log,方便回溯对比
日志与调试开关分离设计
生产环境不能靠 set -x 调试,但又需要可追溯性:
- 开头统一重定向所有输出:
exec >> /var/log/deploy_$(date +\%Y\%m\%d).log 2>&1 - 每个逻辑块加时间戳标记:
echo "[$(date '+%T')] 开始停止旧服务..." - 调试模式用开关控制:
if [[ "${DEBUG:-0}" == "1" ]]; then set -x; fi,上线时设 DEBUG=0 即可关闭
权限与路径安全不妥协
很多部署失败源于环境差异:
- 所有路径用绝对路径:
/usr/bin/java而非java,避免 cron 下 PATH 缺失 - 敏感配置(如数据库密码)不写进脚本,改用
source /etc/deploy/secrets.env,且该文件权限为600 - 部署用户最小权限原则:新建
deploy用户,只对/opt/app和/var/log/app有读写权,禁用 shell 登录


















