refactor(docker): 优化docker配置和部署脚本

重构Docker相关配置,包括:
- 更新.dockerignore文件,增加更多忽略规则
- 优化requirements.txt依赖管理
- 新增Makefile提供常用命令
- 重构docker-compose.yml配置
- 增强docker-entrypoint.sh功能
- 改进Dockerfile多阶段构建
- 新增docker-deploy.sh一键部署脚本
This commit is contained in:
linyq 2025-08-16 01:52:28 +08:00
parent 2569b7fee7
commit ced37047aa
7 changed files with 537 additions and 121 deletions

View File

@ -1,24 +1,99 @@
# Exclude common Python files and directories
venv/
__pycache__/
*.pyc
*.pyo
*.pyd
*.pyz
*.pyw
*.pyi
*.egg-info/
# Exclude development and local files
.env
.env.*
*.log
*.db
# Exclude version control system files
# Git 相关
.git/
.gitignore
.gitattributes
.svn/
storage/
# Python 相关
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# 虚拟环境
.env
.env.*
.venv
venv/
ENV/
env.bak/
venv.bak/
# IDE 相关
.vscode/
.idea/
*.swp
*.swo
*~
# 操作系统相关
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# 日志和数据库文件
*.log
*.db
logs/
# 临时文件
*.tmp
*.temp
temp/
tmp/
# 存储目录(运行时生成的内容)
storage/temp/
storage/tasks/
storage/demo.py
# 缓存目录
.cache/
.pytest_cache/
# 文档(保留必要的)
docs/
*.md
!README.md
# Docker 相关文件(避免递归复制)
Dockerfile.*
docker-compose.*.yml
# 配置文件(使用示例配置)
config.toml
# 资源文件中的大文件
resource/videos/
resource/songs/
# 测试文件
tests/
test_*
*_test.py
# 其他不必要的文件
*.bak
*.orig
*.rej

View File

