From 58c9f36a75ff8265462067cf7a95d9ac5caa7b18 Mon Sep 17 00:00:00 2001 From: dekun Date: Sun, 12 Jul 2026 12:23:29 +0800 Subject: [PATCH] Add interactive deploy manager with install, uninstall, and update menus. Provides curl-friendly manage.sh so production servers can bootstrap without a prior clone, then configure API and risk settings in the browser. Co-authored-by: Cursor --- README.md | 8 +- deploy/README.md | 121 +++++++++++---- deploy/lib/common.sh | 318 ++++++++++++++++++++++++++++++++++++++++ deploy/lib/install.sh | 105 +++++++++++++ deploy/lib/uninstall.sh | 73 +++++++++ deploy/lib/update.sh | 82 +++++++++++ deploy/manage.sh | 129 ++++++++++++++++ docs/ubuntu-server.md | 15 +- 8 files changed, 815 insertions(+), 36 deletions(-) create mode 100644 deploy/lib/common.sh create mode 100644 deploy/lib/install.sh create mode 100644 deploy/lib/uninstall.sh create mode 100644 deploy/lib/update.sh create mode 100644 deploy/manage.sh diff --git a/README.md b/README.md index a6abada..40dab38 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,17 @@ | 进程 | **PM2**(唯一推荐的常驻方式) | **环境详解**(Python 3.10+,Node,PM2 安装与启动顺序):**[docs/ubuntu-server.md](./docs/ubuntu-server.md)** -**一键 venv**:`bash deploy/setup_env.sh` → **[deploy/README.md](./deploy/README.md)** +**一键部署管理器**:`curl -fsSL .../deploy/manage.sh | bash` → **[deploy/README.md](./deploy/README.md)** ```bash +# 新服务器(推荐) +curl -fsSL https://git.bz121.com/dekun/crypto_monitor/raw/branch/main/deploy/manage.sh | bash + +# 或手动 clone cd /opt git clone https://git.bz121.com/dekun/crypto_monitor.git crypto_monitor cd /opt/crypto_monitor -bash deploy/setup_env.sh --install-system-deps +bash deploy/manage.sh ``` 配置与运维脚本: **[docs/env-sync-scripts.md](./docs/env-sync-scripts.md)** · **[备份与恢复.md](./备份与恢复.md)** diff --git a/deploy/README.md b/deploy/README.md index 9792cd1..6baec07 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -1,51 +1,117 @@ # 环境一键部署(Ubuntu / root /opt) -在 **`/opt/crypto_monitor`** 下以 **root** 为各子项目创建 Python **`.venv`**,安装依赖,从 `.env.example` 生成 `.env`(不覆盖已有),并可选安装 **PM2**. +在 **`/opt/crypto_monitor`** 下以 **root** 部署三所 Flask + 中控 hub/agent,使用 **PM2** 常驻. -完整系统要求(Python / Node / PM2 版本,启动顺序)见 **[docs/ubuntu-server.md](../docs/ubuntu-server.md)**. +完整系统要求见 **[docs/ubuntu-server.md](../docs/ubuntu-server.md)**. + +--- + +## 一键部署管理器(推荐) + +新服务器**无需先 clone**,一条命令进入菜单: + +```bash +curl -fsSL https://git.bz121.com/dekun/crypto_monitor/raw/branch/main/deploy/manage.sh | bash +``` + +已安装机器: + +```bash +bash /opt/crypto_monitor/deploy/manage.sh +``` + +### 菜单 + +| 选项 | 功能 | +|------|------| +| **1) 一键部署** | 装系统依赖 + Node/PM2 + venv + 自动生成密钥 + 启动 7 进程 | +| **2) 一键卸载** | 备份 `.env` / `hub_settings.json` → 停 PM2 → 移走目录 | +| **3) 更新** | 快速更新 / 依赖更新 / 深度重装 | +| **0) 退出** | | + +### 部署完成后 + +脚本自动验收(PM2 7 进程 + 页面可访问),并提示: + +- 登录账号: **admin** +- 登录密码: **admin123** +- 浏览器配置: 各所 **env 配置**(API,风控) + 中控 **系统设置** + +**无需 SSH 编辑 `.env` 填 API**;密钥由 `bootstrap_deploy_secrets.py` 自动生成. + +| 地址 | 端口 | +|------|------| +| 中控 | 5100 | +| Binance | 5001 | +| Gate | 5000 | +| OKX | 5004 | + +agent 默认 `127.0.0.1:15200/15201/15202`,由代码内置,一般无需改. + +--- + +## 脚本结构 + +``` +deploy/ +├── manage.sh # 入口(自举 + 菜单) +├── lib/ +│ ├── common.sh # 公共函数,验收 +│ ├── install.sh # 一键部署 +│ ├── uninstall.sh # 一键卸载 +│ └── update.sh # 更新子菜单 +├── setup_env.sh # venv + 依赖(被 install 调用) +├── pm2_start_all.sh # 启动 7 进程 +├── pull_and_restart.sh # 快速更新(被 update 调用) +└── reinstall.sh # 深度重装(被 update 调用) +``` --- ## 前置条件 - **Ubuntu 22.04 / 24.04**,用户 **root** -- 已安装 **git**,仓库位于 **`/opt/crypto_monitor`** - -```bash -apt update -apt install -y python3 python3-pip python3-venv curl git ca-certificates -# Node 20 + PM2 见 docs/ubuntu-server.md §3 -``` +- 能 `git clone` 仓库到 `/opt/crypto_monitor` --- -## 一键执行 +## 分步安装(仍可用) + +若不使用 `manage.sh`,可手动: ```bash +cd /opt +git clone https://git.bz121.com/dekun/crypto_monitor.git crypto_monitor cd /opt/crypto_monitor bash deploy/setup_env.sh --install-system-deps +bash deploy/pm2_start_all.sh +pm2 save && pm2 startup ``` -常用参数: +`setup_env.sh` 常用参数: ```bash bash deploy/setup_env.sh --only binance,gate # 仅部分子项目 -bash deploy/setup_env.sh --recreate-venv # 重建虚拟环境 -bash deploy/setup_env.sh --skip-pm2 # 不尝试安装 pm2 -bash deploy/setup_env.sh --skip-env-copy # 不复制 .env.example +bash deploy/setup_env.sh --recreate-venv # 重建虚拟环境 +bash deploy/setup_env.sh --skip-pm2 # 不尝试安装 pm2 +bash deploy/setup_env.sh --skip-env-copy # 不复制 .env.example ``` -**整目录重装**(保留 `.env`,清库,去脏 PM2)见 **[reinstall-plan-b.md](./reinstall-plan-b.md)**,执行 `bash deploy/reinstall.sh`.与 `setup_env.sh` 独立,不影响首次一键安装. +**整目录重装**(保留 `.env`,清库)见 **[reinstall-plan-b.md](./reinstall-plan-b.md)**: + +```bash +bash deploy/reinstall.sh --yes +``` 若在其它环境编辑过脚本后报 `pipefail` 错误,先转 LF: ```bash -sed -i 's/\r$//' deploy/setup_env.sh +sed -i 's/\r$//' deploy/manage.sh deploy/lib/*.sh ``` --- -## 脚本会做什么 +## setup_env.sh 会做什么 | 步骤 | 说明 | |------|------| @@ -59,21 +125,14 @@ sed -i 's/\r$//' deploy/setup_env.sh --- -## 部署之后 +## 环境变量(可选) -1. 编辑各子目录 **`.env`**(交易所 API,企业微信等;**AI 请在中控系统设置 → AI 配置**). -2. **仅用 PM2 常驻**(见 [docs/ubuntu-server.md](../docs/ubuntu-server.md) §3): - - ```bash - cd /opt/crypto_monitor/crypto_monitor_binance && pm2 start ecosystem.config.cjs - # … 其余三所 … - cd /opt/crypto_monitor/manual_trading_hub && pm2 start ecosystem.config.cjs - pm2 save - ``` - - 或一条命令:`bash deploy/pm2_start_all.sh` - -3. 三所 `.env` 同步脚本见 **[docs/env-sync-scripts.md](../docs/env-sync-scripts.md)**. +```bash +INSTALL_ROOT=/opt/crypto_monitor +GIT_URL=https://git.bz121.com/dekun/crypto_monitor.git +GIT_BRANCH=main +BACKUP_ROOT=/root/backups +``` --- diff --git a/deploy/lib/common.sh b/deploy/lib/common.sh new file mode 100644 index 0000000..e8a6ca2 --- /dev/null +++ b/deploy/lib/common.sh @@ -0,0 +1,318 @@ +#!/usr/bin/env bash +# deploy/lib/common.sh — 部署管理器公共函数 +set -e +set -u +if [ -n "${BASH_VERSION:-}" ]; then + set -o pipefail +fi + +INSTALL_ROOT="${INSTALL_ROOT:-/opt/crypto_monitor}" +GIT_URL="${GIT_URL:-https://git.bz121.com/dekun/crypto_monitor.git}" +GIT_BRANCH="${GIT_BRANCH:-main}" +BACKUP_ROOT="${BACKUP_ROOT:-/root/backups}" +TZ_NAME="${CM_TZ:-Asia/Shanghai}" +NODE_MAJOR="${NODE_MAJOR:-20}" + +LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DEPLOY_DIR="$(cd "${LIB_DIR}/.." && pwd)" +REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)" + +PM2_APPS=( + crypto_binance + crypto_gate + crypto_okx + manual-trading-hub + manual-agent-binance + manual-agent-okx + manual-agent-gate +) + +CONFIG_PATHS=( + crypto_monitor_binance/.env + crypto_monitor_okx/.env + crypto_monitor_gate/.env + manual_trading_hub/.env + manual_trading_hub/hub_settings.json +) + +INSTANCE_DIRS=( + crypto_monitor_binance + crypto_monitor_gate + crypto_monitor_okx + manual_trading_hub +) + +log() { printf '[%s] %s\n' "$(TZ="${TZ_NAME}" date '+%Y-%m-%d %H:%M:%S')" "$*"; } +step() { echo ""; log "==> $*"; } + +die() { + echo "错误: $*" >&2 + exit 1 +} + +require_root() { + if [[ "$(id -u)" -ne 0 ]]; then + die "请使用 root 执行(推荐: sudo -i 后运行)" + fi +} + +require_ubuntu() { + if [[ ! -f /etc/os-release ]]; then + log "警告: 未检测到 /etc/os-release,跳过 Ubuntu 版本检查" + return 0 + fi + # shellcheck source=/dev/null + source /etc/os-release + if [[ "${ID:-}" != "ubuntu" ]]; then + log "警告: 当前系统为 ${ID:-unknown},官方仅测试 Ubuntu 22.04/24.04" + return 0 + fi + local ver="${VERSION_ID:-}" + if [[ "${ver}" != "22.04" && "${ver}" != "24.04" ]]; then + log "警告: Ubuntu ${ver} 未在文档中明确测试,继续执行" + fi +} + +detect_server_ip() { + local ip="" + if command -v hostname >/dev/null 2>&1; then + ip="$(hostname -I 2>/dev/null | awk '{print $1}')" + fi + if [[ -z "${ip}" ]]; then + ip="127.0.0.1" + fi + echo "${ip}" +} + +confirm_yes() { + local msg="$1" + local ans="" + read -r -p "${msg} [y/N] " ans + [[ "${ans}" == [yY] || "${ans}" == [yY][eE][sS] ]] +} + +confirm_uninstall() { + local ans="" + echo "此操作将停止全部 PM2 进程并移走安装目录." + read -r -p "输入 UNINSTALL 确认卸载: " ans + [[ "${ans}" == "UNINSTALL" ]] +} + +repo_ready() { + [[ -f "${1}/deploy/setup_env.sh" && -f "${1}/deploy/manage.sh" ]] +} + +resolve_repo_root() { + if repo_ready "${INSTALL_ROOT}"; then + echo "${INSTALL_ROOT}" + return 0 + fi + if repo_ready "${REPO_ROOT}"; then + echo "${REPO_ROOT}" + return 0 + fi + return 1 +} + +install_log_file() { + local stamp + stamp="$(TZ="${TZ_NAME}" date +%Y%m%d-%H%M%S)" + mkdir -p "${BACKUP_ROOT}/deploy-logs" + echo "${BACKUP_ROOT}/deploy-logs/manage-${stamp}.log" +} + +backup_configs_to() { + local src_root="$1" + local dest="$2" + mkdir -p "${dest}" + local rel copied=0 + for rel in "${CONFIG_PATHS[@]}"; do + local src="${src_root}/${rel}" + if [[ -f "${src}" ]]; then + mkdir -p "${dest}/$(dirname "${rel}")" + cp -a "${src}" "${dest}/${rel}" + log "backup ${rel}" + copied=$((copied + 1)) + fi + done + if [[ "${copied}" -eq 0 ]]; then + log "提示: 未找到可备份的配置文件" + fi +} + +install_system_packages() { + step "安装系统依赖" + if ! command -v apt-get >/dev/null 2>&1; then + die "未检测到 apt-get,请手动安装 python3-venv git curl" + fi + export DEBIAN_FRONTEND=noninteractive + apt-get update -qq + apt-get install -y python3 python3-pip python3-venv curl git ca-certificates + local pyver="" + if command -v python3 >/dev/null 2>&1; then + pyver="$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')" + apt-get install -y "python${pyver}-venv" 2>/dev/null || apt-get install -y python3-venv + fi +} + +install_node_pm2() { + step "检查 Node.js 与 PM2" + if command -v pm2 >/dev/null 2>&1; then + log "PM2 已安装: $(pm2 -v)" + return 0 + fi + if ! command -v node >/dev/null 2>&1; then + log "安装 Node.js ${NODE_MAJOR}.x ..." + curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" | bash - + apt-get install -y nodejs + fi + log "安装 PM2 ..." + npm install -g pm2 + log "PM2: $(pm2 -v)" +} + +install_backup_cron_all() { + step "安装三所每日备份 cron" + local dir + for dir in crypto_monitor_binance crypto_monitor_gate crypto_monitor_okx; do + local inst="${REPO_ROOT}/${dir}/scripts/install_backup_cron.sh" + if [[ -f "${inst}" ]]; then + chmod +x "${inst}" + bash "${inst}" || log "警告: ${dir} cron 安装失败" + fi + done +} + +remove_backup_cron_all() { + step "移除三所备份 cron" + local tmp removed=0 + tmp="$(mktemp)" + if ! crontab -l 2>/dev/null >"${tmp}"; then + rm -f "${tmp}" + return 0 + fi + local filtered + filtered="$(grep -vF "backup_data.sh" "${tmp}" || true)" + if [[ "${filtered}" != "$(cat "${tmp}")" ]]; then + printf '%s\n' "${filtered}" | awk ' + BEGIN { tz = 0 } + /^CRON_TZ=Asia\/Shanghai$/ { + if (tz++) next + } + { print } + ' | crontab - + removed=1 + fi + rm -f "${tmp}" + if [[ "${removed}" -eq 1 ]]; then + log "已移除 backup_data.sh 相关 cron" + fi +} + +pm2_save_startup() { + step "PM2 save & startup" + pm2 save 2>/dev/null || true + if pm2 startup systemd -u root --hp /root 2>/dev/null | grep -q "sudo"; then + pm2 startup systemd -u root --hp /root 2>/dev/null | grep "^sudo" | bash || true + else + pm2 startup 2>/dev/null || true + fi +} + +pm2_count_online() { + local name online=0 + if ! command -v pm2 >/dev/null 2>&1; then + echo "0" + return 0 + fi + for name in "${PM2_APPS[@]}"; do + if pm2 pid "${name}" >/dev/null 2>&1; then + online=$((online + 1)) + fi + done + echo "${online}" +} + +is_deployed() { + local root="$1" + [[ -x "${root}/crypto_monitor_binance/.venv/bin/python" ]] \ + || [[ -x "${root}/manual_trading_hub/.venv/bin/python" ]] +} + +check_http() { + local url="$1" + local code + code="$(curl -sS -o /dev/null -w '%{http_code}' --connect-timeout 5 "${url}" 2>/dev/null || echo "000")" + [[ "${code}" == "200" || "${code}" == "302" || "${code}" == "301" ]] +} + +verify_deployment() { + local ip="${1:-$(detect_server_ip)}" + local ok=1 + local online total + + step "部署验收" + total="${#PM2_APPS[@]}" + online="$(pm2_count_online)" + if [[ "${online}" -eq "${total}" ]]; then + echo " [✓] PM2 进程 ${online}/${total} online" + else + echo " [✗] PM2 进程 ${online}/${total} online" + ok=0 + pm2 list 2>/dev/null || true + fi + + local checks=( + "中控:http://127.0.0.1:5100/" + "Binance:http://127.0.0.1:5001/" + "Gate:http://127.0.0.1:5000/" + "OKX:http://127.0.0.1:5004/" + ) + local item label url + for item in "${checks[@]}"; do + label="${item%%:*}" + url="${item#*:}" + if check_http "${url}"; then + echo " [✓] ${label} 可访问" + else + echo " [✗] ${label} 不可访问 (${url})" + ok=0 + fi + done + + if [[ "${ok}" -eq 1 ]]; then + echo "" + log "验收通过: 进程都在 + 页面可打开" + return 0 + fi + echo "" + log "验收未完全通过,可执行 pm2 logs <进程名> --lines 30 排查" + return 1 +} + +print_post_install_guide() { + local ip="${1:-$(detect_server_ip)}" + cat </dev/null 2>&1; then + bash "${REPO_ROOT}/deploy/pm2_start_all.sh" 2>/dev/null || pm2 restart all 2>/dev/null || true + pm2_save_startup + fi + verify_deployment "$(detect_server_ip)" || true + print_post_install_guide "$(detect_server_ip)" + ;; + c|C) + install_deep + ;; + *) + log "已取消" + ;; + esac +} + +main_install() { + require_root + require_ubuntu + + if repo_ready "${INSTALL_ROOT}"; then + REPO_ROOT="${INSTALL_ROOT}" + elif repo_ready "${REPO_ROOT}"; then + : + else + REPO_ROOT="" + fi + + if [[ -n "${REPO_ROOT}" ]] && is_deployed "${REPO_ROOT}"; then + handle_existing_install + return 0 + fi + + if [[ -z "${REPO_ROOT}" ]]; then + install_system_packages + install_node_pm2 + install_fresh + REPO_ROOT="${INSTALL_ROOT}" + else + install_system_packages + install_node_pm2 + fi + + run_install_pipeline +} + +main_install "$@" diff --git a/deploy/lib/uninstall.sh b/deploy/lib/uninstall.sh new file mode 100644 index 0000000..8d86aee --- /dev/null +++ b/deploy/lib/uninstall.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +# deploy/lib/uninstall.sh — 一键卸载 +set -e +set -u +if [ -n "${BASH_VERSION:-}" ]; then + set -o pipefail +fi + +LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=common.sh +source "${LIB_DIR}/common.sh" + +main_uninstall() { + require_root + + local root="" + if ! root="$(resolve_repo_root)"; then + if [[ -d "${INSTALL_ROOT}" ]]; then + root="${INSTALL_ROOT}" + else + die "未找到安装目录 ${INSTALL_ROOT}" + fi + fi + REPO_ROOT="${root}" + + if ! confirm_uninstall; then + log "已取消卸载" + return 0 + fi + + local stamp backup_dir removed_dir + stamp="$(TZ="${TZ_NAME}" date +%Y%m%d-%H%M%S)" + backup_dir="${BACKUP_ROOT}/pre-uninstall-${stamp}" + removed_dir="${INSTALL_ROOT}.removed.${stamp}" + + step "备份配置到 ${backup_dir}" + backup_configs_to "${REPO_ROOT}" "${backup_dir}" + { + echo "created_at=${stamp}" + echo "install_root=${INSTALL_ROOT}" + echo "removed_dir=${removed_dir}" + } >"${backup_dir}/uninstall.manifest" + + step "停止并清空 PM2" + if command -v pm2 >/dev/null 2>&1; then + pm2 stop all 2>/dev/null || true + pm2 delete all 2>/dev/null || true + pm2 save 2>/dev/null || true + else + log "未安装 pm2,跳过" + fi + + remove_backup_cron_all + + step "移走安装目录" + if [[ -d "${INSTALL_ROOT}" ]]; then + mv "${INSTALL_ROOT}" "${removed_dir}" + log "已移动: ${INSTALL_ROOT} -> ${removed_dir}" + else + log "安装目录不存在,跳过" + fi + + echo "" + echo "卸载完成." + echo " 配置备份: ${backup_dir}" + echo " 旧目录: ${removed_dir} (确认无误后可手动删除)" + echo "" + echo "回滚示例:" + echo " mv ${removed_dir} ${INSTALL_ROOT}" + echo " bash ${INSTALL_ROOT}/deploy/manage.sh # 选 1 修复环境" +} + +main_uninstall "$@" diff --git a/deploy/lib/update.sh b/deploy/lib/update.sh new file mode 100644 index 0000000..cb5adcd --- /dev/null +++ b/deploy/lib/update.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +# deploy/lib/update.sh — 更新 +set -e +set -u +if [ -n "${BASH_VERSION:-}" ]; then + set -o pipefail +fi + +LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=common.sh +source "${LIB_DIR}/common.sh" + +require_installed() { + if ! repo_ready "${REPO_ROOT}"; then + die "未找到安装,请先执行「1) 一键部署」" + fi +} + +update_quick() { + step "快速更新" + bash "${REPO_ROOT}/deploy/pull_and_restart.sh" + verify_deployment "$(detect_server_ip)" || true +} + +update_deps() { + step "依赖更新" + local dir req + for dir in crypto_monitor_binance crypto_monitor_gate crypto_monitor_okx; do + local proj="${REPO_ROOT}/${dir}" + if [[ -x "${proj}/.venv/bin/pip" ]]; then + log "pip install ${dir}" + "${proj}/.venv/bin/pip" install -r "${REPO_ROOT}/requirements.txt" -q + fi + done + local hub="${REPO_ROOT}/manual_trading_hub" + if [[ -x "${hub}/.venv/bin/pip" && -f "${hub}/requirements.txt" ]]; then + log "pip install manual_trading_hub" + "${hub}/.venv/bin/pip" install -r "${hub}/requirements.txt" -q + fi + update_quick +} + +update_deep() { + step "深度重装" + if ! confirm_yes "深度重装将清库并保留 .env,确认继续?"; then + log "已取消" + return 0 + fi + bash "${REPO_ROOT}/deploy/reinstall.sh" --yes + verify_deployment "$(detect_server_ip)" || true +} + +show_update_menu() { + while true; do + echo "" + echo " 更新选项:" + echo " 3-1) 快速更新(git pull + pm2 restart)" + echo " 3-2) 依赖更新(含 pip install)" + echo " 3-3) 深度重装(保留 .env,清库)" + echo " 0) 返回主菜单" + local choice="" + read -r -p "请选择 [0/3-1/3-2/3-3]: " choice + case "${choice}" in + 3-1|31|1) update_quick; break ;; + 3-2|32|2) update_deps; break ;; + 3-3|33|3) update_deep; break ;; + 0) break ;; + *) echo "无效选项" ;; + esac + done +} + +main_update() { + require_root + if ! REPO_ROOT="$(resolve_repo_root)"; then + die "未找到安装目录 ${INSTALL_ROOT},请先执行「1) 一键部署」" + fi + require_installed + show_update_menu +} + +main_update "$@" diff --git a/deploy/manage.sh b/deploy/manage.sh new file mode 100644 index 0000000..981f8f8 --- /dev/null +++ b/deploy/manage.sh @@ -0,0 +1,129 @@ +#!/usr/bin/env bash +# crypto_monitor 部署管理器 — 一键部署 / 卸载 / 更新 +# +# 新服务器(免克隆): +# curl -fsSL https://git.bz121.com/dekun/crypto_monitor/raw/branch/main/deploy/manage.sh | bash +# +# 已安装: +# bash /opt/crypto_monitor/deploy/manage.sh +# +set -e +set -u +if [ -n "${BASH_VERSION:-}" ]; then + set -o pipefail +fi + +INSTALL_ROOT="${INSTALL_ROOT:-/opt/crypto_monitor}" +GIT_URL="${GIT_URL:-https://git.bz121.com/dekun/crypto_monitor.git}" +GIT_BRANCH="${GIT_BRANCH:-main}" + +SCRIPT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")" +DEPLOY_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)" +LIB_DIR="${DEPLOY_DIR}/lib" + +repo_ready() { + [[ -f "${1}/deploy/setup_env.sh" && -f "${1}/deploy/manage.sh" ]] +} + +bootstrap_repo() { + if repo_ready "${INSTALL_ROOT}"; then + REPO_ROOT="${INSTALL_ROOT}" + DEPLOY_DIR="${REPO_ROOT}/deploy" + LIB_DIR="${DEPLOY_DIR}/lib" + return 0 + fi + if repo_ready "${REPO_ROOT}"; then + return 0 + fi + + echo "crypto_monitor 部署管理器 — 首次自举" + echo "将克隆到: ${INSTALL_ROOT}" + if [[ "$(id -u)" -ne 0 ]]; then + echo "错误: 请使用 root 执行" >&2 + exit 1 + fi + if ! command -v git >/dev/null 2>&1; then + if command -v apt-get >/dev/null 2>&1; then + export DEBIAN_FRONTEND=noninteractive + apt-get update -qq + apt-get install -y git ca-certificates curl + else + echo "错误: 未找到 git" >&2 + exit 1 + fi + fi + if [[ -d "${INSTALL_ROOT}" ]]; then + echo "错误: ${INSTALL_ROOT} 已存在但不是有效仓库" >&2 + echo "请手动处理后再运行,或设置 INSTALL_ROOT 指向其它路径" >&2 + exit 1 + fi + mkdir -p "$(dirname "${INSTALL_ROOT}")" + git clone -b "${GIT_BRANCH}" "${GIT_URL}" "${INSTALL_ROOT}" + exec bash "${INSTALL_ROOT}/deploy/manage.sh" "$@" +} + +show_banner() { + local ip path + path="${INSTALL_ROOT}" + if repo_ready "${REPO_ROOT}"; then + path="${REPO_ROOT}" + fi + # shellcheck source=/dev/null + if [[ -f "${LIB_DIR}/common.sh" ]]; then + source "${LIB_DIR}/common.sh" + ip="$(detect_server_ip)" + else + ip="?" + fi + echo "" + echo "╔══════════════════════════════════════╗" + echo "║ crypto_monitor 部署管理器 ║" + echo "║ 路径: ${path}" + echo "╚══════════════════════════════════════╝" + echo "" +} + +show_menu() { + echo " 1) 一键部署" + echo " 2) 一键卸载" + echo " 3) 更新" + echo " 0) 退出" + echo "" +} + +main_menu() { + bootstrap_repo + # shellcheck source=lib/common.sh + source "${LIB_DIR}/common.sh" + REPO_ROOT="$(resolve_repo_root || echo "${INSTALL_ROOT}")" + + while true; do + show_banner + show_menu + local choice="" + read -r -p "请选择 [0-3]: " choice + case "${choice}" in + 1) + bash "${LIB_DIR}/install.sh" + ;; + 2) + bash "${LIB_DIR}/uninstall.sh" + ;; + 3) + bash "${LIB_DIR}/update.sh" + ;; + 0) + echo "再见." + exit 0 + ;; + *) + echo "无效选项,请输入 0-3" + ;; + esac + echo "" + read -r -p "按 Enter 返回菜单..." _ + done +} + +main_menu "$@" diff --git a/docs/ubuntu-server.md b/docs/ubuntu-server.md index 0d5483b..b0e4a60 100644 --- a/docs/ubuntu-server.md +++ b/docs/ubuntu-server.md @@ -38,11 +38,20 @@ apt install -y python3.12-venv ### 2.2 一键创建各目录 venv +**推荐**(新服务器一条命令): + +```bash +curl -fsSL https://git.bz121.com/dekun/crypto_monitor/raw/branch/main/deploy/manage.sh | bash +# 菜单选 1) 一键部署 +``` + +或已 clone 后: + ```bash cd /opt/crypto_monitor +bash deploy/manage.sh +# 或仅建环境: bash deploy/setup_env.sh --install-system-deps -# 或已是 root 且已装 venv 包: -bash deploy/setup_env.sh ``` 完成后各目录使用 **`.venv/bin/python`** 运行 `app.py` / `hub.py`;**PM2 的 ecosystem 脚本已指向该解释器**. @@ -163,7 +172,7 @@ curl -sS http://127.0.0.1:5100/api/monitor/board | head | 文档 | 内容 | |------|------| -| [deploy/README.md](../deploy/README.md) | `setup_env.sh` 参数说明 | +| [deploy/README.md](../deploy/README.md) | `manage.sh` 一键部署;`setup_env.sh` 参数 | | [备份与恢复.md](../备份与恢复.md) | 数据库与 `.env` 备份 | | 各 `crypto_monitor_*/部署文档.md` | 交易所 SOCKS,`.env`,PM2 细节 | | [manual_trading_hub/部署文档.md](../manual_trading_hub/部署文档.md) | 中控 PM2,端口,反代 |