Files
Nexus/deploy/deploy-production.sh
T
Nexus Agent 863e49e518 feat(ops): prod timezone probe, web/app container sync, and D-01 agent upgrade.
Unify upgrade-agent with install.sh via agent_deploy; auto-sync Git web/app after
Docker upgrade to prevent vite hash drift; extend prod_probe for Beijing TZ checks.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-09 07:12:38 +08:00

150 lines
5.8 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# 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="azureuser@20.24.218.235"
# - Key: export NEXUS_SSH_KEY=~/.ssh/id_rsa_nexus
#
# Usage:
# cd "$NEXUS_ROOT"
# bash deploy/pre_deploy_check.sh
# bash deploy/deploy-production.sh
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "${ROOT}"
SECRETS="${ROOT}/deploy/nexus-1panel.secrets.sh"
if [[ -f "$SECRETS" ]]; then
# shellcheck disable=SC1090
source "$SECRETS"
fi
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}" "$@"; }
scp_cmd() { scp "${SSH_OPTS[@]}" "$@"; }
echo "═══ Nexus production deploy ═══"
echo "SSH target: ${NEXUS_SSH_HOST}"
if ! ssh_cmd "echo SSH OK" >/dev/null 2>&1; then
echo "ERROR: Cannot SSH to ${NEXUS_SSH_HOST}" >&2
echo " Configure ~/.ssh/config (Host nexus) or set NEXUS_SSH / NEXUS_SSH_KEY" >&2
exit 1
fi
REMOTE_DETECT=$(ssh_cmd 'bash -s' <<'REMOTE'
set -euo pipefail
docker_cmd() {
if docker "$@" 2>/dev/null; then return 0; fi
sudo docker "$@" 2>/dev/null
}
compose_cmd() {
if docker compose "$@" 2>/dev/null; then return 0; fi
sudo docker compose "$@" 2>/dev/null
}
for d in /opt/nexus /www/wwwroot/api.synaglobal.vip; do
[[ -d "$d/server" ]] || continue
echo "ROOT=$d"
if [[ -f "$d/docker/.env.prod" ]] && compose_cmd 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_cmd 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" && compose_cmd "${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 [[ -f "$d/deploy/nexus-1panel.sh" ]] && command -v nx >/dev/null 2>&1; then
q=$(docker_cmd ps --format '{{.Names}}' 2>/dev/null | grep -E '^nexus-prod-nexus-' || true)
[[ -n "$q" ]] && echo RUNTIME=docker && exit 0
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
)
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
if [[ "$RUNTIME" == "docker" ]]; then
echo "▶ Sync Git web/app into container..."
ssh_cmd "sudo env NEXUS_ROOT=${DEPLOY_PATH} NEXUS_PUBLISH_PORT=\$(grep -E '^NEXUS_PUBLISH_PORT=' ${DEPLOY_PATH}/docker/.env.prod 2>/dev/null | cut -d= -f2 | tr -d '\"' || echo 8600) bash ${DEPLOY_PATH}/deploy/sync_webapp_to_container.sh" || {
echo "WARN: web/app sync failed — run sync_webapp_to_container.sh on server manually" >&2
}
fi
sleep 3
PORT="$(ssh_cmd "grep -E '^NEXUS_PUBLISH_PORT=' ${DEPLOY_PATH}/docker/.env.prod 2>/dev/null | cut -d= -f2 | tr -d '\"'" 2>/dev/null || true)"
PORT="${PORT:-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
echo "✓ Deploy successful"
if ssh_cmd "command -v crontab >/dev/null && crontab -l 2>/dev/null | grep -q nexus-health-monitor" 2>/dev/null; then
echo "✓ Ops cron (health_monitor) already installed"
else
echo "▶ Installing ops cron (health_monitor + db_backup)…"
if ssh_cmd "sudo env NEXUS_ROOT=${DEPLOY_PATH} bash ${DEPLOY_PATH}/deploy/install_ops_cron.sh" 2>/dev/null; then
echo "✓ Ops cron installed"
else
echo " 提示: 远程 cron 安装失败,可在服务器执行: sudo nx cron"
fi
fi
else
echo "✗ Verification failed — check logs on server" >&2
exit 1
fi