新增自动构建镜像

This commit is contained in:
zhinianboke 2025-10-25 17:43:46 +08:00
parent 37581e7b4d
commit 16d9946c25
6 changed files with 248 additions and 16 deletions

137
README.md
View File

@ -184,10 +184,12 @@ xianyu-auto-reply/
│ ├── .gitignore # Git忽略文件配置完整版
│ └── README.md # 项目说明文档(本文件)
└── 📊 数据目录(运行时创建)
├── data/ # 数据目录Docker挂载
│ └── xianyu_data.db # SQLite数据库文件
├── data/ # 数据目录Docker挂载自动创建
│ ├── xianyu_data.db # SQLite主数据库文件
│ ├── user_stats.db # 用户统计数据库
│ └── xianyu_data_backup_*.db # 数据库备份文件
├── logs/ # 按日期分割的日志文件
└── backups/ # 数据备份文件
└── backups/ # 其他备份文件
```
</details>
@ -203,6 +205,12 @@ xianyu-auto-reply/
- ✅ 完善的错误处理和重试机制,提升系统稳定性
- ✅ 修复滑块验证模块内存泄漏问题,浏览器资源正确释放
**📦 数据管理优化**
- ✅ 数据库文件统一迁移到 `data/` 目录,更好的组织和管理
- ✅ 启动时自动检测并迁移旧数据库文件,无需手动操作
- ✅ 备份文件自动整理到数据目录,便于集中管理
- ✅ Docker挂载更简洁一个data目录包含所有数据
**🛠️ 配置文件优化**
- ✅ 完善 `.gitignore`,新增编译产物、浏览器缓存等规则
- ✅ 完善 `.dockerignore`优化Docker构建速度和镜像体积
@ -221,9 +229,10 @@ xianyu-auto-reply/
**🏗️ 多架构支持**
- ✅ Docker镜像支持AMD64和ARM64双架构
- ✅ GitHub Actions自动构建多架构镜像
- ✅ GitHub Actions自动构建并推送到双镜像仓库
- ✅ 支持Oracle Cloud、AWS Graviton等ARM服务器
- ✅ Docker自动选择匹配的架构无需手动指定
- ✅ 国内外双镜像源,确保下载速度
## 🚀 云服务器推荐
@ -234,26 +243,57 @@ xianyu-auto-reply/
**⚡ 最快部署方式(推荐)**:使用预构建镜像,无需下载源码,一条命令即可启动!
### 方式一Docker 一键部署(最简单)
### 方式一Docker 一键部署(最简单)
**国内用户(阿里云镜像,推荐)**
```bash
# 1. 创建数据目录
mkdir -p xianyu-auto-reply
# 2. 一键启动容器
docker run -d -p 8080:8080 --restart always -v $PWD/xianyu-auto-reply/:/app/data/ --name xianyu-auto-reply registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:1.0.4
# 2. 一键启动容器支持AMD64/ARM64自动选择架构
docker run -d \
-p 8080:8080 \
--restart always \
-v $PWD/xianyu-auto-reply/:/app/data/ \
--name xianyu-auto-reply \
registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:latest
# 3. 访问系统
# http://localhost:8080
```
**国际用户Docker Hub镜像**
```bash
# 使用Docker Hub国际镜像
docker run -d \
-p 8080:8080 \
--restart always \
-v $PWD/xianyu-auto-reply/:/app/data/ \
--name xianyu-auto-reply \
zhinianblog/xianyu-auto-reply:latest
```
**Windows用户**
```cmd
```powershell
# 创建数据目录
mkdir xianyu-auto-reply
# 启动容器
docker run -d -p 8080:8080 -v %cd%/xianyu-auto-reply/:/app/data/ --name xianyu-auto-reply registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:1.0.4
# 国内用户(阿里云)
docker run -d -p 8080:8080 --restart always -v %cd%/xianyu-auto-reply/:/app/data/ --name xianyu-auto-reply registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:latest
# 国际用户Docker Hub
docker run -d -p 8080:8080 --restart always -v %cd%/xianyu-auto-reply/:/app/data/ --name xianyu-auto-reply zhinianblog/xianyu-auto-reply:latest
```
**ARM64服务器** (Oracle Cloud, AWS Graviton等)
```bash
# Docker会自动选择ARM64镜像无需特殊配置
docker run -d \
-p 8080:8080 \
--restart always \
-v $PWD/xianyu-auto-reply/:/app/data/ \
--name xianyu-auto-reply \
registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:latest
```
### 方式二:从源码构建部署
@ -337,7 +377,11 @@ python Start.py
- ✅ **linux/amd64** - Intel/AMD处理器传统服务器、PC、虚拟机
- ✅ **linux/arm64** - ARM64处理器ARM服务器、树莓派4+、Apple M系列
**自动构建**: GitHub Actions自动构建并推送多架构镜像Docker会自动选择匹配的架构
**镜像仓库**:
- 🇨🇳 **阿里云**: `registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:latest`
- 🌍 **Docker Hub**: `zhinianblog/xianyu-auto-reply:latest`
**自动构建**: GitHub Actions自动构建并推送多架构镜像到两个镜像仓库Docker会自动选择匹配的架构
**适用的ARM云服务器**:
- Oracle Cloud - Ampere A1 (永久免费4核24GB)
@ -356,6 +400,9 @@ WEB_PORT=8080 # Web服务端口
API_HOST=0.0.0.0 # API服务主机
TZ=Asia/Shanghai # 时区设置
# 数据库配置
DB_PATH=data/xianyu_data.db # 数据库文件路径默认在data目录
# 管理员配置
ADMIN_USERNAME=admin # 管理员用户名
ADMIN_PASSWORD=admin123 # 管理员密码(请修改)
@ -734,6 +781,74 @@ CPU_LIMIT=2.0 # CPU限制(核心数)
- **日志文件**`logs/` 目录下的按日期分割的日志文件
- **日志级别**支持DEBUG、INFO、WARNING、ERROR级别
### Docker容器管理
**查看容器日志**
```bash
# 实时查看日志
docker logs -f xianyu-auto-reply
# 查看最近100行
docker logs --tail 100 xianyu-auto-reply
```
**更新到最新版本**
国内用户(阿里云镜像):
```bash
# 1. 停止并删除旧容器
docker stop xianyu-auto-reply
docker rm xianyu-auto-reply
# 2. 拉取最新镜像
docker pull registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:latest
# 3. 启动新容器
docker run -d -p 8080:8080 --restart always \
-v $PWD/xianyu-auto-reply/:/app/data/ \
--name xianyu-auto-reply \
registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:latest
```
国际用户Docker Hub
```bash
# 1. 停止并删除旧容器
docker stop xianyu-auto-reply
docker rm xianyu-auto-reply
# 2. 拉取最新镜像
docker pull zhinianblog/xianyu-auto-reply:latest
# 3. 启动新容器
docker run -d -p 8080:8080 --restart always \
-v $PWD/xianyu-auto-reply/:/app/data/ \
--name xianyu-auto-reply \
zhinianblog/xianyu-auto-reply:latest
```
**验证多架构镜像**
```bash
# 查看镜像支持的架构
docker manifest inspect registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:latest | grep architecture
# 或Docker Hub镜像
docker manifest inspect zhinianblog/xianyu-auto-reply:latest | grep architecture
# 应该显示: "architecture": "amd64" 和 "architecture": "arm64"
```
**容器重启**
```bash
# 重启容器
docker restart xianyu-auto-reply
# 停止容器
docker stop xianyu-auto-reply
# 启动容器
docker start xianyu-auto-reply
```
## 🔒 安全特性

