| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- #!/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="/var/log/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:8001/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:8001/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
|