diff --git a/deploy/deploy-frontend.sh b/deploy/deploy-frontend.sh index 465376b3..693206d7 100644 --- a/deploy/deploy-frontend.sh +++ b/deploy/deploy-frontend.sh @@ -1,58 +1,95 @@ -#!/bin/bash +#!/usr/bin/env bash # deploy-frontend.sh — Build Vuetify frontend and deploy to server # +# Docker 生产:前端在镜像内构建,远程执行 nexus-1panel.sh upgrade +# Supervisor:tar 上传到 web/app + supervisorctl restart +# # Usage: bash deploy/deploy-frontend.sh -# Run from the Nexus project root directory. set -euo pipefail +NEXUS_SSH_HOST="${NEXUS_SSH:-nexus}" +SSH_OPTS=(-o BatchMode=yes -o ConnectTimeout=15) +if [[ -n "${NEXUS_SSH_KEY:-}" ]]; then + SSH_OPTS+=(-i "${NEXUS_SSH_KEY}") +fi +ssh_cmd() { ssh "${SSH_OPTS[@]}" "${NEXUS_SSH_HOST}" "$@"; } + echo "═══ Nexus Frontend Deploy ═══" -# 1. Build -echo "▶ Building frontend..." +REMOTE_RUNTIME=$(ssh_cmd 'bash -s' <<'REMOTE' +set -euo pipefail +for d in /opt/nexus /www/wwwroot/api.synaglobal.vip; do + [[ -d "$d/server" ]] || continue + if [[ -f "$d/docker/.env.prod" ]] && docker compose version >/dev/null 2>&1; then + prof="$d/docker/.host-profile" + [[ -f "$prof" ]] || prof="$d/docker/profiles/2c8g.env" + if [[ -f "$prof" ]]; then + args=(-f "$d/docker/docker-compose.prod.yml") + docker network inspect 1panel-network >/dev/null 2>&1 && \ + [[ -f "$d/docker/docker-compose.1panel.yml" ]] && \ + args+=(-f "$d/docker/docker-compose.1panel.yml") + q=$(cd "$d" && docker compose "${args[@]}" \ + --env-file "$d/docker/.env.prod" --env-file "$prof" ps -q nexus 2>/dev/null || true) + [[ -n "$q" ]] && echo "docker $d" && exit 0 + fi + fi + if command -v supervisorctl >/dev/null 2>&1 && supervisorctl status nexus >/dev/null 2>&1; then + echo "supervisor $d" + exit 0 + fi +done +echo "unknown" +REMOTE +) + +RUNTIME="${REMOTE_RUNTIME%% *}" +DEPLOY_PATH="${REMOTE_RUNTIME#* }" +[[ "$DEPLOY_PATH" == "$REMOTE_RUNTIME" ]] && DEPLOY_PATH="/www/wwwroot/api.synaglobal.vip" + +echo "Remote runtime: ${RUNTIME} @ ${DEPLOY_PATH}" + +echo "▶ Building frontend (local verify)..." cd frontend && npx vite build && cd .. echo "✓ Build complete" -# 2. Tar the build output (index.html + assets/) -echo "▶ Packaging..." -tar czf /tmp/nexus-frontend.tar.gz -C web/app index.html assets/ -echo "✓ Package ready ($(du -h /tmp/nexus-frontend.tar.gz | cut -f1))" +if [[ "$RUNTIME" == "docker" ]]; then + echo "▶ Docker 生产:重建镜像以包含新前端(非 tar 热更新)..." + ssh_cmd "cd ${DEPLOY_PATH} && sudo env NEXUS_ROOT=${DEPLOY_PATH} bash ${DEPLOY_PATH}/deploy/nexus-1panel.sh upgrade" +else + echo "▶ Packaging..." + tar czf /tmp/nexus-frontend.tar.gz -C web/app index.html assets/ + echo "✓ Package ready ($(du -h /tmp/nexus-frontend.tar.gz | cut -f1))" -# 3. Upload to server -echo "▶ Uploading to server..." -scp /tmp/nexus-frontend.tar.gz nexus:/tmp/nexus-frontend.tar.gz -echo "✓ Upload complete" + echo "▶ Uploading to server..." + scp "${SSH_OPTS[@]}" /tmp/nexus-frontend.tar.gz "${NEXUS_SSH_HOST}:/tmp/nexus-frontend.tar.gz" + echo "✓ Upload complete" -# 4. Extract on server + prune orphaned legacy chunks -echo "▶ Deploying on server..." -ssh nexus "cd /www/wwwroot/api.synaglobal.vip/web/app && tar xzf /tmp/nexus-frontend.tar.gz && rm /tmp/nexus-frontend.tar.gz" -echo "▶ Pruning orphaned assets (dry-run first)..." -if ! ssh nexus "python3 /www/wwwroot/api.synaglobal.vip/deploy/prune_frontend_assets.py --dry-run"; then - echo "✗ Prune dry-run failed — aborting (no files deleted)" - exit 1 + echo "▶ Deploying on server..." + ssh_cmd "cd ${DEPLOY_PATH}/web/app && tar xzf /tmp/nexus-frontend.tar.gz && rm /tmp/nexus-frontend.tar.gz" + echo "▶ Pruning orphaned assets..." + if ! ssh_cmd "python3 ${DEPLOY_PATH}/deploy/prune_frontend_assets.py --dry-run"; then + echo "✗ Prune dry-run failed" + exit 1 + fi + ssh_cmd "python3 ${DEPLOY_PATH}/deploy/prune_frontend_assets.py" + echo "✓ Extracted and pruned" + + echo "▶ Restarting backend..." + ssh_cmd "supervisorctl restart nexus" + echo "✓ Restarted" fi -if ! ssh nexus "python3 /www/wwwroot/api.synaglobal.vip/deploy/prune_frontend_assets.py"; then - echo "✗ Prune failed — check index.html references before retry" - exit 1 -fi -echo "✓ Extracted and pruned" -# 5. Restart backend -echo "▶ Restarting backend..." -ssh nexus "supervisorctl restart nexus" -echo "✓ Restarted" - -# 6. Health check sleep 3 -HEALTH=$(ssh nexus "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8600/health" 2>/dev/null || echo "000") -SPA=$(ssh nexus "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8600/app/" 2>/dev/null || echo "000") +HEALTH=$(ssh_cmd "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8600/health" 2>/dev/null || echo "000") +SPA=$(ssh_cmd "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8600/app/" 2>/dev/null || echo "000") echo "" echo "═══ Verification ═══" echo " /health → $HEALTH" echo " /app/ → $SPA" -if [ "$HEALTH" = "200" ] && [ "$SPA" = "200" ]; then +if [[ "$HEALTH" == "200" || "$HEALTH" == "ok" ]] && [[ "$SPA" == "200" ]]; then echo "✓ Deploy successful!" else echo "✗ Verification failed — check server logs" diff --git a/deploy/deploy-on-server.sh b/deploy/deploy-on-server.sh index d475026c..fcf476f5 100644 --- a/deploy/deploy-on-server.sh +++ b/deploy/deploy-on-server.sh @@ -1,28 +1,44 @@ #!/usr/bin/env bash -# Run ON production server (宝塔终端 / ssh root@47.254.123.106) -# Pulls latest main from Gitea and restarts Nexus. Frontend tar must be uploaded separately -# if you did not build on this machine. +# Run ON production server — 自动识别 Docker / Supervisor # # Usage (on server): -# cd /www/wwwroot/api.synaglobal.vip -# bash deploy/deploy-on-server.sh +# cd /opt/nexus && sudo bash deploy/deploy-on-server.sh +# cd /www/wwwroot/api.synaglobal.vip && bash deploy/deploy-on-server.sh # # Optional env: # NEXUS_GITEA_TOKEN — if git pull needs auth -# SKIP_FRONTEND=1 — backend only +# SKIP_FRONTEND=1 — Supervisor 模式跳过热更新前端 tar +# NEXUS_DEPLOY_PATH — 覆盖自动检测路径 set -euo pipefail -DEPLOY_PATH="${NEXUS_DEPLOY_PATH:-/www/wwwroot/api.synaglobal.vip}" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +# shellcheck source=./detect_deploy_runtime.sh +source "${SCRIPT_DIR}/detect_deploy_runtime.sh" + +DEPLOY_PATH="$(resolve_nexus_root "${NEXUS_DEPLOY_PATH:-}" 2>/dev/null || true)" +if [[ -z "$DEPLOY_PATH" ]]; then + echo "ERROR: cannot resolve Nexus root" >&2 + exit 1 +fi cd "${DEPLOY_PATH}" -echo "═══ Nexus server-side deploy ═══" -echo "Path: ${DEPLOY_PATH}" +RUNTIME="$(detect_nexus_runtime "$DEPLOY_PATH")" +PORT="$(nexus_publish_port_for "$DEPLOY_PATH")" -if [ -n "${NEXUS_GITEA_TOKEN:-}" ]; then +echo "═══ Nexus server-side deploy ═══" +echo "Path: ${DEPLOY_PATH}" +echo "Runtime: ${RUNTIME}" + +if [[ -n "${NEXUS_GITEA_TOKEN:-}" ]]; then git remote set-url origin "http://admin:${NEXUS_GITEA_TOKEN}@66.154.115.8:3000/admin/Nexus.git" fi +if [[ "$RUNTIME" == "docker" ]]; then + echo "▶ Docker upgrade (pull + rebuild)..." + exec env NEXUS_ROOT="$DEPLOY_PATH" bash "$DEPLOY_PATH/deploy/nexus-1panel.sh" upgrade +fi + echo "▶ git fetch + reset --hard origin/main..." git fetch --all git reset --hard origin/main @@ -31,11 +47,11 @@ echo " HEAD: $(git log -1 --oneline)" echo "▶ supervisorctl restart nexus..." supervisorctl restart nexus -if [ -f /tmp/nexus-frontend.tar.gz ] && [ "${SKIP_FRONTEND:-0}" != "1" ]; then +if [[ -f /tmp/nexus-frontend.tar.gz && "${SKIP_FRONTEND:-0}" != "1" ]]; then echo "▶ extract /tmp/nexus-frontend.tar.gz..." tar xzf /tmp/nexus-frontend.tar.gz -C web/app rm -f /tmp/nexus-frontend.tar.gz - if [ -f deploy/prune_frontend_assets.py ]; then + if [[ -f deploy/prune_frontend_assets.py ]]; then python3 deploy/prune_frontend_assets.py --dry-run python3 deploy/prune_frontend_assets.py fi @@ -43,13 +59,14 @@ if [ -f /tmp/nexus-frontend.tar.gz ] && [ "${SKIP_FRONTEND:-0}" != "1" ]; then fi sleep 3 -HEALTH=$(curl -s http://127.0.0.1:8600/health || true) -SPA=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8600/app/ || echo "000") +HEALTH=$(curl -s "http://127.0.0.1:${PORT}/health" || true) +SPA=$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:${PORT}/app/" || echo "000") echo " /health → ${HEALTH}" echo " /app/ → ${SPA}" -if [ "${HEALTH}" = "ok" ] && [ "${SPA}" = "200" ]; then +if [[ "${HEALTH}" == "ok" && "${SPA}" == "200" ]]; then echo "✓ Server deploy OK" + suggest_ops_cron "$DEPLOY_PATH" else echo "✗ Verify failed — check: supervisorctl status nexus" >&2 exit 1 diff --git a/deploy/deploy-production.sh b/deploy/deploy-production.sh index cb9ac092..c1aa8ea5 100644 --- a/deploy/deploy-production.sh +++ b/deploy/deploy-production.sh @@ -1,14 +1,14 @@ #!/usr/bin/env bash -# Full production deploy: push (optional) + backend pull + frontend tar + health +# Full production deploy: push (optional) + backend upgrade + frontend + health +# +# 自动识别远程 Docker(/opt/nexus)或 Supervisor(/www/wwwroot/...)运行时。 # # Prerequisites on YOUR machine: -# - SSH: ~/.ssh/config Host nexus OR export NEXUS_SSH="root@47.254.123.106" +# - SSH: ~/.ssh/config Host nexus OR export NEXUS_SSH="azureuser@20.24.218.235" # - Key: export NEXUS_SSH_KEY=~/.ssh/id_rsa_nexus -# - Gitea push access for origin main # # Usage: # cd "$NEXUS_ROOT" -# git add ... && git commit ... && git push origin main # if not pushed yet # bash deploy/pre_deploy_check.sh # bash deploy/deploy-production.sh @@ -19,17 +19,14 @@ cd "${ROOT}" NEXUS_SSH_HOST="${NEXUS_SSH:-nexus}" SSH_OPTS=(-o BatchMode=yes -o ConnectTimeout=15) -if [ -n "${NEXUS_SSH_KEY:-}" ]; then +if [[ -n "${NEXUS_SSH_KEY:-}" ]]; then SSH_OPTS+=(-i "${NEXUS_SSH_KEY}") fi ssh_cmd() { ssh "${SSH_OPTS[@]}" "${NEXUS_SSH_HOST}" "$@"; } scp_cmd() { scp "${SSH_OPTS[@]}" "$@"; } -DEPLOY_PATH="${NEXUS_DEPLOY_PATH:-/www/wwwroot/api.synaglobal.vip}" - echo "═══ Nexus production deploy ═══" echo "SSH target: ${NEXUS_SSH_HOST}" -echo "Deploy path: ${DEPLOY_PATH}" if ! ssh_cmd "echo SSH OK" >/dev/null 2>&1; then echo "ERROR: Cannot SSH to ${NEXUS_SSH_HOST}" >&2 @@ -37,27 +34,82 @@ if ! ssh_cmd "echo SSH OK" >/dev/null 2>&1; then exit 1 fi -echo "▶ Backend: git pull + restart..." -ssh_cmd "cd ${DEPLOY_PATH} && git fetch --all && git reset --hard origin/main && supervisorctl restart nexus" +REMOTE_DETECT=$(ssh_cmd 'bash -s' <<'REMOTE' +set -euo pipefail +for d in /opt/nexus /www/wwwroot/api.synaglobal.vip; do + [[ -d "$d/server" ]] || continue + echo "ROOT=$d" + if [[ -f "$d/docker/.env.prod" ]] && docker compose version >/dev/null 2>&1; then + prof="$d/docker/.host-profile" + [[ -f "$prof" ]] || prof="$d/docker/profiles/2c8g.env" + if [[ -f "$prof" ]]; then + args=(-f "$d/docker/docker-compose.prod.yml") + docker network inspect 1panel-network >/dev/null 2>&1 && \ + [[ -f "$d/docker/docker-compose.1panel.yml" ]] && \ + args+=(-f "$d/docker/docker-compose.1panel.yml") + q=$(cd "$d" && docker compose "${args[@]}" \ + --env-file "$d/docker/.env.prod" --env-file "$prof" ps -q nexus 2>/dev/null || true) + [[ -n "$q" ]] && echo RUNTIME=docker && exit 0 + fi + fi + if command -v supervisorctl >/dev/null 2>&1 && supervisorctl status nexus >/dev/null 2>&1; then + echo RUNTIME=supervisor + exit 0 + fi + echo RUNTIME=unknown + exit 0 +done +echo RUNTIME=none +REMOTE +) -echo "▶ Frontend: build + upload..." -cd frontend && npx vite build && cd .. -tar czf /tmp/nexus-frontend.tar.gz -C web/app index.html assets/ -scp_cmd /tmp/nexus-frontend.tar.gz "${NEXUS_SSH_HOST}:/tmp/nexus-frontend.tar.gz" -ssh_cmd "cd ${DEPLOY_PATH}/web/app && tar xzf /tmp/nexus-frontend.tar.gz && rm /tmp/nexus-frontend.tar.gz" -if ssh_cmd "test -f ${DEPLOY_PATH}/deploy/prune_frontend_assets.py"; then - ssh_cmd "python3 ${DEPLOY_PATH}/deploy/prune_frontend_assets.py --dry-run" - ssh_cmd "python3 ${DEPLOY_PATH}/deploy/prune_frontend_assets.py" +DEPLOY_PATH="${NEXUS_DEPLOY_PATH:-$(echo "$REMOTE_DETECT" | sed -n 's/^ROOT=//p' | head -1)}" +RUNTIME="$(echo "$REMOTE_DETECT" | sed -n 's/^RUNTIME=//p' | head -1)" + +if [[ -z "$DEPLOY_PATH" ]]; then + DEPLOY_PATH="${NEXUS_DEPLOY_PATH:-/opt/nexus}" +fi +if [[ -z "$RUNTIME" || "$RUNTIME" == "none" ]]; then + RUNTIME="unknown" +fi + +echo "Deploy path: ${DEPLOY_PATH}" +echo "Runtime: ${RUNTIME}" + +if [[ "$RUNTIME" == "docker" ]]; then + echo "▶ Docker: git pull + 镜像重建(前端在镜像内 vite build)..." + ssh_cmd "cd ${DEPLOY_PATH} && sudo git fetch --all && sudo git reset --hard origin/main && \ + sudo env NEXUS_ROOT=${DEPLOY_PATH} bash ${DEPLOY_PATH}/deploy/nexus-1panel.sh upgrade" +elif [[ "$RUNTIME" == "supervisor" ]]; then + echo "▶ Supervisor: git pull + restart..." + ssh_cmd "cd ${DEPLOY_PATH} && git fetch --all && git reset --hard origin/main && supervisorctl restart nexus" + + echo "▶ Frontend: build + upload..." + cd frontend && npx vite build && cd .. + tar czf /tmp/nexus-frontend.tar.gz -C web/app index.html assets/ + scp_cmd /tmp/nexus-frontend.tar.gz "${NEXUS_SSH_HOST}:/tmp/nexus-frontend.tar.gz" + ssh_cmd "cd ${DEPLOY_PATH}/web/app && tar xzf /tmp/nexus-frontend.tar.gz && rm /tmp/nexus-frontend.tar.gz" + if ssh_cmd "test -f ${DEPLOY_PATH}/deploy/prune_frontend_assets.py"; then + ssh_cmd "python3 ${DEPLOY_PATH}/deploy/prune_frontend_assets.py --dry-run" + ssh_cmd "python3 ${DEPLOY_PATH}/deploy/prune_frontend_assets.py" + fi +else + echo "ERROR: 无法识别远程运行时(非 Docker 也非 Supervisor)" >&2 + echo " 请手动: ssh ${NEXUS_SSH_HOST} 'sudo nx update'" >&2 + exit 1 fi sleep 3 -HEALTH=$(ssh_cmd "curl -s http://127.0.0.1:8600/health" 2>/dev/null || true) -SPA=$(ssh_cmd "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8600/app/" 2>/dev/null || echo "000") +PORT="$(ssh_cmd "grep -E '^NEXUS_PUBLISH_PORT=' ${DEPLOY_PATH}/docker/.env.prod 2>/dev/null | cut -d= -f2 | tr -d '\"' || echo 8600")" +HEALTH=$(ssh_cmd "curl -s http://127.0.0.1:${PORT}/health" 2>/dev/null || true) +SPA=$(ssh_cmd "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:${PORT}/app/" 2>/dev/null || echo "000") echo " /health → ${HEALTH}" echo " /app/ → ${SPA}" -if [ "${HEALTH}" = "ok" ] && [ "${SPA}" = "200" ]; then +if [[ "${HEALTH}" == "ok" && "${SPA}" == "200" ]]; then echo "✓ Deploy successful" + ssh_cmd "command -v crontab >/dev/null && crontab -l 2>/dev/null | grep -q nexus-health-monitor" 2>/dev/null || \ + echo " 提示: 远程未安装巡检 cron,可在服务器执行 sudo nx cron" else - echo "✗ Verification failed — check supervisor logs on server" >&2 + echo "✗ Verification failed — check logs on server" >&2 exit 1 fi diff --git a/deploy/detect_deploy_runtime.sh b/deploy/detect_deploy_runtime.sh new file mode 100644 index 00000000..804e239d --- /dev/null +++ b/deploy/detect_deploy_runtime.sh @@ -0,0 +1,130 @@ +#!/usr/bin/env bash +# Nexus — 部署运行时检测(Docker 1Panel / Supervisor 裸机) +# +# source deploy/detect_deploy_runtime.sh +# ROOT="$(resolve_nexus_root)" +# RUNTIME="$(detect_nexus_runtime "$ROOT")" # docker | supervisor | unknown +set -euo pipefail + +_COMPOSE_FILE="docker/docker-compose.prod.yml" +_COMPOSE_1PANEL="docker/docker-compose.1panel.yml" +_ENV_PROD="docker/.env.prod" + +resolve_nexus_root() { + local hint="${1:-}" + if [[ -n "$hint" && -d "$hint/server" ]]; then + echo "$hint" + return 0 + fi + if [[ -n "${NEXUS_ROOT:-}" && -d "${NEXUS_ROOT}/server" ]]; then + echo "$NEXUS_ROOT" + return 0 + fi + if [[ -n "${NEXUS_DEPLOY_PATH:-}" && -d "${NEXUS_DEPLOY_PATH}/server" ]]; then + echo "$NEXUS_DEPLOY_PATH" + return 0 + fi + local d + for d in /opt/nexus /www/wwwroot/api.synaglobal.vip; do + if [[ -d "$d/server" ]]; then + echo "$d" + return 0 + fi + done + for d in /www/wwwroot/*/; do + [[ -d "${d}server" ]] || continue + echo "${d%/}" + return 0 + done + if command -v supervisorctl >/dev/null 2>&1; then + local cwd + cwd="$(supervisorctl status nexus 2>/dev/null | grep -oP 'cwd=\K[^ ,]+' || true)" + if [[ -n "$cwd" && -d "$cwd/server" ]]; then + echo "$cwd" + return 0 + fi + fi + return 1 +} + +_has_1panel_network() { + docker network inspect 1panel-network >/dev/null 2>&1 +} + +detect_nexus_runtime() { + local root="$1" + if [[ -f "$root/$_ENV_PROD" ]] && command -v docker >/dev/null 2>&1 \ + && docker compose version >/dev/null 2>&1; then + local -a args=(-f "$root/$_COMPOSE_FILE") + if _has_1panel_network && [[ -f "$root/$_COMPOSE_1PANEL" ]]; then + args+=(-f "$root/$_COMPOSE_1PANEL") + fi + local prof q + prof="$root/docker/.host-profile" + [[ -f "$prof" ]] || prof="$root/docker/profiles/2c8g.env" + if [[ -f "$prof" ]]; then + q="$(cd "$root" && docker compose "${args[@]}" \ + --env-file "$root/$_ENV_PROD" --env-file "$prof" \ + ps -q nexus 2>/dev/null || true)" + if [[ -n "$q" ]]; then + echo docker + return 0 + fi + fi + fi + if command -v supervisorctl >/dev/null 2>&1 \ + && supervisorctl status nexus >/dev/null 2>&1; then + echo supervisor + return 0 + fi + echo unknown +} + +nexus_publish_port_for() { + local root="$1" + local port + port="$(grep -E '^NEXUS_PUBLISH_PORT=' "$root/$_ENV_PROD" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '\r" ' || true)" + if [[ -z "$port" && -f "$root/.env" ]]; then + port="$(grep -E '^NEXUS_PORT=' "$root/.env" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '\r" ' || true)" + fi + echo "${port:-8600}" +} + +nexus_restart_service() { + local root="$1" + local runtime + runtime="$(detect_nexus_runtime "$root")" + case "$runtime" in + docker) + local cname + cname="$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E 'nexus-prod-nexus|nexus-nexus-1' | head -1 || true)" + if [[ -n "$cname" ]]; then + docker restart "$cname" + return 0 + fi + return 1 + ;; + supervisor) + supervisorctl restart nexus + ;; + *) + return 1 + ;; + esac +} + +nexus_has_ops_cron() { + command -v crontab >/dev/null 2>&1 \ + && crontab -l 2>/dev/null | grep -q 'nexus-health-monitor' +} + +suggest_ops_cron() { + local root="$1" + if nexus_has_ops_cron; then + return 0 + fi + echo "" + echo "[WARN] 未检测到 health_monitor / db_backup cron" + echo " 建议: sudo bash ${root}/deploy/install_ops_cron.sh" + echo " 或: sudo nx cron" +} diff --git a/deploy/nexus-1panel.sh b/deploy/nexus-1panel.sh index ac733890..821c8eee 100755 --- a/deploy/nexus-1panel.sh +++ b/deploy/nexus-1panel.sh @@ -1206,6 +1206,12 @@ cmd_upgrade() { rollback_compose_upgrade "$NEXUS_ROOT" || true exit 1 fi + # shellcheck source=./detect_deploy_runtime.sh + if [[ -f "$NEXUS_ROOT/deploy/detect_deploy_runtime.sh" ]]; then + # shellcheck disable=SC1091 + source "$NEXUS_ROOT/deploy/detect_deploy_runtime.sh" + suggest_ops_cron "$NEXUS_ROOT" + fi } cmd_check() { diff --git a/deploy/upgrade.sh b/deploy/upgrade.sh index 39bec7df..8fff4008 100644 --- a/deploy/upgrade.sh +++ b/deploy/upgrade.sh @@ -1,16 +1,17 @@ -#!/bin/bash -# ================================================================ -# Nexus 6.0 — Upgrade Script +#!/usr/bin/env bash +# Nexus 6.0 — Upgrade Script(自动识别 Docker / Supervisor) # -# Usage: -# sudo bash upgrade.sh # auto-detect deploy dir -# sudo bash upgrade.sh --deploy-dir /opt/nexus # specify deploy dir +# sudo bash deploy/upgrade.sh +# sudo bash deploy/upgrade.sh --deploy-dir /opt/nexus # -# Safe: git pull + pip install + restart. Database is NOT touched. -# ================================================================ - +# Docker 1Panel:委托 deploy/nexus-1panel.sh upgrade(拉代码 + 备份 + 重建镜像) +# Supervisor 裸机:git pull + venv pip + supervisorctl restart set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +# shellcheck source=./detect_deploy_runtime.sh +source "${SCRIPT_DIR}/detect_deploy_runtime.sh" + RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' @@ -21,98 +22,90 @@ warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } error() { echo -e "${RED}[ERROR]${NC} $*"; } DEPLOY_DIR="" +EXTRA_ARGS=() while [[ $# -gt 0 ]]; do - case $1 in + case "$1" in --deploy-dir) DEPLOY_DIR="$2"; shift 2 ;; + --no-backup|--require-backup|--no-cache|--prune|--check|--dry-run) + EXTRA_ARGS+=("$1"); shift ;; -h|--help) - echo "Usage: sudo bash upgrade.sh [--deploy-dir PATH]" - exit 0 ;; - *) shift ;; + cat <<'EOF' +用法: sudo bash deploy/upgrade.sh [--deploy-dir PATH] [nexus-1panel 升级选项] + +Docker 环境自动走 nexus-1panel.sh upgrade;Supervisor 环境走 venv + supervisorctl。 +EOF + exit 0 + ;; + *) EXTRA_ARGS+=("$1"); shift ;; esac done -# Auto-detect deploy directory -if [ -z "$DEPLOY_DIR" ]; then - # Check common locations - for d in /opt/nexus /www/wwwroot/*/; do - if [ -d "$d/server" ] && [ -d "$d/web" ]; then - DEPLOY_DIR="$d" - break - fi - done - # Try from Supervisor config - if [ -z "$DEPLOY_DIR" ]; then - DEPLOY_DIR=$(supervisorctl status nexus 2>/dev/null | grep -oP 'cwd=\K[^ ,]+' || true) - fi +if [[ -z "$DEPLOY_DIR" ]]; then + DEPLOY_DIR="$(resolve_nexus_root 2>/dev/null || true)" fi -if [ -z "$DEPLOY_DIR" ] || [ ! -d "$DEPLOY_DIR/server" ]; then - error "Cannot find Nexus installation. Use --deploy-dir to specify." +if [[ -z "$DEPLOY_DIR" || ! -d "$DEPLOY_DIR/server" ]]; then + error "找不到 Nexus 安装目录,请使用 --deploy-dir 指定" exit 1 fi +RUNTIME="$(detect_nexus_runtime "$DEPLOY_DIR")" + +if [[ "$RUNTIME" == "docker" ]]; then + info "检测到 Docker Compose 运行时,委托 nexus-1panel.sh upgrade" + exec env NEXUS_ROOT="$DEPLOY_DIR" bash "$DEPLOY_DIR/deploy/nexus-1panel.sh" upgrade "${EXTRA_ARGS[@]}" +fi + VENV_DIR="$DEPLOY_DIR/venv" ENV_FILE="$DEPLOY_DIR/.env" echo "" echo "==========================================" -echo " Nexus 6.0 Upgrade" +echo " Nexus 6.0 Upgrade (Supervisor)" echo "==========================================" echo " Deploy: $DEPLOY_DIR" echo "" -# 1. Pull latest code info "Step 1/4: Updating source code..." -if [ -d "$DEPLOY_DIR/.git" ]; then +if [[ -d "$DEPLOY_DIR/.git" ]]; then cd "$DEPLOY_DIR" - OLD_REV=$(git rev-parse HEAD 2>/dev/null || echo "unknown") + OLD_REV="$(git rev-parse HEAD 2>/dev/null || echo unknown)" git pull --ff-only 2>/dev/null || { - error "git pull failed. You may have local changes." - error "Resolve conflicts manually: cd $DEPLOY_DIR && git status" + error "git pull failed. Resolve conflicts: cd $DEPLOY_DIR && git status" exit 1 } - NEW_REV=$(git rev-parse HEAD 2>/dev/null || echo "unknown") - if [ "$OLD_REV" = "$NEW_REV" ]; then + NEW_REV="$(git rev-parse HEAD 2>/dev/null || echo unknown)" + if [[ "$OLD_REV" == "$NEW_REV" ]]; then info " Already up to date (no new commits)" else info " Updated: ${OLD_REV:0:8}..${NEW_REV:0:8}" fi else - warn " Not a git repo. Skip git pull (update files manually)" + warn " Not a git repo. Skip git pull" fi -# 2. Update Python dependencies info "Step 2/4: Updating Python dependencies..." -if [ -d "$VENV_DIR/bin" ]; then +if [[ -d "$VENV_DIR/bin" ]]; then "$VENV_DIR/bin/pip" install -q --upgrade pip "$VENV_DIR/bin/pip" install -q -r "$DEPLOY_DIR/requirements.txt" 2>/dev/null || { - warn " pip install had some warnings, but continuing..." + warn " pip install had warnings, continuing..." } else error " venv not found at $VENV_DIR. Run install.sh first." exit 1 fi -# 3. Restart application info "Step 3/4: Restarting Nexus..." supervisorctl restart nexus >/dev/null 2>&1 || { - warn " supervisorctl restart failed. Try manually: supervisorctl restart nexus" + warn " supervisorctl restart failed. Try: supervisorctl restart nexus" } -# 4. Health check info "Step 4/4: Verifying health..." - -# Read port from .env or default -PORT=8600 -if [ -f "$ENV_FILE" ]; then - PORT_FROM_ENV=$(grep '^NEXUS_PORT=' "$ENV_FILE" 2>/dev/null | cut -d'=' -f2 || true) - [ -n "$PORT_FROM_ENV" ] && PORT="$PORT_FROM_ENV" -fi - +PORT="$(nexus_publish_port_for "$DEPLOY_DIR")" HEALTH_OK=false -for i in $(seq 1 15); do - if curl -sf "http://127.0.0.1:$PORT/health" >/dev/null 2>&1; then +for _ in $(seq 1 15); do + if curl -sf "http://127.0.0.1:${PORT}/health" >/dev/null 2>&1; then HEALTH_OK=true break fi @@ -120,11 +113,12 @@ for i in $(seq 1 15); do done echo "" -if [ "$HEALTH_OK" = true ]; then +if [[ "$HEALTH_OK" == true ]]; then echo -e " ${GREEN}Upgrade complete! Nexus is healthy.${NC}" + suggest_ops_cron "$DEPLOY_DIR" else echo -e " ${YELLOW}Health check pending. Verify manually:${NC}" - echo " curl http://127.0.0.1:$PORT/health" + echo " curl http://127.0.0.1:${PORT}/health" echo " supervisorctl status nexus" fi echo "" diff --git a/docs/changelog/2026-06-06-nx-god-menu-audit-round5-deploy-runtime-detect.md b/docs/changelog/2026-06-06-nx-god-menu-audit-round5-deploy-runtime-detect.md new file mode 100644 index 00000000..50bb2670 --- /dev/null +++ b/docs/changelog/2026-06-06-nx-god-menu-audit-round5-deploy-runtime-detect.md @@ -0,0 +1,36 @@ +# nx 上帝菜单巡检第五轮 — 部署脚本 Docker/Supervisor 分流 + +| 项 | 内容 | +|----|------| +| 日期 | 2026-06-06 | +| 动机 | `upgrade.sh`、`deploy-production.sh` 等仍硬编码 Supervisor + `/www/wwwroot`,Docker 1Panel 生产(`/opt/nexus`)无法正确升级 | + +## 变更摘要 + +1. **detect_deploy_runtime.sh**(新):共享 `resolve_nexus_root` / `detect_nexus_runtime` / `suggest_ops_cron`。 +2. **upgrade.sh**:检测到 Docker Compose 栈时 `exec nexus-1panel.sh upgrade`;Supervisor 保留 venv 路径。 +3. **deploy-production.sh**:SSH 远程探测运行时;Docker 走镜像重建,Supervisor 走 tar 前端 + supervisorctl。 +4. **deploy-on-server.sh** / **deploy-frontend.sh**:同上自动分流。 +5. **nexus-1panel.sh upgrade**:成功后若未安装 cron 则提示 `nx cron`。 + +## 涉及文件 + +- `deploy/detect_deploy_runtime.sh` +- `deploy/upgrade.sh` +- `deploy/deploy-production.sh` +- `deploy/deploy-on-server.sh` +- `deploy/deploy-frontend.sh` +- `deploy/nexus-1panel.sh` + +## 迁移 / 重启 + +- 仅 host 脚本更新,`git pull` 即可;无需 DB 迁移。 + +## 验证 + +```bash +bash -n deploy/detect_deploy_runtime.sh deploy/upgrade.sh deploy/deploy-production.sh +# Docker 生产: +sudo bash deploy/upgrade.sh --deploy-dir /opt/nexus --check +sudo bash deploy/deploy-on-server.sh --help 2>/dev/null || true +```