@ -1,63 +1,97 @@
# 构建阶段
FROM python:3.10-slim-bullseye as builder
# 多阶段构建 - 构建阶段
FROM python:3.12-slim-bookworm AS builder
# 设置构建参数
ARG DEBIAN_FRONTEND=noninteractive
# 设置工作目录
WORKDIR /build
# 安装构建依赖
RUN apt-get update && apt-get install -y \
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
git \
git-lfs \
pkg-config \
&& rm -rf /var/lib/apt/lists/*
# 创建虚拟环境
RUN python -m venv /opt/venv
# 升级 pip 并创建虚拟环境
RUN python -m pip install --upgrade pip setuptools wheel && \
python -m venv /opt/venv
# 激活虚拟环境
ENV PATH="/opt/venv/bin:$PATH"
# 首先安装 PyTorch因为它是最大的依赖
RUN pip install --no-cache-dir torch torchvision torchaudio
# 然后安装其他依赖
# 复制 requirements.txt 并安装 Python 依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir -r requirements.txt
# 运行阶段
FROM python:3.10-slim-bullseye
FROM python:3.12-slim-bookworm
# 设置运行参数
ARG DEBIAN_FRONTEND=noninteractive
# 设置工作目录
WORKDIR /NarratoAI
# 从builder阶段复制虚拟环境
# 从构建阶段复制虚拟环境
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# 安装运行时依赖
RUN apt-get update && apt-get install -y \
# 设置环境变量
ENV PATH="/opt/venv/bin:$PATH" \
PYTHONPATH="/NarratoAI" \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONIOENCODING=utf-8 \
LANG=C.UTF-8 \
LC_ALL=C.UTF-8
# 安装运行时系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
imagemagick \
ffmpeg \
wget \
curl \
git-lfs \
&& rm -rf /var/lib/apt/lists/* \
&& sed -i '/<policy domain="path" rights="none" pattern="@\*"/d' /etc/ImageMagick-6/policy.xml
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# 设置环境变量
ENV PYTHONPATH="/NarratoAI" \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1
# 配置 ImageMagick 策略(允许处理更多格式)
RUN sed -i 's/<policy domain="path" rights="none" pattern="@\*"/<policy domain="path" rights="read|write" pattern="@\*"/' /etc/ImageMagick-6/policy.xml || true
# 设置目录权限
RUN chmod 777 /NarratoAI
# 安装git lfs
# 初始化 git-lfs
RUN git lfs install
# 创建非 root 用户(安全最佳实践)
RUN groupadd -r narratoai && useradd -r -g narratoai -d /NarratoAI -s /bin/bash narratoai
# 复制应用代码
COPY . .
COPY --chown=narratoai:narratoai . .
# 确保配置文件存在
RUN if [ ! -f config.toml ]; then cp config.example.toml config.toml; fi
# 创建必要的目录并设置权限
RUN mkdir -p storage/temp storage/tasks storage/json storage/narration_scripts storage/drama_analysis && \
chown -R narratoai:narratoai /NarratoAI && \
chmod -R 755 /NarratoAI
# 复制并设置入口点脚本
COPY --chown=narratoai:narratoai docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
# 切换到非 root 用户
USER narratoai
# 暴露端口
EXPOSE 8501
# 使用脚本作为入口点
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:8501/_stcore/health || exit 1
# 设置入口点
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["webui"]

63
Makefile Normal file
View File

@ -0,0 +1,63 @@
# NarratoAI Docker Makefile
.PHONY: help build up down restart logs shell clean deploy
# 默认目标
.DEFAULT_GOAL := help
# 变量定义
SERVICE_NAME := narratoai-webui
# 颜色定义
GREEN := \033[32m
YELLOW := \033[33m
BLUE := \033[34m
RESET := \033[0m
help: ## 显示帮助信息
@echo "$(GREEN)NarratoAI Docker 管理命令$(RESET)"
@echo ""
@echo "$(YELLOW)可用命令:$(RESET)"
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " $(BLUE)%-15s$(RESET) %s\n", $$1, $$2}' $(MAKEFILE_LIST)
deploy: ## 一键部署
@echo "$(GREEN)执行一键部署...$(RESET)"
./docker-deploy.sh
build: ## 构建 Docker 镜像
@echo "$(GREEN)构建 Docker 镜像...$(RESET)"
docker-compose build
up: ## 启动服务
@echo "$(GREEN)启动服务...$(RESET)"
docker-compose up -d
@echo "$(GREEN)访问地址: http://localhost:8501$(RESET)"
down: ## 停止服务
@echo "$(YELLOW)停止服务...$(RESET)"
docker-compose down
restart: ## 重启服务
@echo "$(YELLOW)重启服务...$(RESET)"
docker-compose restart
logs: ## 查看日志
docker-compose logs -f
shell: ## 进入容器
docker-compose exec $(SERVICE_NAME) bash
ps: ## 查看服务状态
docker-compose ps
clean: ## 清理未使用的资源
@echo "$(YELLOW)清理未使用的资源...$(RESET)"
docker system prune -f
config: ## 检查配置文件
@if [ -f "config.toml" ]; then \
echo "$(GREEN)config.toml 存在$(RESET)"; \
else \
echo "$(YELLOW)复制示例配置...$(RESET)"; \
cp config.example.toml config.toml; \
fi

View File

@ -1,38 +1,29 @@
x-common: &common
services:
narratoai-webui:
build:
context: .
dockerfile: Dockerfile
image: linyq1/narratoai:latest
volumes:
- ./:/NarratoAI
environment:
- VPN_PROXY_URL=http://host.docker.internal:7890
- PYTHONUNBUFFERED=1
- PYTHONMALLOC=malloc
- OPENCV_OPENCL_RUNTIME=disabled
- OPENCV_CPU_DISABLE=0
restart: always
mem_limit: 4g
mem_reservation: 2g
memswap_limit: 6g
cpus: 2.0
cpu_shares: 1024
image: narratoai:latest
container_name: narratoai-webui
services:
webui:
<<: *common
container_name: webui
ports:
- "8501:8501"
command: ["webui"]
logging:
driver: "json-file"
options:
max-size: "200m"
max-file: "3"
tmpfs:
- /tmp:size=1G
ulimits:
nofile:
soft: 65536
hard: 65536
volumes:
- ./storage:/NarratoAI/storage
- ./config.toml:/NarratoAI/config.toml
- ./resource:/NarratoAI/resource:ro
environment:
- PYTHONUNBUFFERED=1
- TZ=Asia/Shanghai
restart: unless-stopped
# 健康检查
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8501/_stcore/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s

184
docker-deploy.sh Executable file
View File

@ -0,0 +1,184 @@
#!/bin/bash
# NarratoAI Docker 一键部署脚本
set -e
# 颜色定义
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
# 日志函数
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 显示帮助信息
show_help() {
cat << EOF
NarratoAI Docker 一键部署脚本
使用方法:
$0 [选项]
选项:
-h, --help 显示此帮助信息
-b, --build 强制重新构建镜像
--no-cache 构建时不使用缓存
示例:
$0 # 标准部署
$0 -b # 重新构建并部署
$0 --no-cache # 无缓存构建
EOF
}
# 检查系统要求
check_requirements() {
log_info "检查系统要求..."
if ! command -v docker &> /dev/null; then
log_error "Docker 未安装,请先安装 Docker"
exit 1
fi
if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
log_error "Docker Compose 未安装,请先安装 Docker Compose"
exit 1
fi
if ! docker info &> /dev/null; then
log_error "Docker 服务未运行,请启动 Docker"
exit 1
fi
}
# 检查配置文件
check_config() {
if [ ! -f "config.toml" ]; then
if [ -f "config.example.toml" ]; then
log_warning "config.toml 不存在,复制示例配置文件"
cp config.example.toml config.toml
log_info "请编辑 config.toml 文件配置您的 API 密钥"
else
log_error "未找到配置文件模板"
exit 1
fi
fi
}
# 构建镜像
build_image() {
log_info "构建 Docker 镜像..."
local build_args=""
if [ "$NO_CACHE" = "true" ]; then
build_args="--no-cache"
fi
docker-compose build $build_args
}
# 启动服务
start_services() {
log_info "启动 NarratoAI 服务..."
docker-compose down 2>/dev/null || true
docker-compose up -d
}
# 等待服务就绪
wait_for_service() {
log_info "等待服务就绪..."
local max_attempts=30
local attempt=1
while [ $attempt -le $max_attempts ]; do
if curl -f http://localhost:8501/_stcore/health &>/dev/null; then
log_info "服务已就绪"
return 0
fi
sleep 2
((attempt++))
done
log_warning "服务启动超时,请检查日志"
return 1
}
# 显示部署信息
show_deployment_info() {
echo
log_info "NarratoAI 部署完成!"
echo "访问地址: http://localhost:8501"
echo
echo "常用命令:"
echo " 查看日志: docker-compose logs -f"
echo " 停止服务: docker-compose down"
echo " 重启服务: docker-compose restart"
}
# 主函数
main() {
FORCE_BUILD=false
NO_CACHE=false
# 解析命令行参数
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
exit 0
;;
-b|--build)
FORCE_BUILD=true
shift
;;
--no-cache)
NO_CACHE=true
shift
;;
*)
log_error "未知选项: $1"
show_help
exit 1
;;
esac
done
# 执行部署流程
log_info "开始 NarratoAI Docker 部署..."
check_requirements
check_config
if [ "$FORCE_BUILD" = "true" ] || ! docker images | grep -q "narratoai"; then
build_image
fi
start_services
if wait_for_service; then
show_deployment_info
else
log_error "部署失败,请检查日志"
docker-compose logs --tail=20
exit 1
fi
}
# 执行主函数
main "$@"

View File

@ -1,8 +1,87 @@
#!/bin/bash
set -e
if [ "$1" = "webui" ]; then
exec streamlit run webui.py --browser.serverAddress=127.0.0.1 --server.enableCORS=True --browser.gatherUsageStats=False
else
# 函数:打印日志
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
}
# 函数:检查必要的文件和目录
check_requirements() {
log "检查应用环境..."
# 检查配置文件
if [ ! -f "config.toml" ]; then
if [ -f "config.example.toml" ]; then
log "复制示例配置文件..."
cp config.example.toml config.toml
else
log "警告: 未找到配置文件"
fi
fi
# 检查必要的目录
for dir in "storage/temp" "storage/tasks" "storage/json" "storage/narration_scripts" "storage/drama_analysis"; do
if [ ! -d "$dir" ]; then
log "创建目录: $dir"
mkdir -p "$dir"
fi
done
log "环境检查完成"
}
# 函数:启动 WebUI
start_webui() {
log "启动 NarratoAI WebUI..."
# 检查端口是否可用
if command -v netstat >/dev/null 2>&1; then
if netstat -tuln | grep -q ":8501 "; then
log "警告: 端口 8501 已被占用"
fi
fi
# 启动 Streamlit 应用
exec streamlit run webui.py \
--server.address=0.0.0.0 \
--server.port=8501 \
--server.enableCORS=true \
--server.maxUploadSize=2048 \
--server.enableXsrfProtection=false \
--browser.gatherUsageStats=false \
--browser.serverAddress=0.0.0.0 \
--logger.level=info
}
# 主逻辑
log "NarratoAI Docker 容器启动中..."
# 检查环境
check_requirements
# 根据参数执行不同的命令
case "$1" in
"webui"|"")
start_webui
;;
"bash"|"sh")
log "启动交互式 shell..."
exec /bin/bash
;;
"health")
# 健康检查命令
log "执行健康检查..."
if curl -f http://localhost:8501/_stcore/health >/dev/null 2>&1; then
log "健康检查通过"
exit 0
else
log "健康检查失败"
exit 1
fi
;;
*)
log "执行自定义命令: $*"
exec "$@"
fi
;;
esac

View File

@ -1,45 +1,35 @@
# 必须项
requests~=2.32.0
# 核心依赖
requests>=2.32.0
moviepy==2.1.1
edge-tts==6.1.19
streamlit~=1.45.0
streamlit>=1.45.0
watchdog==6.0.0
loguru~=0.7.3
tomli~=2.2.1
loguru>=0.7.3
tomli>=2.2.1
tomli-w>=1.0.0
pydub==0.25.1
pysrt==1.1.2
openai~=1.77.0
# AI 服务依赖
openai>=1.77.0
google-generativeai>=0.8.5
azure-cognitiveservices-speech~=1.37.0
azure-cognitiveservices-speech>=1.37.0
# 待优化项
# opencv-python==4.11.0.86
# scikit-learn==1.6.1
# 图像处理依赖
Pillow>=10.3.0
# 进度条和重试机制
tqdm>=4.66.6
tenacity>=9.0.0
# 可选依赖(根据功能需要)
# 如果需要本地语音识别,取消注释下面的行
# faster-whisper>=1.0.1
# faster-whisper~=1.0.1
# tomli~=2.0.1
# aiohttp~=3.10.10
# httpx==0.27.2
# urllib3~=2.2.1
# 如果需要 OpenCV 图像处理,取消注释下面的行
# opencv-python>=4.11.0.86
# python-multipart~=0.0.9
# redis==5.0.3
# opencv-python~=4.10.0.84
# git-changelog~=2.5.2
# watchdog==5.0.2
# pydub==0.25.1
# psutil>=5.9.0
# scikit-learn~=1.5.2
# pillow==10.3.0
# python-dotenv~=1.0.1
# tqdm>=4.66.6
# tenacity>=9.0.0
# tiktoken==0.8.0
# pysrt==1.1.2
# transformers==4.50.0
# yt-dlp==2025.4.30
# 如果需要 CUDA 支持,取消注释下面的行
# torch>=2.0.0
# torchvision>=0.15.0
# torchaudio>=2.0.0