#!/bin/bash # ============================================================= # 智价云(药店版) - Linux 生产环境部署脚本 # 用法:./deploy.sh [start|stop|restart|status|build|logs] # ============================================================= set -euo pipefail # ---------- 基础配置(按实际路径修改) ---------- APP_NAME="zhijiayun-pharmacy" APP_HOME="/opt/zhijiayun-pharmacy" JAR_NAME="zhijiayun-gateway-1.0.0.jar" JAR_PATH="${APP_HOME}/${JAR_NAME}" LOG_DIR="/opt/logs/zhijiayun-pharmacy" PID_FILE="${APP_HOME}/${APP_NAME}.pid" ENV_FILE="${APP_HOME}/.env" # JVM 参数(根据服务器内存调整 -Xmx) JAVA_OPTS="-server \ -Xms512m \ -Xmx1g \ -XX:MetaspaceSize=128m \ -XX:MaxMetaspaceSize=256m \ -XX:+UseG1GC \ -XX:MaxGCPauseMillis=200 \ -XX:+HeapDumpOnOutOfMemoryError \ -XX:HeapDumpPath=${LOG_DIR}/heapdump.hprof \ -Dfile.encoding=UTF-8 \ -Duser.timezone=Asia/Shanghai" # ---------- 颜色输出 ---------- RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m' info() { echo -e "${GREEN}[INFO]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } error() { echo -e "${RED}[ERROR]${NC} $*"; exit 1; } # ---------- 加载环境变量 ---------- load_env() { if [ -f "${ENV_FILE}" ]; then info "加载环境变量: ${ENV_FILE}" set -a # shellcheck source=/dev/null source "${ENV_FILE}" set +a else warn ".env 文件不存在: ${ENV_FILE},请确认已配置环境变量" fi # 校验必填环境变量 local required_vars=("DB_PASSWORD" "REDIS_PASSWORD" "JWT_SECRET" "ALIBABA_CLOUD_ACCESS_KEY_ID" "ALIBABA_CLOUD_ACCESS_KEY_SECRET") for var in "${required_vars[@]}"; do if [ -z "${!var:-}" ]; then error "必填环境变量 ${var} 未设置,请检查 ${ENV_FILE}" fi done } # ---------- 获取 PID ---------- get_pid() { if [ -f "${PID_FILE}" ]; then local pid pid=$(cat "${PID_FILE}") if kill -0 "${pid}" 2>/dev/null; then echo "${pid}" return fi rm -f "${PID_FILE}" fi # 兜底:通过进程名查找 pgrep -f "${JAR_NAME}" || true } # ---------- 启动 ---------- do_start() { local pid pid=$(get_pid) if [ -n "${pid}" ]; then warn "应用已在运行,PID=${pid},跳过启动" return fi load_env [ ! -f "${JAR_PATH}" ] && error "JAR 包不存在: ${JAR_PATH}" mkdir -p "${LOG_DIR}" info "启动 ${APP_NAME} ..." nohup java ${JAVA_OPTS} \ -jar "${JAR_PATH}" \ --spring.profiles.active=prod \ > "${LOG_DIR}/startup.log" 2>&1 & local new_pid=$! echo "${new_pid}" > "${PID_FILE}" info "启动中,PID=${new_pid},等待健康检查..." # 等待最多 60 秒 local timeout=60 while [ ${timeout} -gt 0 ]; do sleep 2 if curl -sf "http://localhost:8002/actuator/health" > /dev/null 2>&1; then info "✅ 应用启动成功!PID=${new_pid}" return fi timeout=$((timeout - 2)) echo -n "." done echo "" error "❌ 应用启动超时,请查看日志: tail -f ${LOG_DIR}/startup.log" } # ---------- 停止 ---------- do_stop() { local pid pid=$(get_pid) if [ -z "${pid}" ]; then warn "应用未运行" return fi info "正在停止 ${APP_NAME},PID=${pid} ..." kill -15 "${pid}" local timeout=30 while [ ${timeout} -gt 0 ]; do if ! kill -0 "${pid}" 2>/dev/null; then rm -f "${PID_FILE}" info "✅ 应用已停止" return fi sleep 1 timeout=$((timeout - 1)) done warn "优雅停止超时,强制终止 PID=${pid}" kill -9 "${pid}" 2>/dev/null || true rm -f "${PID_FILE}" info "已强制终止" } # ---------- 重启 ---------- do_restart() { do_stop sleep 2 do_start } # ---------- 状态 ---------- do_status() { local pid pid=$(get_pid) if [ -n "${pid}" ]; then info "✅ ${APP_NAME} 运行中,PID=${pid}" # 尝试健康检查 if curl -sf "http://localhost:8002/actuator/health" 2>/dev/null; then echo "" else warn "健康检查端口无响应(应用可能正在启动中)" fi else warn "❌ ${APP_NAME} 未运行" fi } # ---------- 构建(需要 Maven) ---------- do_build() { local project_dir project_dir="$(dirname "$(dirname "$(realpath "$0")")")" info "Maven 打包: ${project_dir}" cd "${project_dir}" mvn clean package -DskipTests -pl zhijiayun-gateway -am local jar_src jar_src="${project_dir}/zhijiayun-gateway/target/${JAR_NAME}" [ ! -f "${jar_src}" ] && error "构建产物不存在: ${jar_src}" mkdir -p "${APP_HOME}" cp -f "${jar_src}" "${JAR_PATH}" info "✅ 构建完成,JAR 已复制到: ${JAR_PATH}" } # ---------- 日志 ---------- do_logs() { local lines=${2:-200} local log_file="${LOG_DIR}/zhijiayun-pharmacy.log" if [ -f "${log_file}" ]; then tail -n "${lines}" -f "${log_file}" else tail -n "${lines}" -f "${LOG_DIR}/startup.log" fi } # ---------- 入口 ---------- case "${1:-help}" in start) do_start ;; stop) do_stop ;; restart) do_restart ;; status) do_status ;; build) do_build ;; logs) do_logs ;; *) echo "用法: $0 {start|stop|restart|status|build|logs}" echo "" echo " start 启动应用(自动加载 .env)" echo " stop 优雅停止应用" echo " restart 重启应用" echo " status 查看运行状态 + 健康检查" echo " build Maven 打包并复制 JAR 到部署目录" echo " logs 实时跟踪日志(默认最后200行)" ;; esac