智享教程网
白蓝主题五 · 清爽阅读
首页  > 日常经验

手写一个靠谱的持续部署脚本,上线再也不用提心吊胆

上周五下午三点,线上订单接口突然 502,排查一圈发现是新版本打包后漏传了 config.js —— 因为部署还是靠人工 scp + systemctl restart,手一抖,跳过了配置文件同步这步。

别让“手动上线”成为故障源头

很多小团队没上 Jenkins 或 GitLab CI,不是不想,是觉得太重。但真没必要。一个不到 50 行的 shell 脚本,配上 git hook 和简单权限控制,就能把「改完代码 → 推到 main → 自动上线」跑通。关键是:它能跑、好查、出错了立刻知道哪一步挂了。

一个真实可用的 deploy.sh 示例

假设你用的是 Node.js 服务,部署到 Ubuntu 服务器,代码托管在 GitHub,项目结构长这样:

my-app/
├── package.json
├── dist/
├── .env.production
└── deploy.sh

本地开发完,运行 git push origin main 后,服务器自动拉取、安装依赖、重启服务。脚本核心逻辑如下:

#!/bin/bash
# deploy.sh - 放在项目根目录,chmod +x deploy.sh

APP_DIR="/var/www/my-app"
BACKUP_DIR="/var/www/backups"
LOG_FILE="/var/log/my-app-deploy.log"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)

echo "[$(date)] 开始部署..." >> $LOG_FILE

# 进入项目目录
cd $APP_DIR || { echo "进入目录失败" >> $LOG_FILE; exit 1; }

# 备份当前 dist(可选)
mkdir -p $BACKUP_DIR
cp -r ./dist $BACKUP_DIR/dist-$TIMESTAMP >> $LOG_FILE 2>&1

# 拉取最新代码
git pull origin main >> $LOG_FILE 2>&1
if [ $? -ne 0 ]; then
echo "git pull 失败" >> $LOG_FILE
exit 1
fi

# 安装依赖(--production 跳过 dev 依赖)
npm ci --production >> $LOG_FILE 2>&1
if [ $? -ne 0 ]; then
echo "npm 安装失败" >> $LOG_FILE
exit 1
fi

# 构建(如需)
npm run build >> $LOG_FILE 2>&1

# 重启服务(假设用 pm2)
pm2 reload my-app --update-env >> $LOG_FILE 2>&1
if [ $? -ne 0 ]; then
echo "pm2 重启失败,尝试启动..." >> $LOG_FILE
pm2 start ecosystem.config.js --only my-app >> $LOG_FILE 2>&1
fi

echo "[$(date)] 部署完成" >> $LOG_FILE

怎么让它“自动”起来?

把脚本放服务器上还不够,得让它感知到代码更新。最轻量的办法:在服务器上开个 webhook 接口(比如用 Python 的 Flask 写个三行路由),或者更简单——直接配个 git 的 post-receive hook。

比如,在服务器的 bare 仓库里(/var/repo/my-app.git/hooks/post-receive)加一行:

#!/bin/bash
GIT_WORK_TREE=/var/www/my-app git checkout -f main
cd /var/www/my-app && ./deploy.sh

再给这个 hook 加执行权限:chmod +x post-receive。之后每次 push,服务器就自己动起来了。

几个踩过的坑,顺手记下来

• 环境变量别硬编码:.env 文件千万别提交到 git,用 scp .env.production user@server:/var/www/my-app/.env 单独传一次,脚本里只负责读取;
• 权限问题很常见:确保运行脚本的用户对 /var/www/my-app 有读写权限,pm2 也得用同一用户启;
• 日志别省:每一步都 echo + 重定向到日志,半夜报警时翻 log 比猜快十倍;
• 不要跳过测试:哪怕只是 curl -s http://localhost:3000/health | grep ok,上线后自动验一下接口通不通,比等用户反馈强。

脚本不追求多炫酷,能稳、能查、能快速回滚,就是好脚本。上线前多跑两遍,比写一百行文档都管用。