对于个人项目或内部测试环境,编写 Shell 脚本配合 nohup 启动是最轻量的方案;如果是生产环境,建议优先考虑 systemd 或容器化部署,脚本仅作为辅助手段。
先说结论:脚本能解决重复劳动,但必须包含进程清理、端口等待和健康检查逻辑,生产环境需谨慎。
- 适合:小型 VPS 或测试环境,资源有限且变更频率低
- 核心:避免使用 pkill 误杀,增加启动失败回滚机制
- 建议:生产环境改用 systemd 管理,脚本用于构建或备份环节
完整部署脚本示例
以下脚本包含了环境变量配置、安全停止、备份、启动及健康检查流程。请根据实际路径修改头部变量。
#!/bin/bash
# ================= 配置区 =================
APP_NAME="your-app.jar"
APP_PORT="8080"
WORK_DIR="/opt/app"
BACKUP_DIR="/opt/app/backup"
JAVA_OPTS="-Xms512m -Xmx512m"
HEALTH_URL="http://localhost:${APP_PORT}/actuator/health"
# =========================================
cd ${WORK_DIR} || exit 1
# 1. 停止旧进程 (避免 pkill 误杀)
echo "Stopping old process..."
PID=$(ps -ef | grep ${APP_NAME} | grep -v grep | awk '{print $2}')
if [ -n "$PID" ]; then
kill $PID
# 等待端口释放
for i in {1..30}; do
if ! netstat -tlnp | grep :${APP_PORT} > /dev/null 2>&1; then
break
fi
sleep 1
done
# 如果端口仍占用,强制杀死
if netstat -tlnp | grep :${APP_PORT} > /dev/null 2>&1; then
PID=$(ps -ef | grep ${APP_NAME} | grep -v grep | awk '{print $2}')
[ -n "$PID" ] && kill -9 $PID
sleep 2
fi
fi
# 2. 备份旧版本
if [ -f "${WORK_DIR}/${APP_NAME}" ]; then
mkdir -p ${BACKUP_DIR}
cp ${APP_NAME} ${BACKUP_DIR}/${APP_NAME}.$(date +%Y%m%d%H%M%S)
echo "Backup completed."
fi
# 3. 启动新服务
echo "Starting new process..."
nohup java ${JAVA_OPTS} -jar ${APP_NAME} `--server`.port=${APP_PORT} > app.log 2>&1 &
# 4. 健康检查 (等待最多 60 秒)
echo "Checking health..."
for i in {1..60}; do
sleep 1
if curl -s ${HEALTH_URL} | grep -q "UP"; then
echo "Deployment successful!"
exit 0
fi
done
echo "Deployment failed! Check app.log"
# 此处可添加回滚逻辑,如恢复 backup 目录最新文件
exit 1脚本授权与执行
脚本编写完成后,需要赋予执行权限并通过后台任务或直接调用运行。
# 赋予执行权限
chmod +x deploy.sh
# 执行部署
./deploy.sh
# 查看实时日志
tail -f app.log验证部署是否生效
脚本执行退出码为 0 仅代表健康检查通过,建议人工二次确认。
- 进程验证:
ps -ef | grep ${APP_NAME}确认进程存在且 PID 已更新。 - 端口验证:
ss -tlnp | grep ${APP_PORT}确认端口处于 LISTEN 状态。 - 业务验证:调用核心接口或访问首页,确认业务逻辑正常。
- 日志验证:
tail -n 100 app.log确认无 Exception 堆栈信息。
生产环境增强建议
纯脚本部署缺乏守护能力,生产环境建议配合以下措施:
1. 日志切割配置
防止 app.log 无限增长占满磁盘,配置 logrotate。
/opt/app/app.log {
daily
rotate 7
missingok
notifempty
copytruncate
}2. 定时任务备份
可结合 crontab 定期清理备份目录,保留最近 N 个版本。
# 每天凌晨清理 7 天前的备份
0 2 * * * find /opt/app/backup -name "*.jar.*" -mtime +7 -delete3. 使用 systemd 托管
更推荐编写 /etc/systemd/system/myapp.service 文件,利用系统能力实现开机自启和崩溃重启。
常见坑与排查
- 端口占用等待:旧进程 killed 后端口可能处于 TIME_WAIT 状态,脚本中已增加循环检测端口释放的逻辑。
- Java 版本不一致:编译环境与实践环境 Java 版本不同可能导致 class version 错误,部署前务必核对
java -version。 - 权限问题:确保脚本用户对
WORK_DIR和日志文件有读写权限,避免Permission denied。 - 环境变量丢失:nohup 启动可能丢失部分环境变量,建议在脚本中显式 export 所需变量。