大家好,我是剽悍一小兔,独立开发者,副业搞钱尝试者,热爱技术分享,欢迎一起学习交流。我会每天分享编程技术、独立开发、行业咨询、思考感悟。
代表作:《JavaScript百炼成仙》
公众号:java小白翻身
小程序:速用百宝箱
设计一个包含进程检测、停止旧实例、编译打包、启动新实例的自动化脚本,并解决端口冲突问题。以下是完整脚本及关键逻辑说明:
自动化部署脚本(deploy.sh)
#!/bin/bash
set -euo pipefail # 严格模式:遇到错误立即终止,未定义变量报错
# ==================== 可自定义配置 ====================
PROJECT_DIR="/path/to/your/project" # 项目根目录(含pom.xml的目录)
JAR_NAME="your-app.jar" # 编译后的jar包名称(如:demo-0.0.1-SNAPSHOT.jar)
JAVA_OPTS="-Xmx512m -Xms256m" # JVM参数(根据服务器内存调整)
LOG_FILE="app.log" # 日志输出文件
PORT=8080 # 应用端口(用于检测端口是否释放)
# ======================================================
# 函数:停止当前运行的jar进程
stop_jar() {
echo "正在查找运行中的 $JAR_NAME 进程..."
local pid=$(ps -ef | grep "java -jar $JAR_NAME" | grep -v grep | awk '{print $2}')
if [ -n "$pid" ]; then
echo "找到进程PID: $pid,尝试优雅停止..."
kill -15 "$pid" # 发送SIGTERM信号,允许进程优雅退出
# 等待进程终止(最多30秒)
local timeout=30
local end_time=$(( $(date +%s) + timeout ))
while [ $(date +%s) -lt $end_time ]; do
if ! ps -p "$pid" > /dev/null; then
echo "进程 $pid 已停止"
return 0
fi
sleep 1
done
# 超时未停止则强制终止
echo "优雅停止超时,强制终止进程 $pid..."
kill -9 "$pid"
sleep 2 # 确保进程资源释放
else
echo "未找到运行中的 $JAR_NAME 进程"
fi
}
# 函数:检查端口是否已释放
check_port() {
local port=$1
echo "检查端口 $port 是否释放..."
while true; do
if ! lsof -i :$port > /dev/null; then
echo "端口 $port 已释放"
return 0
fi
echo "端口 $port 仍被占用,等待5秒..."
sleep 5
done
}
# 主流程
echo "===== 开始自动化部署 ====="
# 步骤1:进入项目目录
cd "$PROJECT_DIR" || { echo "项目目录 $PROJECT_DIR 不存在!"; exit 1; }
# 步骤2:拉取最新代码
echo "正在执行 git pull..."
git pull || { echo "git pull 失败!"; exit 1; }
# 步骤3:编译打包(跳过测试)
echo "正在执行 mvn clean package..."
mvn clean package -DskipTests || { echo "mvn 编译打包失败!"; exit 1; }
# 步骤4:停止旧进程
stop_jar
# 步骤5:确保端口释放(避免旧进程残留占用端口)
check_port "$PORT"
# 步骤6:启动新实例(后台运行+日志重定向)
echo "正在启动新实例 $JAR_NAME..."
nohup java $JAVA_OPTS -jar "target/$JAR_NAME" > "$LOG_FILE" 2>&1 &
echo "部署完成!新进程PID: $!"
echo "日志查看:tail -f $LOG_FILE"
echo "应用端口:$PORT"
脚本关键逻辑说明
1. 严格错误处理
- •
set -euo pipefail
:脚本遇到错误(如命令执行失败)立即终止,避免因局部失败导致后续步骤出错。 - • 每个关键步骤(如
git pull
、mvn package
)后检查退出状态(|| { ... }
),失败时明确提示并终止脚本。
2. 停止旧进程(避免端口冲突核心逻辑)
- • 优雅停止:先用
kill -15
(SIGTERM)通知进程正常退出(允许释放资源、保存状态)。 - • 超时强制终止:若30秒内未停止(可能因死锁或资源占用),用
kill -9
强制终止,确保端口释放。 - • 精准查找进程:通过
grep "java -jar $JAR_NAME"
匹配特定jar进程,避免误杀其他Java进程。
3. 端口释放检查
- • 即使旧进程被终止,操作系统可能需要短暂时间回收端口(TIME_WAIT状态)。通过
lsof -i :$PORT
检测端口是否完全释放,避免新进程启动时提示“端口已被占用”。
4. 后台运行与日志记录
- • 使用
nohup
避免终端关闭导致进程终止。 - •
> "$LOG_FILE" 2>&1
将标准输出(stdout)和错误输出(stderr)统一重定向到日志文件,方便排查问题。
使用说明
- 1. 修改配置:替换脚本中
PROJECT_DIR
(项目路径)、JAR_NAME
(jar包名称)、JAVA_OPTS
(JVM参数)、PORT
(应用端口)为实际值。 - 2. 赋予执行权限:
chmod +x deploy.sh
- 3. 执行脚本:
./deploy.sh
扩展建议
- • 添加健康检查:启动后通过
curl
检查应用是否正常响应(如curl http://localhost:8080/actuator/health
),确保启动成功。 - • 集成CI/CD:可将脚本添加到GitLab CI、Jenkins等工具,实现代码提交后自动触发部署。
- • 日志分割:若日志文件过大,可结合
logrotate
定期切割日志。
如果需要进一步调整(如适配systemd服务、添加邮件通知等),可以告诉我具体需求,我会帮你优化脚本。