View File

@ -7,11 +7,98 @@
import os
import sys
import shutil
from pathlib import Path
# ==================== 在导入任何模块之前先迁移数据库 ====================
def _migrate_database_files_early():
"""在启动前检查并迁移数据库文件到data目录使用print因为logger还未初始化"""
print("检查数据库文件位置...")
# 确保data目录存在
data_dir = Path("data")
if not data_dir.exists():
data_dir.mkdir(parents=True, exist_ok=True)
print("✓ 创建 data 目录")
# 定义需要迁移的文件
files_to_migrate = [
("xianyu_data.db", "data/xianyu_data.db", "主数据库"),
("user_stats.db", "data/user_stats.db", "统计数据库"),
]
migrated_files = []
# 迁移主数据库和统计数据库
for old_path, new_path, description in files_to_migrate:
old_file = Path(old_path)
new_file = Path(new_path)
if old_file.exists():
if not new_file.exists():
# 新位置不存在,移动文件
try:
shutil.move(str(old_file), str(new_file))
print(f"✓ 迁移{description}: {old_path} -> {new_path}")
migrated_files.append(description)
except Exception as e:
print(f"⚠ 无法迁移{description}: {e}")
print(f" 尝试复制文件...")
try:
shutil.copy2(str(old_file), str(new_file))
print(f"✓ 已复制{description}到新位置")
print(f" 请在确认数据正常后手动删除: {old_path}")
migrated_files.append(f"{description}(已复制)")
except Exception as e2:
print(f"✗ 复制{description}失败: {e2}")
else:
# 新位置已存在,检查旧文件大小
try:
if old_file.stat().st_size > 0:
print(f"⚠ 发现旧{description}文件: {old_path}")
print(f" 新数据库位于: {new_path}")
print(f" 建议备份后删除旧文件")
except:
pass
# 迁移备份文件
backup_files = list(Path(".").glob("xianyu_data_backup_*.db"))
if backup_files:
print(f"发现 {len(backup_files)} 个备份文件")
backup_migrated = 0
for backup_file in backup_files:
new_backup_path = data_dir / backup_file.name
if not new_backup_path.exists():
try:
shutil.move(str(backup_file), str(new_backup_path))
print(f"✓ 迁移备份文件: {backup_file.name}")
backup_migrated += 1
except Exception as e:
print(f"⚠ 无法迁移备份文件 {backup_file.name}: {e}")
if backup_migrated > 0:
migrated_files.append(f"{backup_migrated}个备份文件")
# 输出迁移总结
if migrated_files:
print(f"✓ 数据库迁移完成,已迁移: {', '.join(migrated_files)}")
else:
print("✓ 数据库文件检查完成")
return True
# 在导入 db_manager 之前先执行数据库迁移
try:
_migrate_database_files_early()
except Exception as e:
print(f"⚠ 数据库迁移检查失败: {e}")
# 继续启动,因为可能是首次运行
# ==================== 现在可以安全地导入其他模块 ====================
import asyncio
import threading
import uvicorn
from urllib.parse import urlparse
from pathlib import Path
from loguru import logger
# 修复Linux环境下的asyncio子进程问题
@ -56,6 +143,8 @@ def _start_api_server():
uvicorn.run("reply_server:app", host=host, port=port, log_level="info")
def load_keywords_file(path: str):
"""从文件读取关键字 -> [(keyword, reply)]"""
kw_list = []

