添加Docker部署方案

- 多阶段Dockerfile:第一阶段构建前端(npm),第二阶段Python运行时(uv+opencv)
- docker-compose.yml:单服务,data/logs目录挂载持久化
- deploy.sh一键部署脚本:自动构建+启动+健康检查
- .dockerignore排除不必要文件减小构建上下文
- main.py添加前端静态文件服务(生产环境单端口部署)
- README更新部署文档和代理配置说明
This commit is contained in:
yml2213
2026-06-23 00:54:48 +08:00
parent da2fedd484
commit 93d358f214
6 changed files with 265 additions and 1 deletions
+33
View File
@@ -0,0 +1,33 @@
.venv/
__pycache__/
*/__pycache__
*.pyc
# 运行时数据(通过 volume 挂载)
data/
logs/
*.db
*.log
# 前端依赖和构建产物(Docker 内重新构建)
web/frontend/node_modules/
web/frontend/dist/
# geetest 临时图片
bg.jpg
fullbg.jpg
slice.jpg
# Git
.git/
.gitignore
# IDE
.vscode/
.idea/
# 文档
*.md
# 测试日志
11.log
+52
View File
@@ -0,0 +1,52 @@
# ===== 阶段1: 构建前端 =====
FROM node:20-slim AS frontend-builder
WORKDIR /build
COPY web/frontend/package.json web/frontend/package-lock.json* ./
RUN npm ci || npm install
COPY web/frontend/ ./
RUN npm run build
# ===== 阶段2: Python 运行时 =====
FROM python:3.12-slim AS runtime
# 安装 OpenCV 系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
libgl1 \
libglib2.0-0 \
&& rm -rf /var/lib/apt/lists/*
# 安装 uv 用于快速安装依赖
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
WORKDIR /app
# 先复制依赖文件,利用 Docker 缓存层
COPY pyproject.toml uv.lock* ./
RUN uv venv /app/.venv && uv pip install -e .
# 复制项目代码
COPY core/ ./core/
COPY utils/ ./utils/
COPY web/backend/ ./web/backend/
COPY README.md ./
# 复制前端构建产物
COPY --from=frontend-builder /build/dist ./web/frontend/dist
# 创建数据和日志目录
RUN mkdir -p /app/data /app/logs
# 环境变量
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
ENV PATH="/app/.venv/bin:$PATH"
EXPOSE 8000
# 健康检查
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health')" || exit 1
# 启动命令
CMD ["python", "-m", "uvicorn", "web.backend.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"]
+60
View File
@@ -83,3 +83,63 @@ cd web/frontend && npm install && npm run dev
## 许可证
MIT License
## 部署
### Docker 部署(推荐,生产环境)
```bash
# 一键部署(自动构建镜像 + 启动服务)
./deploy.sh
# 或手动操作:
docker compose up -d --build
```
部署完成后访问 `http://服务器IP:8000`,默认账号 `admin / admin123`
**Docker 常用命令:**
```bash
docker compose logs -f # 查看实时日志
docker compose restart # 重启服务
docker compose down # 停止服务
docker compose up -d --build # 重新构建并启动(代码更新后)
```
**数据持久化:** 数据库和日志通过 volume 挂载到宿主机 `./data``./logs` 目录,容器重建后数据不丢失。
### 本地开发
```bash
# 一键启动(自动检查依赖,前后端分离开发模式)
./start_web.sh
# 或手动启动:
# 后端
uv pip install -e .
.venv/bin/python -m uvicorn web.backend.main:app --reload --port 8000
# 前端
cd web/frontend && npm install && npm run dev
```
访问 `http://localhost:5173`(开发模式),默认账号 `admin / admin123`
### 代理配置说明
在 Web 界面"代理配置"页面设置:
1. **API 代理**:填入代理 API 地址(支持返回 JSON 格式),系统自动获取并验证代理
2. **白名单**:如代理需要白名单,填入 UID 和 UKEY,系统自动同步出口 IP
3. **出口 IP 漂移**:移动网络出口 IP 频繁漂移时,系统会保留多个出口 IP 在白名单中
**代理 API JSON 格式:**
```json
// 正常返回
{"code":0,"success":"true","msg":"","data":[{"IP":"1.2.3.4","Port":8080}]}
// 白名单错误
{"code":-1,"msg":"51.请先添加白名单:1.2.3.4","data":""}
```
Executable
+72
View File
@@ -0,0 +1,72 @@
#!/usr/bin/env bash
set -e
# ===== 斗鱼批量登录 Docker 部署脚本 =====
ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$ROOT_DIR"
echo ""
echo "=============================="
echo " 斗鱼批量登录 - Docker 部署"
echo "=============================="
# 检查 Docker
if ! command -v docker &> /dev/null; then
echo "❌ 未安装 Docker,请先安装:"
echo " curl -fsSL https://get.docker.com | sh"
exit 1
fi
# 检查 docker compose
if docker compose version &> /dev/null; then
COMPOSE="docker compose"
elif command -v docker-compose &> /dev/null; then
COMPOSE="docker-compose"
else
echo "❌ 未安装 docker compose,请先安装 Docker Compose"
exit 1
fi
echo " 使用: $COMPOSE"
echo ""
# 创建数据和日志目录
mkdir -p data logs
# 构建并启动
echo "正在构建镜像(首次构建约3-5分钟)..."
$COMPOSE build
echo ""
echo "正在启动服务..."
$COMPOSE up -d
echo ""
echo "等待服务启动..."
sleep 3
# 健康检查
for i in $(seq 1 10); do
if curl -s http://localhost:8000/api/health | grep -q "ok" 2>/dev/null; then
echo ""
echo "=============================="
echo " ✅ 部署成功!"
echo "=============================="
echo " 访问地址: http://localhost:8000"
echo " 默认账号: admin / admin123"
echo ""
echo " 查看日志: $COMPOSE logs -f"
echo " 停止服务: $COMPOSE down"
echo " 重启服务: $COMPOSE restart"
echo "=============================="
exit 0
fi
echo " 等待中... ($i/10)"
sleep 2
done
echo ""
echo "❌ 服务启动超时,查看日志:"
$COMPOSE logs --tail 30
exit 1
+18
View File
@@ -0,0 +1,18 @@
services:
douyu-login:
build: .
container_name: douyu-login
restart: unless-stopped
ports:
- "8000:8000"
volumes:
# 持久化数据库和日志
- ./data:/app/data
- ./logs:/app/logs
environment:
- TZ=Asia/Shanghai
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health')"]
interval: 30s
timeout: 5s
retries: 3
+30 -1
View File
@@ -1,9 +1,13 @@
"""FastAPI 入口"""
import os
from pathlib import Path
import uvicorn
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from .database import init_db
from .routers import auth, users, accounts, login, proxy, cookies, logs
@@ -45,6 +49,31 @@ def health():
return {"status": "ok"}
# ---- 生产环境:serve 前端静态文件 ----
# Docker 部署时前端构建产物会被复制到 web/frontend/dist
_FRONTEND_DIST = Path(__file__).resolve().parents[2] / "web" / "frontend" / "dist"
_INDEX_HTML = _FRONTEND_DIST / "index.html"
if _INDEX_HTML.exists():
# 挂载静态资源目录(js/css/图片等)
_ASSETS_DIR = _FRONTEND_DIST / "assets"
if _ASSETS_DIR.exists():
app.mount("/assets", StaticFiles(directory=str(_ASSETS_DIR)), name="assets")
@app.get("/{full_path:path}")
async def serve_spa(full_path: str, request: Request):
"""SPA fallback:非 /api 路径返回 index.html"""
# 排除 API 路径
if full_path.startswith("api"):
return {"detail": "Not Found"}
# 尝试返回静态文件
file_path = _FRONTEND_DIST / full_path
if file_path.is_file():
return FileResponse(str(file_path))
# SPA fallback 到 index.html
return FileResponse(str(_INDEX_HTML))
def run():
uvicorn.run("web.backend.main:app", host="0.0.0.0", port=8000, reload=True)