feat(deploy): 支持远程服务器部署
- deploy.sh 新增 push/remote-deploy/remote-stop/remote-status/remote-log 命令, 远程流程: 构建→上传→停旧→备份→启动→/mcp 健康检查 - 新增 deploy/remote.conf.example 模板(SSH/目录/JDK路径/JVM参数), 实际 remote.conf 已 gitignore - 远程启动前 source 服务器上的 app.env 注入环境变量 - 新增 application-prod.yml,敏感值全部走环境变量,不写明文
This commit is contained in:
@@ -9,5 +9,6 @@ front/dist/
|
||||
|
||||
# 本地部署凭据与运行态
|
||||
deploy/.env.dev
|
||||
deploy/remote.conf
|
||||
deploy/app.pid
|
||||
logs/
|
||||
|
||||
@@ -90,6 +90,87 @@ do_status() {
|
||||
fi
|
||||
}
|
||||
|
||||
# ---------- 远程部署 ----------
|
||||
REMOTE_CONF="$APP_HOME/deploy/remote.conf"
|
||||
|
||||
load_remote_conf() {
|
||||
if [ ! -f "$REMOTE_CONF" ]; then
|
||||
echo "[ERROR] 缺少 $REMOTE_CONF,请复制 deploy/remote.conf.example 并填写" >&2
|
||||
exit 1
|
||||
fi
|
||||
set -a; source "$REMOTE_CONF"; set +a
|
||||
: "${REMOTE_SSH_HOST:?未配置 REMOTE_SSH_HOST}"
|
||||
: "${REMOTE_DIR:?未配置 REMOTE_DIR}"
|
||||
REMOTE_SSH_PORT="${REMOTE_SSH_PORT:-22}"
|
||||
REMOTE_PROFILE="${REMOTE_PROFILE:-prod}"
|
||||
REMOTE_PORT="${REMOTE_PORT:-8088}"
|
||||
REMOTE_JAVA_OPTS="${REMOTE_JAVA_OPTS:-}"
|
||||
REMOTE_SPRING_ARGS="${REMOTE_SPRING_ARGS:-}"
|
||||
REMOTE_JAVA_BIN="${REMOTE_JAVA_BIN:-java}"
|
||||
}
|
||||
|
||||
ssh_remote() { ssh -p "$REMOTE_SSH_PORT" "$REMOTE_SSH_HOST" "$@"; }
|
||||
|
||||
do_push() {
|
||||
[ -f "$JAR" ] || { echo "[ERROR] 未找到 jar,先执行: $0 build" >&2; exit 1; }
|
||||
load_remote_conf
|
||||
ssh_remote "mkdir -p '$REMOTE_DIR/logs'"
|
||||
scp -P "$REMOTE_SSH_PORT" "$JAR" "$REMOTE_SSH_HOST:$REMOTE_DIR/xiaoqu-agent-service.jar.new"
|
||||
echo "[OK] 已上传到 $REMOTE_SSH_HOST:$REMOTE_DIR/xiaoqu-agent-service.jar.new"
|
||||
}
|
||||
|
||||
do_remote_deploy() {
|
||||
do_build
|
||||
do_push
|
||||
ssh_remote "REMOTE_DIR='$REMOTE_DIR' REMOTE_PROFILE='$REMOTE_PROFILE' REMOTE_PORT='$REMOTE_PORT' REMOTE_JAVA_OPTS='$REMOTE_JAVA_OPTS' REMOTE_SPRING_ARGS='$REMOTE_SPRING_ARGS' REMOTE_JAVA_BIN='$REMOTE_JAVA_BIN' bash -s" <<'EOS'
|
||||
set -euo pipefail
|
||||
cd "$REMOTE_DIR"
|
||||
if [ -f app.pid ] && kill -0 "$(cat app.pid)" 2>/dev/null; then
|
||||
kill "$(cat app.pid)"
|
||||
for i in $(seq 1 15); do kill -0 "$(cat app.pid)" 2>/dev/null || break; sleep 1; done
|
||||
kill -0 "$(cat app.pid)" 2>/dev/null && kill -9 "$(cat app.pid)"
|
||||
fi
|
||||
[ -f xiaoqu-agent-service.jar ] && cp xiaoqu-agent-service.jar "xiaoqu-agent-service.jar.bak.$(date +%Y%m%d%H%M%S)"
|
||||
mv -f xiaoqu-agent-service.jar.new xiaoqu-agent-service.jar
|
||||
if [ -f app.env ]; then
|
||||
set -a; source app.env; set +a
|
||||
else
|
||||
echo "[WARN] 未找到 $REMOTE_DIR/app.env,环境变量未注入,prd 可能启动失败" >&2
|
||||
fi
|
||||
nohup "$REMOTE_JAVA_BIN" $REMOTE_JAVA_OPTS -jar xiaoqu-agent-service.jar --spring.profiles.active="$REMOTE_PROFILE" $REMOTE_SPRING_ARGS >> logs/agent-service.log 2>&1 &
|
||||
echo $! > app.pid
|
||||
echo "[OK] 远程已启动 (pid $(cat app.pid)),等待健康检查..."
|
||||
for i in $(seq 1 90); do
|
||||
if ! kill -0 "$(cat app.pid)" 2>/dev/null; then
|
||||
echo "[ERROR] 远程进程已退出,最后 40 行日志:" >&2
|
||||
tail -40 logs/agent-service.log >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
code=$(curl -s -o /dev/null -w "%{http_code}" -X POST "http://127.0.0.1:$REMOTE_PORT/mcp" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Accept: application/json, text/event-stream' \
|
||||
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"deploy-check","version":"0"}}}' || true)
|
||||
if [ "$code" = "200" ] || [ "$code" = "401" ]; then
|
||||
echo "[OK] 远程服务已就绪 (HTTP $code, /mcp)"
|
||||
exit 0
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
echo "[ERROR] 远程健康检查超时,日志: $REMOTE_DIR/logs/agent-service.log" >&2
|
||||
exit 1
|
||||
EOS
|
||||
}
|
||||
|
||||
do_remote_stop() {
|
||||
load_remote_conf
|
||||
ssh_remote "cd '$REMOTE_DIR' && if [ -f app.pid ] && kill -0 \$(cat app.pid) 2>/dev/null; then kill \$(cat app.pid) && rm -f app.pid && echo '[OK] 远程已停止'; else echo '[SKIP] 远程未在运行'; fi"
|
||||
}
|
||||
|
||||
do_remote_status() {
|
||||
load_remote_conf
|
||||
ssh_remote "cd '$REMOTE_DIR' && if [ -f app.pid ] && kill -0 \$(cat app.pid) 2>/dev/null; then echo \"远程运行中 (pid \$(cat app.pid))\"; else echo '远程未运行'; exit 1; fi"
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
build) do_build ;;
|
||||
start) do_start ;;
|
||||
@@ -97,7 +178,12 @@ case "${1:-}" in
|
||||
restart) do_stop; do_start ;;
|
||||
status) do_status ;;
|
||||
log) tail -f "$LOG_FILE" ;;
|
||||
push) do_push ;;
|
||||
remote-deploy) do_remote_deploy ;;
|
||||
remote-stop) do_remote_stop ;;
|
||||
remote-status) do_remote_status ;;
|
||||
remote-log) load_remote_conf; ssh_remote "tail -f '$REMOTE_DIR/logs/agent-service.log'" ;;
|
||||
*)
|
||||
echo "用法: $0 {build|start|stop|restart|status|log}" >&2
|
||||
echo "用法: $0 {build|start|stop|restart|status|log|push|remote-deploy|remote-stop|remote-status|remote-log}" >&2
|
||||
exit 1 ;;
|
||||
esac
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# 远程部署配置(本文件为模板;实际使用复制为 remote.conf,已 gitignore,不入库)
|
||||
# 用法: cp deploy/remote.conf.example deploy/remote.conf,填好后执行 ./deploy/deploy.sh remote-deploy
|
||||
|
||||
# --- SSH 连接(必填)---
|
||||
# 推荐先在 ~/.ssh/config 配置别名和密钥,这里直接填别名,避免明文密码
|
||||
# 例如: REMOTE_SSH_HOST=xiaoqu-prd 或 REMOTE_SSH_HOST=deploy@192.168.1.100
|
||||
REMOTE_SSH_HOST=
|
||||
REMOTE_SSH_PORT=22
|
||||
|
||||
# --- 远程目录(必填)---
|
||||
# 远程服务器上的部署目录,jar、pid、日志都放在这里
|
||||
REMOTE_DIR=/opt/xiaoqu/agent-service
|
||||
|
||||
# --- 运行参数 ---
|
||||
# Spring profile(对应 application-<profile>.yml;若远程没有对应 yml,
|
||||
# 用下面的 REMOTE_SPRING_ARGS 覆盖具体配置项)
|
||||
REMOTE_PROFILE=prod
|
||||
# 服务端口(健康检查用)
|
||||
REMOTE_PORT=8088
|
||||
|
||||
# JVM 参数(可选)
|
||||
REMOTE_JAVA_OPTS=-Xms512m -Xmx1024m
|
||||
|
||||
# java 命令路径(可选,默认用 PATH 里的 java;远程有多个 JDK 时建议显式指定 17)
|
||||
# REMOTE_JAVA_BIN=/usr/lib/jvm/jre-17-openjdk/bin/java
|
||||
REMOTE_JAVA_BIN=
|
||||
|
||||
# 追加给 Spring Boot 的启动参数(可选),用于覆盖远程环境配置,例如:
|
||||
# REMOTE_SPRING_ARGS=--spring.datasource.url=jdbc:mysql://xxx:3306/db --spring.datasource.password=xxx
|
||||
REMOTE_SPRING_ARGS=
|
||||
|
||||
# 远程服务器要求: JDK 17+、curl(健康检查用)
|
||||
@@ -0,0 +1,38 @@
|
||||
# prd 环境:阿里云 RDS / Redis(拓扑沿用 xiaoqu-franchisee pom.xml prd profile)
|
||||
# 敏感值一律走环境变量,不写明文、不入库;
|
||||
# 服务器上由 /data/xiaoqu-agent-service/app.env 注入(deploy.sh 启动前 source)
|
||||
app:
|
||||
open:
|
||||
api-key: ${OPEN_API_KEY}
|
||||
# ak 明文 AES-GCM 加密密钥,prd 必须与 dev 不同值
|
||||
token-cipher-key: ${TOKEN_CIPHER_KEY}
|
||||
datasource:
|
||||
m0: # 权限库 xiaoqu_complex(user/agent/authority 等)
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
jdbc-url: ${SVC_DB_M0_URL}
|
||||
username: ${SVC_DB_M0_USER}
|
||||
password: ${SVC_DB_M0_PASSWORD}
|
||||
m1: # 商城库 xiaoqu_mall(按需启用)
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
jdbc-url: ${SVC_DB_M1_URL}
|
||||
username: ${SVC_DB_M1_USER}
|
||||
password: ${SVC_DB_M1_PASSWORD}
|
||||
m2: # 业务库 xiaoqu_franchisee
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
jdbc-url: ${SVC_DB_M2_URL}
|
||||
username: ${SVC_DB_M2_USER}
|
||||
password: ${SVC_DB_M2_PASSWORD}
|
||||
svc: # 自有库 xiaoqu_agent_svc(token/scope/tool/audit,读写,Flyway 自动建表)
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
jdbc-url: ${SVC_DB_SVC_URL}
|
||||
username: ${SVC_DB_SVC_USER}
|
||||
password: ${SVC_DB_SVC_PASSWORD}
|
||||
|
||||
spring:
|
||||
data:
|
||||
redis:
|
||||
host: ${SVC_REDIS_HOST}
|
||||
port: ${SVC_REDIS_PORT:6379}
|
||||
password: ${SVC_REDIS_PASSWORD}
|
||||
database: ${SVC_REDIS_DB:5}
|
||||
timeout: 5s
|
||||
Reference in New Issue
Block a user