View File

@ -20,7 +20,7 @@ class DBManager:
"""初始化数据库连接和表结构"""
# 支持环境变量配置数据库路径
if db_path is None:
db_path = os.getenv('DB_PATH', 'xianyu_data.db')
db_path = os.getenv('DB_PATH', 'data/xianyu_data.db')
# 确保数据目录存在并有正确权限
db_dir = os.path.dirname(db_path)

View File

@ -48,6 +48,34 @@ python -c "import fastapi, uvicorn, loguru, websockets" 2>/dev/null || {
}
echo "✓ Python 依赖检查完成"
# 迁移数据库文件到data目录如果需要
echo "检查数据库文件位置..."
if [ -f "/app/xianyu_data.db" ] && [ ! -f "/app/data/xianyu_data.db" ]; then
echo "发现旧数据库文件迁移到data目录..."
mv /app/xianyu_data.db /app/data/xianyu_data.db
echo "✓ 主数据库已迁移"
elif [ -f "/app/xianyu_data.db" ] && [ -f "/app/data/xianyu_data.db" ]; then
echo "⚠ 检测到新旧数据库都存在使用data目录中的数据库"
echo " 旧文件: /app/xianyu_data.db"
echo " 新文件: /app/data/xianyu_data.db"
fi
if [ -f "/app/user_stats.db" ] && [ ! -f "/app/data/user_stats.db" ]; then
echo "迁移统计数据库到data目录..."
mv /app/user_stats.db /app/data/user_stats.db
echo "✓ 统计数据库已迁移"
fi
# 迁移备份文件
backup_count=$(ls /app/xianyu_data_backup_*.db 2>/dev/null | wc -l)
if [ "$backup_count" -gt 0 ]; then
echo "发现 $backup_count 个备份文件迁移到data目录..."
mv /app/xianyu_data_backup_*.db /app/data/ 2>/dev/null || true
echo "✓ 备份文件已迁移"
fi
echo "✓ 数据库文件位置检查完成"
# 显示启动信息
echo "========================================"
echo " 系统启动参数:"

View File

@ -4543,8 +4543,8 @@ def list_backup_files(admin_user: Dict[str, Any] = Depends(require_admin)):
try:
log_with_user('info', "查询备份文件列表", admin_user)
# 查找备份文件
backup_files = glob.glob("xianyu_data_backup_*.db")
# 查找备份文件在data目录中
backup_files = glob.glob("data/xianyu_data_backup_*.db")
backup_list = []
for file_path in backup_files:

View File

@ -16,7 +16,7 @@ from pathlib import Path
app = FastAPI(title="闲鱼自动回复系统用户统计", version="1.0.0")
# 数据库文件路径
DB_PATH = Path(__file__).parent / "user_stats.db"
DB_PATH = Path(__file__).parent / "data" / "user_stats.db"
class UserStats(BaseModel):