qinglong/README-NODE.md
jiandanc 0af546cd1d feat: 支持 Python venv 隔离环境,适配 Node.js 原生部署
## 背景
原方案使用系统 Python + pip --prefix 安装依赖到 data/dep_cache/python3,
系统 Python 环境被污染,且无法隔离不同项目的依赖。

## 改动内容

### 核心:Python venv 支持
- shell/start.sh: 使用 python3 -m venv 创建虚拟环境,替代 --prefix 模式
  - 从 .env 文件读取 PYTHON_VENV_DIR 配置
  - 首次启动自动创建 .venv,已存在则跳过
  - 仅将 .venv/bin 加入 PATH 优先级,不设置 PYTHONHOME/PYTHONPATH(避免破坏 venv 机制)
  - .env 不再强制覆盖,仅首次从 .env.example 复制
  - 启动时自动修复 task/ql 软链接指向当前部署目录

### 后端适配
- back/config/const.ts: 新增 PYTHON_VENV_DIR 常量
- back/config/util.ts: venv 模式下跳过 pip --prefix,直接使用 venv 的 pip3

### 开发模式支持
- shell/dev-env.sh: pnpm start 时自动 source,将 .venv/bin 加入 PATH
- package.json: start:back 加入 source dev-env.sh

### 新增文件
- shell/start-simplify.sh: 精简版启动脚本(跳过系统依赖安装,适用于已预装环境的服务器)
- README-NODE.md: Node.js 原生部署完整文档

### 配置
- .env.example: 新增 PYTHON_VENV_DIR=./.venv 配置项(默认注释状态)

## 兼容性
- Docker 模式不受影响(使用独立的 docker-entrypoint.sh,走原有 --prefix 逻辑)
- 未配置 PYTHON_VENV_DIR 时默认使用系统 Python(向后兼容)
2026-06-07 21:03:51 +08:00

297 lines
6.7 KiB
Markdown
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.

