fix(deploy): 部署脚本自动识别 Docker 与 Supervisor 运行时

upgrade/deploy-production 等分流到 nexus-1panel upgrade;升级完成后提示安装 nx cron。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Nexus Agent
2026-06-06 23:07:47 +08:00
parent ba69bc3355
commit 89865ec690
7 changed files with 397 additions and 125 deletions
+70 -33
View File
@@ -1,58 +1,95 @@
#!/bin/bash #!/usr/bin/env bash
# deploy-frontend.sh — Build Vuetify frontend and deploy to server # deploy-frontend.sh — Build Vuetify frontend and deploy to server
# #
# Docker 生产:前端在镜像内构建,远程执行 nexus-1panel.sh upgrade
# Supervisortar 上传到 web/app + supervisorctl restart
#
# Usage: bash deploy/deploy-frontend.sh # Usage: bash deploy/deploy-frontend.sh
# Run from the Nexus project root directory.
set -euo pipefail 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 ═══" echo "═══ Nexus Frontend Deploy ═══"
# 1. Build REMOTE_RUNTIME=$(ssh_cmd 'bash -s' <<'REMOTE'
echo "▶ Building frontend..." 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 .. cd frontend && npx vite build && cd ..
echo "✓ Build complete" echo "✓ Build complete"
# 2. Tar the build output (index.html + assets/) if [[ "$RUNTIME" == "docker" ]]; then
echo "▶ Packaging..." echo "▶ Docker 生产:重建镜像以包含新前端(非 tar 热更新)..."
tar czf /tmp/nexus-frontend.tar.gz -C web/app index.html assets/ ssh_cmd "cd ${DEPLOY_PATH} && sudo env NEXUS_ROOT=${DEPLOY_PATH} bash ${DEPLOY_PATH}/deploy/nexus-1panel.sh upgrade"
echo "✓ Package ready ($(du -h /tmp/nexus-frontend.tar.gz | cut -f1))" 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..."
echo "▶ Uploading to server..." scp "${SSH_OPTS[@]}" /tmp/nexus-frontend.tar.gz "${NEXUS_SSH_HOST}:/tmp/nexus-frontend.tar.gz"
scp /tmp/nexus-frontend.tar.gz nexus:/tmp/nexus-frontend.tar.gz echo "✓ Upload complete"
echo "✓ Upload complete"
# 4. Extract on server + prune orphaned legacy chunks echo "▶ Deploying on server..."
echo "▶ Deploying on server..." ssh_cmd "cd ${DEPLOY_PATH}/web/app && tar xzf /tmp/nexus-frontend.tar.gz && rm /tmp/nexus-frontend.tar.gz"
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..."
echo "▶ Pruning orphaned assets (dry-run first)..." if ! ssh_cmd "python3 ${DEPLOY_PATH}/deploy/prune_frontend_assets.py --dry-run"; then
if ! ssh nexus "python3 /www/wwwroot/api.synaglobal.vip/deploy/prune_frontend_assets.py --dry-run"; then echo "✗ Prune dry-run failed"
echo "✗ Prune dry-run failed — aborting (no files deleted)" exit 1
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 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 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") 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 nexus "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8600/app/" 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 ""
echo "═══ Verification ═══" echo "═══ Verification ═══"
echo " /health → $HEALTH" echo " /health → $HEALTH"
echo " /app/ → $SPA" echo " /app/ → $SPA"
if [ "$HEALTH" = "200" ] && [ "$SPA" = "200" ]; then if [[ "$HEALTH" == "200" || "$HEALTH" == "ok" ]] && [[ "$SPA" == "200" ]]; then
echo "✓ Deploy successful!" echo "✓ Deploy successful!"
else else
echo "✗ Verification failed — check server logs" echo "✗ Verification failed — check server logs"
+32 -15
View File
@@ -1,28 +1,44 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Run ON production server (宝塔终端 / ssh root@47.254.123.106) # Run ON production server — 自动识别 Docker / Supervisor
# Pulls latest main from Gitea and restarts Nexus. Frontend tar must be uploaded separately
# if you did not build on this machine.
# #
# Usage (on server): # Usage (on server):
# cd /www/wwwroot/api.synaglobal.vip # cd /opt/nexus && sudo bash deploy/deploy-on-server.sh
# bash deploy/deploy-on-server.sh # cd /www/wwwroot/api.synaglobal.vip && bash deploy/deploy-on-server.sh
# #
# Optional env: # Optional env:
# NEXUS_GITEA_TOKEN — if git pull needs auth # NEXUS_GITEA_TOKEN — if git pull needs auth
# SKIP_FRONTEND=1 — backend only # SKIP_FRONTEND=1 — Supervisor 模式跳过热更新前端 tar
# NEXUS_DEPLOY_PATH — 覆盖自动检测路径
set -euo pipefail 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}" cd "${DEPLOY_PATH}"
echo "═══ Nexus server-side deploy ═══" RUNTIME="$(detect_nexus_runtime "$DEPLOY_PATH")"
echo "Path: ${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" git remote set-url origin "http://admin:${NEXUS_GITEA_TOKEN}@66.154.115.8:3000/admin/Nexus.git"
fi 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..." echo "▶ git fetch + reset --hard origin/main..."
git fetch --all git fetch --all
git reset --hard origin/main git reset --hard origin/main
@@ -31,11 +47,11 @@ echo " HEAD: $(git log -1 --oneline)"
echo "▶ supervisorctl restart nexus..." echo "▶ supervisorctl restart nexus..."
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..." echo "▶ extract /tmp/nexus-frontend.tar.gz..."
tar xzf /tmp/nexus-frontend.tar.gz -C web/app tar xzf /tmp/nexus-frontend.tar.gz -C web/app
rm -f /tmp/nexus-frontend.tar.gz 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 --dry-run
python3 deploy/prune_frontend_assets.py python3 deploy/prune_frontend_assets.py
fi fi
@@ -43,13 +59,14 @@ if [ -f /tmp/nexus-frontend.tar.gz ] && [ "${SKIP_FRONTEND:-0}" != "1" ]; then
fi fi
sleep 3 sleep 3
HEALTH=$(curl -s http://127.0.0.1:8600/health || true) 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:8600/app/ || echo "000") SPA=$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:${PORT}/app/" || echo "000")
echo " /health → ${HEALTH}" echo " /health → ${HEALTH}"
echo " /app/ → ${SPA}" echo " /app/ → ${SPA}"
if [ "${HEALTH}" = "ok" ] && [ "${SPA}" = "200" ]; then if [[ "${HEALTH}" == "ok" && "${SPA}" == "200" ]]; then
echo "✓ Server deploy OK" echo "✓ Server deploy OK"
suggest_ops_cron "$DEPLOY_PATH"
else else
echo "✗ Verify failed — check: supervisorctl status nexus" >&2 echo "✗ Verify failed — check: supervisorctl status nexus" >&2
exit 1 exit 1
+74 -22
View File
@@ -1,14 +1,14 @@
#!/usr/bin/env bash #!/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: # 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 # - Key: export NEXUS_SSH_KEY=~/.ssh/id_rsa_nexus
# - Gitea push access for origin main
# #
# Usage: # Usage:
# cd "$NEXUS_ROOT" # cd "$NEXUS_ROOT"
# git add ... && git commit ... && git push origin main # if not pushed yet
# bash deploy/pre_deploy_check.sh # bash deploy/pre_deploy_check.sh
# bash deploy/deploy-production.sh # bash deploy/deploy-production.sh
@@ -19,17 +19,14 @@ cd "${ROOT}"
NEXUS_SSH_HOST="${NEXUS_SSH:-nexus}" NEXUS_SSH_HOST="${NEXUS_SSH:-nexus}"
SSH_OPTS=(-o BatchMode=yes -o ConnectTimeout=15) 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}") SSH_OPTS+=(-i "${NEXUS_SSH_KEY}")
fi fi
ssh_cmd() { ssh "${SSH_OPTS[@]}" "${NEXUS_SSH_HOST}" "$@"; } ssh_cmd() { ssh "${SSH_OPTS[@]}" "${NEXUS_SSH_HOST}" "$@"; }
scp_cmd() { scp "${SSH_OPTS[@]}" "$@"; } scp_cmd() { scp "${SSH_OPTS[@]}" "$@"; }
DEPLOY_PATH="${NEXUS_DEPLOY_PATH:-/www/wwwroot/api.synaglobal.vip}"
echo "═══ Nexus production deploy ═══" echo "═══ Nexus production deploy ═══"
echo "SSH target: ${NEXUS_SSH_HOST}" echo "SSH target: ${NEXUS_SSH_HOST}"
echo "Deploy path: ${DEPLOY_PATH}"
if ! ssh_cmd "echo SSH OK" >/dev/null 2>&1; then if ! ssh_cmd "echo SSH OK" >/dev/null 2>&1; then
echo "ERROR: Cannot SSH to ${NEXUS_SSH_HOST}" >&2 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 exit 1
fi fi
echo "▶ Backend: git pull + restart..." REMOTE_DETECT=$(ssh_cmd 'bash -s' <<'REMOTE'
ssh_cmd "cd ${DEPLOY_PATH} && git fetch --all && git reset --hard origin/main && supervisorctl restart nexus" 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..." DEPLOY_PATH="${NEXUS_DEPLOY_PATH:-$(echo "$REMOTE_DETECT" | sed -n 's/^ROOT=//p' | head -1)}"
cd frontend && npx vite build && cd .. RUNTIME="$(echo "$REMOTE_DETECT" | sed -n 's/^RUNTIME=//p' | head -1)"
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" if [[ -z "$DEPLOY_PATH" ]]; then
ssh_cmd "cd ${DEPLOY_PATH}/web/app && tar xzf /tmp/nexus-frontend.tar.gz && rm /tmp/nexus-frontend.tar.gz" DEPLOY_PATH="${NEXUS_DEPLOY_PATH:-/opt/nexus}"
if ssh_cmd "test -f ${DEPLOY_PATH}/deploy/prune_frontend_assets.py"; then fi
ssh_cmd "python3 ${DEPLOY_PATH}/deploy/prune_frontend_assets.py --dry-run" if [[ -z "$RUNTIME" || "$RUNTIME" == "none" ]]; then
ssh_cmd "python3 ${DEPLOY_PATH}/deploy/prune_frontend_assets.py" 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 fi
sleep 3 sleep 3
HEALTH=$(ssh_cmd "curl -s http://127.0.0.1:8600/health" 2>/dev/null || true) PORT="$(ssh_cmd "grep -E '^NEXUS_PUBLISH_PORT=' ${DEPLOY_PATH}/docker/.env.prod 2>/dev/null | cut -d= -f2 | tr -d '\"' || echo 8600")"
SPA=$(ssh_cmd "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 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 " /health → ${HEALTH}"
echo " /app/ → ${SPA}" echo " /app/ → ${SPA}"
if [ "${HEALTH}" = "ok" ] && [ "${SPA}" = "200" ]; then if [[ "${HEALTH}" == "ok" && "${SPA}" == "200" ]]; then
echo "✓ Deploy successful" 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 else
echo "✗ Verification failed — check supervisor logs on server" >&2 echo "✗ Verification failed — check logs on server" >&2
exit 1 exit 1
fi fi
+130
View File
@@ -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"
}
+6
View File
@@ -1206,6 +1206,12 @@ cmd_upgrade() {
rollback_compose_upgrade "$NEXUS_ROOT" || true rollback_compose_upgrade "$NEXUS_ROOT" || true
exit 1 exit 1
fi 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() { cmd_check() {
+49 -55
View File
@@ -1,16 +1,17 @@
#!/bin/bash #!/usr/bin/env bash
# ================================================================ # Nexus 6.0 — Upgrade Script(自动识别 Docker / Supervisor
# Nexus 6.0 — Upgrade Script
# #
# Usage: # sudo bash deploy/upgrade.sh
# sudo bash upgrade.sh # auto-detect deploy dir # sudo bash deploy/upgrade.sh --deploy-dir /opt/nexus
# sudo bash upgrade.sh --deploy-dir /opt/nexus # specify deploy dir
# #
# 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 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' RED='\033[0;31m'
GREEN='\033[0;32m' GREEN='\033[0;32m'
YELLOW='\033[1;33m' YELLOW='\033[1;33m'
@@ -21,98 +22,90 @@ warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*"; } error() { echo -e "${RED}[ERROR]${NC} $*"; }
DEPLOY_DIR="" DEPLOY_DIR=""
EXTRA_ARGS=()
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case $1 in case "$1" in
--deploy-dir) DEPLOY_DIR="$2"; shift 2 ;; --deploy-dir) DEPLOY_DIR="$2"; shift 2 ;;
--no-backup|--require-backup|--no-cache|--prune|--check|--dry-run)
EXTRA_ARGS+=("$1"); shift ;;
-h|--help) -h|--help)
echo "Usage: sudo bash upgrade.sh [--deploy-dir PATH]" cat <<'EOF'
exit 0 ;; 用法: sudo bash deploy/upgrade.sh [--deploy-dir PATH] [nexus-1panel 升级选项]
*) shift ;;
Docker 环境自动走 nexus-1panel.sh upgradeSupervisor 环境走 venv + supervisorctl。
EOF
exit 0
;;
*) EXTRA_ARGS+=("$1"); shift ;;
esac esac
done done
# Auto-detect deploy directory if [[ -z "$DEPLOY_DIR" ]]; then
if [ -z "$DEPLOY_DIR" ]; then DEPLOY_DIR="$(resolve_nexus_root 2>/dev/null || true)"
# 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
fi fi
if [ -z "$DEPLOY_DIR" ] || [ ! -d "$DEPLOY_DIR/server" ]; then if [[ -z "$DEPLOY_DIR" || ! -d "$DEPLOY_DIR/server" ]]; then
error "Cannot find Nexus installation. Use --deploy-dir to specify." error "找不到 Nexus 安装目录,请使用 --deploy-dir 指定"
exit 1 exit 1
fi 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" VENV_DIR="$DEPLOY_DIR/venv"
ENV_FILE="$DEPLOY_DIR/.env" ENV_FILE="$DEPLOY_DIR/.env"
echo "" echo ""
echo "==========================================" echo "=========================================="
echo " Nexus 6.0 Upgrade" echo " Nexus 6.0 Upgrade (Supervisor)"
echo "==========================================" echo "=========================================="
echo " Deploy: $DEPLOY_DIR" echo " Deploy: $DEPLOY_DIR"
echo "" echo ""
# 1. Pull latest code
info "Step 1/4: Updating source code..." info "Step 1/4: Updating source code..."
if [ -d "$DEPLOY_DIR/.git" ]; then if [[ -d "$DEPLOY_DIR/.git" ]]; then
cd "$DEPLOY_DIR" 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 || { git pull --ff-only 2>/dev/null || {
error "git pull failed. You may have local changes." error "git pull failed. Resolve conflicts: cd $DEPLOY_DIR && git status"
error "Resolve conflicts manually: cd $DEPLOY_DIR && git status"
exit 1 exit 1
} }
NEW_REV=$(git rev-parse HEAD 2>/dev/null || echo "unknown") NEW_REV="$(git rev-parse HEAD 2>/dev/null || echo unknown)"
if [ "$OLD_REV" = "$NEW_REV" ]; then if [[ "$OLD_REV" == "$NEW_REV" ]]; then
info " Already up to date (no new commits)" info " Already up to date (no new commits)"
else else
info " Updated: ${OLD_REV:0:8}..${NEW_REV:0:8}" info " Updated: ${OLD_REV:0:8}..${NEW_REV:0:8}"
fi fi
else else
warn " Not a git repo. Skip git pull (update files manually)" warn " Not a git repo. Skip git pull"
fi fi
# 2. Update Python dependencies
info "Step 2/4: Updating 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 --upgrade pip
"$VENV_DIR/bin/pip" install -q -r "$DEPLOY_DIR/requirements.txt" 2>/dev/null || { "$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 else
error " venv not found at $VENV_DIR. Run install.sh first." error " venv not found at $VENV_DIR. Run install.sh first."
exit 1 exit 1
fi fi
# 3. Restart application
info "Step 3/4: Restarting Nexus..." info "Step 3/4: Restarting Nexus..."
supervisorctl restart nexus >/dev/null 2>&1 || { 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..." info "Step 4/4: Verifying health..."
PORT="$(nexus_publish_port_for "$DEPLOY_DIR")"
# 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
HEALTH_OK=false HEALTH_OK=false
for i in $(seq 1 15); do for _ in $(seq 1 15); do
if curl -sf "http://127.0.0.1:$PORT/health" >/dev/null 2>&1; then if curl -sf "http://127.0.0.1:${PORT}/health" >/dev/null 2>&1; then
HEALTH_OK=true HEALTH_OK=true
break break
fi fi
@@ -120,11 +113,12 @@ for i in $(seq 1 15); do
done done
echo "" echo ""
if [ "$HEALTH_OK" = true ]; then if [[ "$HEALTH_OK" == true ]]; then
echo -e " ${GREEN}Upgrade complete! Nexus is healthy.${NC}" echo -e " ${GREEN}Upgrade complete! Nexus is healthy.${NC}"
suggest_ops_cron "$DEPLOY_DIR"
else else
echo -e " ${YELLOW}Health check pending. Verify manually:${NC}" 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" echo " supervisorctl status nexus"
fi fi
echo "" echo ""
@@ -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
```