feat: scaffold gold_monitor web hub, API, PM2 deploy and docs
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
# 环境一键部署(Ubuntu / root /opt)
|
||||
|
||||
在 **`/opt/gold_monitor`** 下以 **root** 部署 Flask Web+API,使用 **PM2** 常驻,端口 **5800**。
|
||||
|
||||
完整说明见 **[docs/ubuntu-server.md](../docs/ubuntu-server.md)** · **[docs/deploy.md](../docs/deploy.md)**。
|
||||
|
||||
---
|
||||
|
||||
## 一键部署管理器(推荐)
|
||||
|
||||
新服务器无需先 clone:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://git.bz121.com/dekun/gold_monitor/raw/branch/main/deploy/manage.sh | bash
|
||||
```
|
||||
|
||||
已安装机器:
|
||||
|
||||
```bash
|
||||
bash /opt/gold_monitor/deploy/manage.sh
|
||||
```
|
||||
|
||||
### 菜单
|
||||
|
||||
| 选项 | 功能 |
|
||||
|------|------|
|
||||
| **1) 一键部署** | 依赖 + venv + PM2 + 验收 `/health` |
|
||||
| **2) 一键卸载** | 备份 `.env`/`data` → 停 PM2 → 可选删目录 |
|
||||
| **3) 更新** | git pull / 依赖更新 + restart |
|
||||
| **0) 退出** | |
|
||||
|
||||
### 部署完成后
|
||||
|
||||
- 地址:`http://<服务器IP>:5800`
|
||||
- 登录:`admin` / `admin123`(请改 `.env`)
|
||||
- 将通用 exe 放到:`/opt/gold_monitor/releases/黄金市价辅助.exe`
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* PM2 进程配置 — gold_monitor
|
||||
* 端口默认 5800
|
||||
*/
|
||||
const path = require("path");
|
||||
const root = path.resolve(__dirname, "..");
|
||||
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: "gold_monitor",
|
||||
cwd: root,
|
||||
script: path.join(root, ".venv/bin/gunicorn"),
|
||||
args: "wsgi:app --bind 0.0.0.0:5800 --workers 2 --threads 4 --timeout 120",
|
||||
interpreter: "none",
|
||||
autorestart: true,
|
||||
max_restarts: 20,
|
||||
min_uptime: "5s",
|
||||
env: {
|
||||
PYTHONUNBUFFERED: "1",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck shell=bash
|
||||
|
||||
detect_server_ip() {
|
||||
local ip
|
||||
ip="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
||||
if [[ -z "${ip}" ]]; then
|
||||
ip="$(ip -4 route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="src"){print $(i+1); exit}}')"
|
||||
fi
|
||||
echo "${ip:-127.0.0.1}"
|
||||
}
|
||||
|
||||
need_root() {
|
||||
if [[ "$(id -u)" -ne 0 ]]; then
|
||||
echo "错误: 请使用 root 执行" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_node_pm2() {
|
||||
if ! command -v node >/dev/null 2>&1; then
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
|
||||
apt-get install -y nodejs
|
||||
fi
|
||||
if ! command -v pm2 >/dev/null 2>&1; then
|
||||
npm install -g pm2
|
||||
fi
|
||||
}
|
||||
|
||||
verify_http() {
|
||||
local url="$1"
|
||||
curl -fsS --max-time 5 "${url}" >/dev/null 2>&1
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck shell=bash
|
||||
set -euo pipefail
|
||||
# shellcheck source=common.sh
|
||||
source "${LIB_DIR}/common.sh"
|
||||
need_root
|
||||
|
||||
echo "[1/4] 安装系统依赖 / venv ..."
|
||||
bash "${REPO_ROOT}/deploy/setup_env.sh"
|
||||
|
||||
echo "[2/4] 安装 Node / PM2 ..."
|
||||
ensure_node_pm2
|
||||
|
||||
echo "[3/4] 启动 PM2 ..."
|
||||
cd "${REPO_ROOT}"
|
||||
pm2 delete gold_monitor >/dev/null 2>&1 || true
|
||||
pm2 start "${REPO_ROOT}/deploy/ecosystem.config.cjs"
|
||||
pm2 save
|
||||
pm2 startup systemd -u root --hp /root >/dev/null 2>&1 || true
|
||||
|
||||
echo "[4/4] 验收 ..."
|
||||
sleep 2
|
||||
IP="$(detect_server_ip)"
|
||||
if verify_http "http://127.0.0.1:5800/health"; then
|
||||
echo "✓ 健康检查通过"
|
||||
else
|
||||
echo "✗ 健康检查失败,请执行: pm2 logs gold_monitor" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "部署完成"
|
||||
echo " 地址: http://${IP}:5800"
|
||||
echo " 登录: admin / admin123 (请立即修改 .env 中 ADMIN_PASSWORD)"
|
||||
echo " 管理: bash ${REPO_ROOT}/deploy/manage.sh"
|
||||
echo ""
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck shell=bash
|
||||
set -euo pipefail
|
||||
# shellcheck source=common.sh
|
||||
source "${LIB_DIR}/common.sh"
|
||||
need_root
|
||||
|
||||
TS="$(date +%Y%m%d_%H%M%S)"
|
||||
BACKUP="/opt/gold_monitor_backup_${TS}"
|
||||
mkdir -p "${BACKUP}"
|
||||
[[ -f "${REPO_ROOT}/.env" ]] && cp "${REPO_ROOT}/.env" "${BACKUP}/"
|
||||
[[ -d "${REPO_ROOT}/data" ]] && cp -a "${REPO_ROOT}/data" "${BACKUP}/" || true
|
||||
|
||||
pm2 delete gold_monitor >/dev/null 2>&1 || true
|
||||
pm2 save >/dev/null 2>&1 || true
|
||||
|
||||
echo "已备份到 ${BACKUP}"
|
||||
read -r -p "是否删除目录 ${REPO_ROOT}? [y/N] " ans
|
||||
if [[ "${ans}" == "y" || "${ans}" == "Y" ]]; then
|
||||
rm -rf "${REPO_ROOT}"
|
||||
echo "已删除 ${REPO_ROOT}"
|
||||
else
|
||||
echo "保留目录,仅停止 PM2 进程"
|
||||
fi
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck shell=bash
|
||||
set -euo pipefail
|
||||
# shellcheck source=common.sh
|
||||
source "${LIB_DIR}/common.sh"
|
||||
need_root
|
||||
|
||||
echo "更新子菜单"
|
||||
echo " 1) 快速更新 (git pull + pm2 restart)"
|
||||
echo " 2) 依赖更新 (pull + pip + restart)"
|
||||
echo " 0) 返回"
|
||||
read -r -p "选择: " choice
|
||||
case "${choice}" in
|
||||
1)
|
||||
git -C "${REPO_ROOT}" pull --ff-only
|
||||
pm2 restart gold_monitor
|
||||
;;
|
||||
2)
|
||||
git -C "${REPO_ROOT}" pull --ff-only
|
||||
bash "${REPO_ROOT}/deploy/setup_env.sh"
|
||||
pm2 restart gold_monitor
|
||||
;;
|
||||
*)
|
||||
echo "取消"
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env bash
|
||||
# gold_monitor 部署管理器 — 一键部署 / 卸载 / 更新
|
||||
#
|
||||
# 新服务器(免克隆):
|
||||
# curl -fsSL https://git.bz121.com/dekun/gold_monitor/raw/branch/main/deploy/manage.sh | bash
|
||||
#
|
||||
# 已安装:
|
||||
# bash /opt/gold_monitor/deploy/manage.sh
|
||||
#
|
||||
set -e
|
||||
if [ -n "${BASH_VERSION:-}" ]; then
|
||||
set -o pipefail
|
||||
fi
|
||||
|
||||
INSTALL_ROOT="${INSTALL_ROOT:-/opt/gold_monitor}"
|
||||
GIT_URL="${GIT_URL:-https://git.bz121.com/dekun/gold_monitor.git}"
|
||||
GIT_BRANCH="${GIT_BRANCH:-main}"
|
||||
|
||||
_script_src="${BASH_SOURCE[0]:-}"
|
||||
if [[ -n "${_script_src}" && -f "${_script_src}" ]]; then
|
||||
DEPLOY_DIR="$(cd "$(dirname "${_script_src}")" && pwd)"
|
||||
REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)"
|
||||
LIB_DIR="${DEPLOY_DIR}/lib"
|
||||
else
|
||||
DEPLOY_DIR=""
|
||||
REPO_ROOT=""
|
||||
LIB_DIR=""
|
||||
fi
|
||||
unset _script_src
|
||||
|
||||
set -u
|
||||
|
||||
repo_ready() {
|
||||
[[ -f "${1}/deploy/setup_env.sh" && -f "${1}/deploy/manage.sh" ]]
|
||||
}
|
||||
|
||||
sync_repo_if_present() {
|
||||
local root="$1"
|
||||
if [[ -d "${root}/.git" ]] && command -v git >/dev/null 2>&1; then
|
||||
git -C "${root}" pull -q --ff-only 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
bootstrap_repo() {
|
||||
if repo_ready "${INSTALL_ROOT}"; then
|
||||
REPO_ROOT="${INSTALL_ROOT}"
|
||||
DEPLOY_DIR="${REPO_ROOT}/deploy"
|
||||
LIB_DIR="${DEPLOY_DIR}/lib"
|
||||
sync_repo_if_present "${REPO_ROOT}"
|
||||
return 0
|
||||
fi
|
||||
if [[ -n "${REPO_ROOT}" ]] && repo_ready "${REPO_ROOT}"; then
|
||||
DEPLOY_DIR="${REPO_ROOT}/deploy"
|
||||
LIB_DIR="${DEPLOY_DIR}/lib"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "gold_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
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$(dirname "${INSTALL_ROOT}")"
|
||||
git clone -b "${GIT_BRANCH}" "${GIT_URL}" "${INSTALL_ROOT}"
|
||||
exec bash "${INSTALL_ROOT}/deploy/manage.sh" "$@" </dev/tty
|
||||
}
|
||||
|
||||
show_banner() {
|
||||
local ip path
|
||||
path="${INSTALL_ROOT}"
|
||||
if repo_ready "${REPO_ROOT}"; then
|
||||
path="${REPO_ROOT}"
|
||||
fi
|
||||
if [[ -f "${LIB_DIR}/common.sh" ]]; then
|
||||
# shellcheck source=/dev/null
|
||||
source "${LIB_DIR}/common.sh"
|
||||
ip="$(detect_server_ip)"
|
||||
else
|
||||
ip="?"
|
||||
fi
|
||||
echo ""
|
||||
echo "╔══════════════════════════════════════╗"
|
||||
echo "║ gold_monitor 部署管理器 ║"
|
||||
echo "║ 路径: ${path}"
|
||||
echo "║ 端口: 5800 IP: ${ip}"
|
||||
echo "╚══════════════════════════════════════╝"
|
||||
echo ""
|
||||
}
|
||||
|
||||
show_menu() {
|
||||
echo " 1) 一键部署(Web + API + PM2)"
|
||||
echo " 2) 一键卸载"
|
||||
echo " 3) 更新"
|
||||
echo " 0) 退出"
|
||||
echo ""
|
||||
}
|
||||
|
||||
main_menu() {
|
||||
bootstrap_repo
|
||||
export REPO_ROOT DEPLOY_DIR LIB_DIR INSTALL_ROOT GIT_URL GIT_BRANCH
|
||||
# shellcheck source=/dev/null
|
||||
source "${LIB_DIR}/common.sh"
|
||||
show_banner
|
||||
while true; do
|
||||
show_menu
|
||||
read -r -p "请选择: " choice
|
||||
case "${choice}" in
|
||||
1) bash "${LIB_DIR}/install.sh" ;;
|
||||
2) bash "${LIB_DIR}/uninstall.sh" ;;
|
||||
3) bash "${LIB_DIR}/update.sh" ;;
|
||||
0) exit 0 ;;
|
||||
*) echo "无效选项" ;;
|
||||
esac
|
||||
echo ""
|
||||
done
|
||||
}
|
||||
|
||||
main_menu "$@"
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
cd "${ROOT}"
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y python3 python3-venv python3-pip git ca-certificates curl
|
||||
|
||||
if [[ ! -d .venv ]]; then
|
||||
python3 -m venv .venv
|
||||
fi
|
||||
# shellcheck disable=SC1091
|
||||
source .venv/bin/activate
|
||||
pip install -U pip
|
||||
pip install -r requirements.txt
|
||||
|
||||
if [[ ! -f .env ]]; then
|
||||
cp .env.example .env
|
||||
# 生成随机 SECRET
|
||||
SECRET="$(python3 - <<'PY'
|
||||
import secrets
|
||||
print(secrets.token_urlsafe(32))
|
||||
PY
|
||||
)"
|
||||
IP="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
||||
IP="${IP:-127.0.0.1}"
|
||||
sed -i "s|^FLASK_SECRET_KEY=.*|FLASK_SECRET_KEY=${SECRET}|" .env
|
||||
sed -i "s|^PUBLIC_BASE_URL=.*|PUBLIC_BASE_URL=http://${IP}:5800|" .env
|
||||
echo "已生成 .env (PUBLIC_BASE_URL=http://${IP}:5800)"
|
||||
fi
|
||||
|
||||
mkdir -p data releases
|
||||
echo "setup_env 完成"
|
||||
Reference in New Issue
Block a user