379 lines
11 KiB
Bash
379 lines
11 KiB
Bash
|
|
#!/usr/bin/env bash
|
|||
|
|
# Nexus NX — 一键安装 + 上帝菜单(1Panel Docker 生产栈)
|
|||
|
|
#
|
|||
|
|
# bash deploy/nx 交互菜单
|
|||
|
|
# bash deploy/nx install 同菜单「安装」
|
|||
|
|
# bash deploy/nx god 上帝菜单(运维)
|
|||
|
|
# nx 安装后链到 /usr/local/bin/nx
|
|||
|
|
#
|
|||
|
|
set -euo pipefail
|
|||
|
|
|
|||
|
|
NX_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||
|
|
# shellcheck source=./nexus-1panel.sh
|
|||
|
|
source "${NX_DIR}/nexus-1panel.sh"
|
|||
|
|
|
|||
|
|
pause_enter() {
|
|||
|
|
echo ""
|
|||
|
|
read -r -p "按 Enter 继续..."
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
clear_screen() {
|
|||
|
|
if [[ -t 1 ]]; then
|
|||
|
|
clear 2>/dev/null || true
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
is_stack_installed() {
|
|||
|
|
[[ -d "${NEXUS_ROOT}/.git" && -f "${NEXUS_ROOT}/${ENV_PROD}" ]]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
detect_runtime() {
|
|||
|
|
if is_stack_installed && docker compose version >/dev/null 2>&1; then
|
|||
|
|
local prof q
|
|||
|
|
prof="$(profile_env_file "$NEXUS_ROOT")"
|
|||
|
|
if [[ -f "$prof" && -f "$NEXUS_ROOT/$ENV_PROD" ]]; then
|
|||
|
|
q="$(cd "$NEXUS_ROOT" && docker compose -f "$COMPOSE_FILE" \
|
|||
|
|
--env-file "$ENV_PROD" --env-file "$prof" ps -q nexus 2>/dev/null || true)"
|
|||
|
|
if [[ -n "$q" ]]; then
|
|||
|
|
NX_RUNTIME="docker"
|
|||
|
|
return 0
|
|||
|
|
fi
|
|||
|
|
fi
|
|||
|
|
fi
|
|||
|
|
if command -v supervisorctl >/dev/null 2>&1 && supervisorctl status nexus >/dev/null 2>&1; then
|
|||
|
|
NX_RUNTIME="supervisor"
|
|||
|
|
return 0
|
|||
|
|
fi
|
|||
|
|
NX_RUNTIME="none"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
install_nx_cli() {
|
|||
|
|
if [[ "$(id -u)" -ne 0 ]]; then
|
|||
|
|
return 0
|
|||
|
|
fi
|
|||
|
|
ln -sf "${NX_DIR}/nx" /usr/local/bin/nx 2>/dev/null || true
|
|||
|
|
chmod +x "${NX_DIR}/nx" 2>/dev/null || true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
menu_header() {
|
|||
|
|
local title="$1"
|
|||
|
|
clear_screen
|
|||
|
|
echo ""
|
|||
|
|
echo "╔══════════════════════════════════════════════════════════╗"
|
|||
|
|
echo "║ Nexus NX — ${title}"
|
|||
|
|
echo "╠══════════════════════════════════════════════════════════╣"
|
|||
|
|
echo "║ 域名: ${NEXUS_DOMAIN} 目录: ${NEXUS_ROOT}"
|
|||
|
|
if is_stack_installed; then
|
|||
|
|
detect_runtime
|
|||
|
|
echo "║ 运行: ${NX_RUNTIME} 档位: $(cat "${NEXUS_ROOT}/${HOST_PROFILE_FILE}" 2>/dev/null || echo "${NEXUS_PROFILE}")"
|
|||
|
|
if [[ -d "${NEXUS_ROOT}/.git" ]]; then
|
|||
|
|
echo "║ 版本: $(git -C "${NEXUS_ROOT}" log -1 --oneline 2>/dev/null || echo '?')"
|
|||
|
|
fi
|
|||
|
|
else
|
|||
|
|
echo "║ 状态: 未安装"
|
|||
|
|
fi
|
|||
|
|
echo "╚══════════════════════════════════════════════════════════╝"
|
|||
|
|
echo ""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
run_install() {
|
|||
|
|
local profile="${1:-2c8g}" extra="${2:-}"
|
|||
|
|
NEXUS_PROFILE="$profile"
|
|||
|
|
SKIP_CLONE=false
|
|||
|
|
FRESH_INSTALL=false
|
|||
|
|
NO_BACKUP=false
|
|||
|
|
PRUNE_IMAGES=false
|
|||
|
|
FROM_ENV="${NEXUS_FROM_ENV}"
|
|||
|
|
case "$extra" in
|
|||
|
|
skip-clone) SKIP_CLONE=true ;;
|
|||
|
|
fresh) FRESH_INSTALL=true ;;
|
|||
|
|
from-env) FROM_ENV="${NEXUS_FROM_ENV}" ;;
|
|||
|
|
esac
|
|||
|
|
load_secrets
|
|||
|
|
cmd_install
|
|||
|
|
install_nx_cli
|
|||
|
|
pause_enter
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
menu_install() {
|
|||
|
|
while true; do
|
|||
|
|
menu_header "安装向导"
|
|||
|
|
cat <<'EOF'
|
|||
|
|
[1] 一键安装(默认 2核8G / 2c8g)
|
|||
|
|
[2] 安装 — 4核16G(4c16g)
|
|||
|
|
[3] 安装 — 1核4G(1c4g)
|
|||
|
|
[4] 自定义规格(输入 CPU 与内存 GB)
|
|||
|
|
[5] 已 clone 到 /opt/nexus,仅 pull + 启动(--skip-clone)
|
|||
|
|
[6] 全新库安装向导模式(/app/install.html)
|
|||
|
|
[7] 检查端口 / 防火墙(不安装)
|
|||
|
|
[8] 写入 Gitea 令牌(init-token)
|
|||
|
|
[9] 返回主菜单
|
|||
|
|
[0] 退出
|
|||
|
|
|
|||
|
|
EOF
|
|||
|
|
read -r -p "请选择: " choice
|
|||
|
|
case "$choice" in
|
|||
|
|
1) run_install 2c8g "" ;;
|
|||
|
|
2) run_install 4c16g "" ;;
|
|||
|
|
3) run_install 1c4g "" ;;
|
|||
|
|
4)
|
|||
|
|
read -r -p "CPU 核数: " cpus
|
|||
|
|
read -r -p "内存 GB: " mem
|
|||
|
|
CUSTOM_CPUS="$cpus"
|
|||
|
|
CUSTOM_MEM_GB="$mem"
|
|||
|
|
run_install 2c8g ""
|
|||
|
|
;;
|
|||
|
|
5) run_install 2c8g skip-clone ;;
|
|||
|
|
6) run_install 2c8g fresh ;;
|
|||
|
|
7)
|
|||
|
|
require_root
|
|||
|
|
load_secrets
|
|||
|
|
check_ports_preflight "$NEXUS_ROOT"
|
|||
|
|
if is_stack_installed; then
|
|||
|
|
check_ports_post "$NEXUS_ROOT"
|
|||
|
|
fi
|
|||
|
|
pause_enter
|
|||
|
|
;;
|
|||
|
|
8)
|
|||
|
|
read -r -p "Gitea Access Token: " tok
|
|||
|
|
cmd_init_token "$tok"
|
|||
|
|
pause_enter
|
|||
|
|
;;
|
|||
|
|
9) return 0 ;;
|
|||
|
|
0) exit 0 ;;
|
|||
|
|
*) warn "无效选项" ; sleep 1 ;;
|
|||
|
|
esac
|
|||
|
|
done
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
god_restart_nexus() {
|
|||
|
|
step "重启 Nexus(Python)..."
|
|||
|
|
if [[ "$NX_RUNTIME" == "docker" ]]; then
|
|||
|
|
compose_cmd "$NEXUS_ROOT" restart nexus
|
|||
|
|
elif [[ "$NX_RUNTIME" == "supervisor" ]]; then
|
|||
|
|
supervisorctl restart nexus
|
|||
|
|
else
|
|||
|
|
error "未检测到运行中的 Nexus"
|
|||
|
|
return 1
|
|||
|
|
fi
|
|||
|
|
info "已发送重启"
|
|||
|
|
sleep 3
|
|||
|
|
curl -sf "http://127.0.0.1:$(nexus_publish_port "$NEXUS_ROOT")/health" && info "/health → ok" || warn "健康检查未通过,请查看日志"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
god_restart_stack() {
|
|||
|
|
step "重启全部 Compose 服务..."
|
|||
|
|
compose_cmd "$NEXUS_ROOT" restart
|
|||
|
|
sleep 5
|
|||
|
|
verify_health "$NEXUS_ROOT" "重启" || true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
god_stop_stack() {
|
|||
|
|
warn "将停止 MySQL / Redis / Nexus 全部容器"
|
|||
|
|
read -r -p "确认? [y/N]: " c
|
|||
|
|
[[ "$c" == "y" || "$c" == "Y" ]] || return 0
|
|||
|
|
compose_cmd "$NEXUS_ROOT" stop
|
|||
|
|
info "已停止"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
god_start_stack() {
|
|||
|
|
compose_cmd "$NEXUS_ROOT" up -d
|
|||
|
|
verify_health "$NEXUS_ROOT" "启动" || true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
god_logs() {
|
|||
|
|
local svc="${1:-nexus}"
|
|||
|
|
echo ""
|
|||
|
|
read -r -p "跟踪日志行数 [80]: " n
|
|||
|
|
n="${n:-80}"
|
|||
|
|
compose_cmd "$NEXUS_ROOT" logs --tail="$n" -f "$svc"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
god_status() {
|
|||
|
|
if [[ "$NX_RUNTIME" == "docker" ]]; then
|
|||
|
|
compose_cmd "$NEXUS_ROOT" ps
|
|||
|
|
elif [[ "$NX_RUNTIME" == "supervisor" ]]; then
|
|||
|
|
supervisorctl status nexus
|
|||
|
|
fi
|
|||
|
|
echo ""
|
|||
|
|
local port h
|
|||
|
|
port="$(nexus_publish_port "$NEXUS_ROOT")"
|
|||
|
|
h=$(curl -sf "http://127.0.0.1:${port}/health" 2>/dev/null || echo "fail")
|
|||
|
|
info "/health → ${h}"
|
|||
|
|
curl -s -o /dev/null -w " /app/ HTTP %{http_code}\n" "http://127.0.0.1:${port}/app/" 2>/dev/null || true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
god_backup_now() {
|
|||
|
|
NO_BACKUP=false
|
|||
|
|
backup_mysql "$NEXUS_ROOT"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
god_upgrade_interactive() {
|
|||
|
|
PRUNE_IMAGES=false
|
|||
|
|
NO_BACKUP=false
|
|||
|
|
read -r -p "跳过 MySQL 备份? [y/N]: " nb
|
|||
|
|
[[ "$nb" == "y" || "$nb" == "Y" ]] && NO_BACKUP=true
|
|||
|
|
read -r -p "升级后清理悬空镜像? [y/N]: " pr
|
|||
|
|
[[ "$pr" == "y" || "$pr" == "Y" ]] && PRUNE_IMAGES=true
|
|||
|
|
cmd_upgrade
|
|||
|
|
pause_enter
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
menu_god() {
|
|||
|
|
if ! is_stack_installed; then
|
|||
|
|
warn "尚未安装,请先使用安装向导"
|
|||
|
|
pause_enter
|
|||
|
|
return 0
|
|||
|
|
fi
|
|||
|
|
require_root
|
|||
|
|
load_secrets
|
|||
|
|
load_saved_profile "$NEXUS_ROOT"
|
|||
|
|
detect_runtime
|
|||
|
|
|
|||
|
|
while true; do
|
|||
|
|
menu_header "上帝菜单 · 运维"
|
|||
|
|
cat <<EOF
|
|||
|
|
── 服务 ──
|
|||
|
|
[1] 重启 Nexus(Python 应用)
|
|||
|
|
[2] 重启全部容器(mysql + redis + nexus)
|
|||
|
|
[3] 启动 Compose 栈
|
|||
|
|
[4] 停止 Compose 栈
|
|||
|
|
[5] 重建 Nexus 镜像并启动(up -d --build nexus)
|
|||
|
|
|
|||
|
|
── 观测 ──
|
|||
|
|
[6] 状态 + 健康检查
|
|||
|
|
[7] 查看 Nexus 日志(跟踪)
|
|||
|
|
[8] 查看 MySQL / Redis 日志
|
|||
|
|
[9] 端口 / 防火墙检查
|
|||
|
|
|
|||
|
|
── 发布 ──
|
|||
|
|
[a] 检查 Git 更新
|
|||
|
|
[b] 一键升级(备份 + pull + 重建)
|
|||
|
|
[c] 立即备份 MySQL
|
|||
|
|
|
|||
|
|
── 其他 ──
|
|||
|
|
[d] 进入 Nexus 容器 shell
|
|||
|
|
[e] 打开 1Panel 反代说明
|
|||
|
|
[0] 返回主菜单
|
|||
|
|
|
|||
|
|
EOF
|
|||
|
|
read -r -p "请选择: " choice
|
|||
|
|
case "$choice" in
|
|||
|
|
1) god_restart_nexus; pause_enter ;;
|
|||
|
|
2) god_restart_stack; pause_enter ;;
|
|||
|
|
3) god_start_stack; pause_enter ;;
|
|||
|
|
4) god_stop_stack; pause_enter ;;
|
|||
|
|
5)
|
|||
|
|
compose_cmd "$NEXUS_ROOT" up -d --build nexus
|
|||
|
|
verify_health "$NEXUS_ROOT" "重建" || true
|
|||
|
|
pause_enter
|
|||
|
|
;;
|
|||
|
|
6) god_status; pause_enter ;;
|
|||
|
|
7) god_logs nexus ;;
|
|||
|
|
8)
|
|||
|
|
echo "1) mysql 2) redis"
|
|||
|
|
read -r -p "选: " s
|
|||
|
|
[[ "$s" == "1" ]] && god_logs mysql || god_logs redis
|
|||
|
|
;;
|
|||
|
|
9)
|
|||
|
|
check_ports_preflight "$NEXUS_ROOT"
|
|||
|
|
check_ports_post "$NEXUS_ROOT"
|
|||
|
|
pause_enter
|
|||
|
|
;;
|
|||
|
|
a|A)
|
|||
|
|
cmd_check
|
|||
|
|
pause_enter
|
|||
|
|
;;
|
|||
|
|
b|B) god_upgrade_interactive ;;
|
|||
|
|
c|C) god_backup_now; pause_enter ;;
|
|||
|
|
d)
|
|||
|
|
compose_cmd "$NEXUS_ROOT" exec nexus bash || compose_cmd "$NEXUS_ROOT" exec nexus sh
|
|||
|
|
;;
|
|||
|
|
e)
|
|||
|
|
info "1Panel → 网站 → 创建站点 ${NEXUS_DOMAIN}"
|
|||
|
|
info "反向代理: http://127.0.0.1:$(nexus_publish_port "$NEXUS_ROOT")"
|
|||
|
|
info "示例配置: ${NEXUS_ROOT}/deploy/1panel/openresty-nexus.conf.example"
|
|||
|
|
pause_enter
|
|||
|
|
;;
|
|||
|
|
0) return 0 ;;
|
|||
|
|
*) warn "无效选项"; sleep 1 ;;
|
|||
|
|
esac
|
|||
|
|
done
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
menu_main() {
|
|||
|
|
load_secrets
|
|||
|
|
while true; do
|
|||
|
|
menu_header "主菜单"
|
|||
|
|
if is_stack_installed; then
|
|||
|
|
echo " 提示: 安装完成后请用 [2] 上帝菜单 重启 Python / 升级 / 看日志"
|
|||
|
|
echo ""
|
|||
|
|
fi
|
|||
|
|
cat <<'EOF'
|
|||
|
|
[1] 安装向导(新机 / 迁机)
|
|||
|
|
[2] 上帝菜单(重启 Python · 升级 · 日志 · 备份)
|
|||
|
|
[3] 快速健康检查
|
|||
|
|
[0] 退出
|
|||
|
|
|
|||
|
|
EOF
|
|||
|
|
read -r -p "请选择: " choice
|
|||
|
|
case "$choice" in
|
|||
|
|
1) menu_install ;;
|
|||
|
|
2) menu_god ;;
|
|||
|
|
3)
|
|||
|
|
require_root
|
|||
|
|
if is_stack_installed; then
|
|||
|
|
god_status
|
|||
|
|
else
|
|||
|
|
check_ports_preflight "$NEXUS_ROOT"
|
|||
|
|
fi
|
|||
|
|
pause_enter
|
|||
|
|
;;
|
|||
|
|
0) exit 0 ;;
|
|||
|
|
*) warn "无效选项"; sleep 1 ;;
|
|||
|
|
esac
|
|||
|
|
done
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
nx_main() {
|
|||
|
|
local sub="${1:-}"
|
|||
|
|
load_secrets
|
|||
|
|
case "$sub" in
|
|||
|
|
""|menu) menu_main ;;
|
|||
|
|
install) menu_install ;;
|
|||
|
|
god|ops|admin) menu_god ;;
|
|||
|
|
install-auto|auto)
|
|||
|
|
require_root
|
|||
|
|
if is_stack_installed; then
|
|||
|
|
run_install "${NEXUS_PROFILE:-2c8g}" skip-clone
|
|||
|
|
else
|
|||
|
|
run_install "${NEXUS_PROFILE:-2c8g}" ""
|
|||
|
|
fi
|
|||
|
|
;;
|
|||
|
|
health)
|
|||
|
|
require_root
|
|||
|
|
is_stack_installed && god_status || check_ports_preflight "$NEXUS_ROOT"
|
|||
|
|
;;
|
|||
|
|
-h|--help)
|
|||
|
|
cat <<EOF
|
|||
|
|
用法: nx [子命令]
|
|||
|
|
|
|||
|
|
(无) 交互主菜单
|
|||
|
|
install 安装向导
|
|||
|
|
install-auto 非交互一键安装(2c8g)
|
|||
|
|
god 上帝菜单(重启/升级/日志)
|
|||
|
|
health 健康检查
|
|||
|
|
|
|||
|
|
底层仍可使用: bash deploy/nexus-1panel.sh install|upgrade|check|ports
|
|||
|
|
EOF
|
|||
|
|
;;
|
|||
|
|
*)
|
|||
|
|
# 兼容 nexus-1panel.sh 子命令
|
|||
|
|
main "$@"
|
|||
|
|
;;
|
|||
|
|
esac
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
chmod +x "${NX_DIR}/nx" 2>/dev/null || true
|
|||
|
|
nx_main "$@"
|