背景
上一篇配置了 GitHub Actions,push 后自动 SSH 到服务器执行 deploy.sh。
但最初的脚本只有三行:
cd /home/ubuntu/app
git pull
docker compose up -d –build
问题:如果新代码有 bug,容器起不来——网站直接挂,而且不会自动退回旧版本。
原因
部署脚本只做了"往前",没做"往后"。
一个能用的部署脚本,至少要包5个环节:
1. 部署脚本的完整环节
一个可靠的部署脚本,至少要包含以下五个环节:
| 记录当前版本 | 出错时知道回滚到哪 |
| 拉取新代码 | 更新到最新 |
| 构建+启动 | 应用新版本 |
| 健康检查 | 验证服务真的能用了 |
| 失败回滚 | 健康检查不过,退回旧版本 |
完整脚本
#!/bin/bash
set -euo pipefail
PROJECT_DIR="/home/ubuntu/app"
HEALTH_URL="http://127.0.0.1:8081/api/health"
cd "$PROJECT_DIR"
echo "🚀 开始部署 – $(date '+%F %T')"
# 1. 记录当前版本
LAST_GOOD=$(git rev-parse HEAD)
echo "📌 当前版本: ${LAST_GOOD:0:8}"
# 2. 回滚函数
rollback() {
echo "⚠️ 部署失败,回滚到 ${LAST_GOOD:0:8}"
git reset –hard "$LAST_GOOD"
docker compose up -d –build
exit 1
}
trap rollback ERR
# 3. 拉取最新代码
git fetch –all
git reset –hard origin/main
NEW_COMMIT=$(git rev-parse –short HEAD)
echo "📌 目标版本: $NEW_COMMIT"
# 4. 构建 + 启动
docker compose up -d –build
# 5. 健康检查(重试 5 次)
for i in $(seq 1 5); do
sleep 3
if curl -fsS "$HEALTH_URL" > /dev/null 2>&1; then
echo "✅ 健康检查通过(第 $i 次)"
exit 0
fi
echo " 第 $i 次失败,等待 3 秒…"
done
# 6. 健康检查失败,回滚
echo "❌ 健康检查 5 次全失败"
rollback
关键点解读
set -euo pipefail —— 脚本的"安全模式":
-e:任何命令失败立刻退出
-u:使用未定义变量报错
-o pipefail:管道中任何一环失败都算失败
没有这三条,脚本会"假装成功"——中间命令挂了它还继续往下跑。
trap rollback ERR —— 捕获任何错误触发回滚:
trap rollback ERR
之后脚本里任何一条命令失败,都会自动调 rollback()。
健康检查重试 5 次 —— 不要只检查一次:
for i in $(seq 1 5); do
sleep 3
if curl -fsS "$HEALTH_URL" > /dev/null 2>&1; then
echo "✅ 通过"
exit 0
fi
done
容器启动后需要几秒钟才能响应,给 15 秒的窗口,比只检查一次稳得多。
三个坑
坑 1:没加 set -e,脚本"假装成功"
比如 docker compose up -d –build 失败了,脚本不会中断,还会继续执行健康检查、输出"部署成功"。这种脚本比没有更危险——你以为部署成功了,其实没有。
坑 2:健康检查只跑一次
curl 一次失败就回滚,太激进。容器启动有延迟,要重试几次。把 5 次 × 3 秒的窗口当成标配。
坑 3:回滚用的是 git reset –hard
这会把服务器上的代码退回旧版本。但如果下一个 push 又拉最新代码,坏代码又回来了。真正的回滚应该是 git revert 后 push 到 GitHub——但那需要 deploy key 有写权限。
简化版:目前 reset –hard 够用。等有真实用户了,再上"revert + push"方案。
网硕互联帮助中心




评论前必须登录!
注册