feat: Docker化部署 - 單容器架構轉換
將 Tool_OCR 從 macOS conda 環境轉換為 Docker 單容器部署方案。 前後端整合於同一容器,通過 Nginx 反向代理,僅對外暴露單一端口。 ## 新增功能 - Docker 單容器架構(Frontend + Backend + Nginx) - 多階段構建優化鏡像大小 - Supervisor 進程管理 - 健康檢查機制 - 完整部署文檔 ## 技術細節 - 對外端口:12015(原 12010 已被佔用) - 內部架構:Nginx(12015) → FastAPI(8000) - 前端靜態文件由 Nginx 直接服務 - API 請求通過 Nginx 反向代理 ## 系統依賴完善 - libmagic1:文件類型檢測 - LibreOffice:Office 文檔轉換 - paddlex[ocr]:PP-StructureV3 版面分析 - 中日韓字體支援 ## 配置調整 - 環境變數路徑:macOS 路徑 → 容器絕對路徑 - 前端 API URL:修正為統一端口 12015 - Pip 安裝:延長超時至 600 秒,重試 5 次 - CRLF 轉換:自動處理 Windows 換行符 ## 清理 - 移除臨時文檔(API_FIX_SUMMARY.md 等 7 個文檔) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
89
docker/default.conf
Normal file
89
docker/default.conf
Normal file
@@ -0,0 +1,89 @@
|
||||
# Nginx Site Configuration for Tool_OCR
|
||||
|
||||
upstream backend {
|
||||
server 127.0.0.1:8000;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 12015;
|
||||
server_name _;
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# Root directory for frontend
|
||||
root /app/frontend/dist;
|
||||
index index.html;
|
||||
|
||||
# Logging
|
||||
access_log /var/log/nginx/tool_ocr_access.log;
|
||||
error_log /var/log/nginx/tool_ocr_error.log;
|
||||
|
||||
# Backend API proxy
|
||||
location /api/ {
|
||||
proxy_pass http://backend/api/;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
# Headers
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Connection "";
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
|
||||
# Buffering
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
|
||||
# Health check endpoint (backend)
|
||||
location /health {
|
||||
proxy_pass http://backend/health;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Connection "";
|
||||
}
|
||||
|
||||
# API docs (backend)
|
||||
location /docs {
|
||||
proxy_pass http://backend/docs;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Connection "";
|
||||
}
|
||||
|
||||
location /openapi.json {
|
||||
proxy_pass http://backend/openapi.json;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Connection "";
|
||||
}
|
||||
|
||||
# Frontend static files with caching
|
||||
location /assets/ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Frontend - React Router support (SPA fallback)
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
expires -1;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
}
|
||||
|
||||
# Deny access to hidden files
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
}
|
||||
41
docker/entrypoint.sh
Normal file
41
docker/entrypoint.sh
Normal file
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "========================================"
|
||||
echo "Tool_OCR Container Starting..."
|
||||
echo "========================================"
|
||||
|
||||
# Wait a moment for system to stabilize
|
||||
sleep 2
|
||||
|
||||
# Run database migrations if needed
|
||||
echo "Checking database migrations..."
|
||||
cd /app/backend
|
||||
if [ -f "alembic.ini" ]; then
|
||||
echo "Running Alembic migrations..."
|
||||
alembic upgrade head || echo "Warning: Migration failed or already up to date"
|
||||
fi
|
||||
|
||||
# Create necessary directories if they don't exist
|
||||
echo "Ensuring directories exist..."
|
||||
mkdir -p \
|
||||
/app/backend/uploads/temp \
|
||||
/app/backend/uploads/processed \
|
||||
/app/backend/uploads/images \
|
||||
/app/backend/storage/markdown \
|
||||
/app/backend/storage/json \
|
||||
/app/backend/storage/exports \
|
||||
/app/backend/models/paddleocr \
|
||||
/app/backend/logs
|
||||
|
||||
# Set permissions
|
||||
chmod -R 755 /app/backend/uploads /app/backend/storage /app/backend/logs
|
||||
|
||||
echo "========================================"
|
||||
echo "Starting services with Supervisor..."
|
||||
echo "- Nginx listening on port 12015"
|
||||
echo "- Backend API on internal port 8000"
|
||||
echo "========================================"
|
||||
|
||||
# Start supervisord
|
||||
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||
40
docker/nginx.conf
Normal file
40
docker/nginx.conf
Normal file
@@ -0,0 +1,40 @@
|
||||
# Nginx Main Configuration
|
||||
user www-data;
|
||||
worker_processes auto;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
use epoll;
|
||||
}
|
||||
|
||||
http {
|
||||
# Basic Settings
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
client_max_body_size 50M; # Match MAX_UPLOAD_SIZE in .env
|
||||
|
||||
# MIME Types
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# Logging
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
# Gzip Compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types text/plain text/css text/xml text/javascript
|
||||
application/json application/javascript application/xml+rss
|
||||
application/rss+xml font/truetype font/opentype
|
||||
application/vnd.ms-fontobject image/svg+xml;
|
||||
|
||||
# Include site configurations
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
28
docker/supervisord.conf
Normal file
28
docker/supervisord.conf
Normal file
@@ -0,0 +1,28 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
user=root
|
||||
logfile=/var/log/supervisor/supervisord.log
|
||||
pidfile=/var/run/supervisord.pid
|
||||
loglevel=info
|
||||
|
||||
[program:nginx]
|
||||
command=/usr/sbin/nginx -g "daemon off;"
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=10
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:backend]
|
||||
command=python -m uvicorn app.main:app --host 127.0.0.1 --port 8000 --log-level info
|
||||
directory=/app/backend
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=20
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
environment=PYTHONUNBUFFERED="1"
|
||||
Reference in New Issue
Block a user