# QingLong - Node.js 原生部署指南
本文档说明如何在 Linux 服务器上以 Node.js 原生方式编译、部署和运行青龙面板,使用 Python venv 隔离环境。
## 一、环境要求
### 本地构建环境macOS / Linux
- Node.js 20.x
- pnpm 8.3.1
- Python 3.x
### 服务器运行环境
- Node.js 16+
- Python 3 + python3-venv
- nginx
- jq、curl、git
- pm2全局安装
## 二、本地编译
```bash
# 克隆项目
git clone https://github.com/whyour/qinglong.git
cd qinglong
# 安装依赖
npm i -g pnpm@8.3.1
pnpm install
# 创建本地 venv可选仅本地开发需要
python3 -m venv .venv
# 构建前端
pnpm build:front
# 构建后端
pnpm build:back
```
构建产物:
```
static/
├── build/ ← 后端编译产物tsc
│ └── app.js ← pm2 入口
└── dist/ ← 前端构建产物umi
├── index.html
└── ...
```
## 三、打包上传
### 打包(不含 node_modules约 12MB
```bash
COPYFILE_DISABLE=1 tar czf qinglong-deploy.tar.gz \
--exclude='node_modules' \
static/ shell/ sample/ back/protos/ \
package.json pnpm-lock.yaml ecosystem.config.js .env.example version.yaml
```
### 上传到服务器
```bash
scp qinglong-deploy.tar.gz user@server:~/
```
## 四、服务器部署
### 4.1 解压并安装依赖
```bash
mkdir -p ~/qinglong
tar xzf qinglong-deploy.tar.gz -C ~/qinglong
cd ~/qinglong
# 安装 pnpm如果没有
npm i -g pnpm@8.3.1
# 安装生产依赖
pnpm install --prod
```
### 4.2 首次启动
```bash
export QL_DIR=$(pwd)
export QL_DATA_DIR="${QL_DIR}/data"
bash shell/start-simplify.sh
```
首次启动会自动:
1. 读取 `.env` 配置(不存在则从 `.env.example` 复制)
2. 创建 Python venv`${QL_DIR}/.venv`
3. 安装 `requests` 到 venv
4. 修复 `task` / `ql` 命令软链接
5. 启动 nginx + pm2
访问 `http://服务器IP:5700` 即可。
### 4.3 配置 systemctl 开机自启
```bash
sudo tee /etc/systemd/system/qinglong.service << 'EOF'
[Unit]
Description=QingLong Panel
After=network.target
[Service]
Type=forking
WorkingDirectory=/home/jiandanc/qinglong
Environment="QL_DIR=/home/jiandanc/qinglong"
Environment="QL_DATA_DIR=/home/jiandanc/qinglong/data"
ExecStart=/bin/bash /home/jiandanc/qinglong/shell/start-simplify.sh
StandardOutput=journal
StandardError=journal
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
# 重载配置
sudo systemctl daemon-reload
# 启动服务
sudo systemctl start qinglong
# 设置开机自启
sudo systemctl enable qinglong
# 查看状态
sudo systemctl status qinglong
# 查看日志
sudo journalctl -u qinglong -f
```
> **注意**`WorkingDirectory`、`QL_DIR`、`QL_DATA_DIR` 需要替换为你的实际部署路径。
## 五、目录结构
部署后的完整目录结构:
```
~/qinglong/ ← QL_DIR
├── .venv/ ← Python 虚拟环境(自动创建)
│ ├── bin/
│ │ ├── python3
│ │ └── pip3
│ └── lib/
├── data/ ← QL_DATA_DIR运行数据
│ ├── config/ ← 配置文件
│ │ ├── config.sh ← 用户配置
│ │ └── crontab.list ← 定时任务列表
│ ├── scripts/ ← 用户脚本
│ ├── log/ ← 运行日志
│ ├── db/ ← 数据库
│ ├── deps/ ← 依赖缓存
│ └── dep_cache/
│ └── node/ ← Node 依赖缓存
├── static/
│ ├── build/ ← 后端编译产物
│ └── dist/ ← 前端构建产物
├── shell/
│ ├── start.sh ← 完整启动脚本(含系统依赖安装)
│ ├── start-simplify.sh ← 精简启动脚本(跳过系统依赖安装)
│ ├── task.sh ← 定时任务执行脚本
│ └── update.sh ← 更新脚本ql 命令)
├── sample/ ← 配置模板
├── back/protos/ ← gRPC proto 文件
├── ecosystem.config.js ← pm2 配置
├── package.json
└── .env ← 环境变量Node.js 读取)
```
## 六、Python venv 说明
### 工作原理
启动脚本将 `.venv/bin` 加入 `PATH` 最前面,使所有 `python3` / `pip3` 调用自动指向 venv无需修改 `task.sh` 等原有脚本。
### 环境变量解析优先级
```
1. export PYTHON_VENV_DIR=/path ← 手动 export最高优先级
2. .env 中 PYTHON_VENV_DIR=./.venv ← 启动脚本从 .env 读取
3. ${QL_DIR}/.venv ← 默认值(兜底)
```
### 不设置的变量
以下变量**不应设置**,否则会破坏 venv 的包解析机制:
- `PYTHONHOME` — 会覆盖 Python 的 prefix 解析
- `PYTHONUSERBASE` — venv 不需要
- `PYTHONPATH` — venv 通过 `pyvenv.cfg` 自动管理
### 验证 venv 是否生效
```bash
# 查看 Python 路径
which python3
# 预期: ~/qinglong/.venv/bin/python3
# 验证是否在 venv 中
python3 -c "import sys; print('✅ venv' if sys.prefix != sys.base_prefix else '❌ 系统')"
```
## 七、本地开发模式
```bash
cd qinglong
# 创建 venv
python3 -m venv .venv
# 安装依赖
pnpm install
# 启动(前端 8000 端口,后端 5700 端口)
pnpm start
```
开发模式下 `pnpm start` 会自动 source `shell/dev-env.sh` 设置 venv 环境。
## 八、常用运维命令
```bash
# 查看服务状态
sudo systemctl status qinglong
# 重启服务
sudo systemctl restart qinglong
# 查看日志
sudo journalctl -u qinglong -f
# 查看 pm2 状态
sudo pm2 list
# 查看 pm2 日志
sudo pm2 logs
# 手动运行任务
cd ~/qinglong
QL_DIR=$(pwd) QL_DATA_DIR="$(pwd)/data" bash shell/task.sh <脚本名> now
# 更新 qinglong重新编译后替换 static/ 目录,重启服务)
sudo systemctl restart qinglong
```
## 九、常见问题
### Q: 网页运行任务一直显示"运行中"
检查 `task` 软链接是否指向正确目录:
```bash
ls -la /usr/local/bin/task
# 应该指向 ~/qinglong/shell/task.sh不是 npm 全局路径
```
修复:
```bash
sudo ln -sf ~/qinglong/shell/task.sh /usr/local/bin/task
sudo pm2 restart qinglong
```
### Q: 安装 Python 依赖报权限错误
```bash
sudo chown -R $(whoami) ~/qinglong/.venv
```
### Q: sudo 运行后普通用户无权限
```bash
sudo chown -R $(whoami) ~/qinglong/data
```
### Q: systemctl 日志为空
确保 service 文件中包含:
```ini
StandardOutput=journal
StandardError=journal
```
然后 `sudo systemctl daemon-reload && sudo systemctl restart qinglong`