提交 68eccb4b authored 作者: 陈泽健's avatar 陈泽健

feat(deploy): 添加容器化部署配置文件(Docker/Nginx/Compose/部署脚本)

- deploy/Dockerfile.backend: 后端镜像(Python 3.10-slim + Playwright)
- deploy/Dockerfile.frontend: 前端多阶段构建(node:20 → nginx:alpine)
- deploy/nginx/default.conf: Nginx 反向代理(API + WebSocket)
- deploy/docker-compose.yml: 服务编排(健康检查 + 启动顺序)
- deploy/.env.example: 环境变量模板
- deploy/deploy.sh: 一键部署脚本
Co-Authored-By: 's avatarClaude <noreply@anthropic.com>
上级 03c3466f
# 环境变量配置
# 复制此文件为 .env 并根据需要修改
# 数据库连接
DATABASE_URL=sqlite+aiosqlite:///./data/test_platform.db
# Playwright 配置
PLAYWRIGHT_HEADLESS=true
PLAYWRIGHT_TIMEOUT=30000
# 日志级别
LOG_LEVEL=INFO
\ No newline at end of file
FROM python:3.10-slim
WORKDIR /app
# 安装 Playwright 系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
wget \
gnupg \
libnss3 \
libnspr4 \
libatk1.0-0t64 \
libatk-bridge2.0-0t64 \
libcups2t64 \
libdrm2 \
libdbus-1-3 \
libxkbcommon0 \
libxcomposite1 \
libxdamage1 \
libxfixes3 \
libxrandr2 \
libgbm1 \
libpango-1.0-0 \
libcairo2 \
libasound2t64 \
&& rm -rf /var/lib/apt/lists/*
# 安装 Python 依赖
COPY backend/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 安装 Playwright Chromium(Linux 版本)
RUN playwright install chromium
# 复制后端代码
COPY backend/ .
# 创建数据目录
RUN mkdir -p /app/data/screenshots /app/data/reports
# 暴露端口
EXPOSE 8001
# 启动命令(单 worker,SQLite 不支持多 worker 并发)
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8001"]
\ No newline at end of file
# ---- 构建阶段 ----
FROM node:20-alpine AS build
WORKDIR /app
# 安装依赖
COPY frontend/package.json frontend/package-lock.json ./
RUN npm ci
# 复制源码并构建
COPY frontend/ .
RUN npm run build
# ---- 运行阶段 ----
FROM nginx:alpine
# 复制构建产物
COPY --from=build /app/dist /usr/share/nginx/html
# 复制 Nginx 配置
COPY deploy/nginx/default.conf /etc/nginx/conf.d/default.conf
# 暴露端口
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
\ No newline at end of file
#!/bin/bash
set -e
echo "============================================"
echo " 平台自动化测试系统 - Docker 部署脚本"
echo "============================================"
echo ""
# 检查 Docker
if ! command -v docker &> /dev/null; then
echo "❌ 错误: Docker 未安装"
echo " 请先安装 Docker: sudo apt-get install -y docker.io docker-compose-v2"
echo " 或参考: https://docs.docker.com/engine/install/"
exit 1
fi
# 检查 Docker Compose
if ! docker compose version &> /dev/null; then
echo "❌ 错误: Docker Compose 未安装"
exit 1
fi
# 获取脚本所在目录
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
echo "📁 项目目录: $PROJECT_DIR"
echo ""
# 创建数据目录
echo "📂 创建数据目录..."
mkdir -p "$PROJECT_DIR/data/screenshots" "$PROJECT_DIR/data/reports"
echo " ✅ 数据目录已就绪"
# 构建镜像
echo ""
echo "📦 构建 Docker 镜像..."
cd "$SCRIPT_DIR"
docker compose build
echo " ✅ 镜像构建完成"
# 启动服务
echo ""
echo "🚀 启动服务..."
docker compose up -d
echo " ✅ 服务已启动"
# 等待服务就绪
echo ""
echo "⏳ 等待服务就绪..."
sleep 10
# 健康检查
echo ""
echo "🔍 执行健康检查..."
MAX_RETRIES=6
RETRY_COUNT=0
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
HEALTH=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8001/health 2>/dev/null || echo "000")
if [ "$HEALTH" = "200" ]; then
echo " ✅ 后端健康检查通过 (HTTP 200)"
break
fi
RETRY_COUNT=$((RETRY_COUNT + 1))
if [ $RETRY_COUNT -lt $MAX_RETRIES ]; then
echo " ⏳ 等待后端就绪... ($RETRY_COUNT/$MAX_RETRIES)"
sleep 5
fi
done
if [ $RETRY_COUNT -ge $MAX_RETRIES ]; then
echo " ⚠️ 后端健康检查超时,请检查日志: docker compose logs backend"
fi
# 检查前端
FRONTEND_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost/ 2>/dev/null || echo "000")
if [ "$FRONTEND_CODE" = "200" ]; then
echo " ✅ 前端可访问 (HTTP 200)"
else
echo " ⚠️ 前端响应码: $FRONTEND_CODE"
fi
# 检查已有服务是否受影响
TROUBLESHOOT_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8088/ 2>/dev/null || echo "000")
echo " ℹ️ 已有故障排查平台 (8088): HTTP $TROUBLESHOOT_CODE"
# 输出访问信息
echo ""
echo "============================================"
echo " ✅ 部署完成!"
echo "============================================"
echo ""
echo " 前端: http://$(curl -s ifconfig.me 2>/dev/null || hostname -I 2>/dev/null | awk '{print $1}' || echo 'localhost')"
echo " API 文档: http://localhost:8001/docs"
echo ""
echo " 已有故障排查平台: http://localhost:8088(不受影响)"
echo ""
echo " 📋 查看日志: docker compose logs -f"
echo " 🛑 停止服务: docker compose down"
echo " 🔄 重启服务: docker compose restart"
echo ""
# 检查容器状态
echo "📊 容器状态:"
docker compose ps
\ No newline at end of file
version: "3.8"
services:
backend:
build:
context: ..
dockerfile: deploy/Dockerfile.backend
container_name: plat-auto-test-backend
ports:
- "8001:8001"
volumes:
- ../data:/app/data
environment:
- DATABASE_URL=sqlite+aiosqlite:///./data/test_platform.db
- PLAYWRIGHT_HEADLESS=true
- PLAYWRIGHT_TIMEOUT=30000
- LOG_LEVEL=INFO
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8001/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
frontend:
build:
context: ..
dockerfile: deploy/Dockerfile.frontend
container_name: plat-auto-test-frontend
ports:
- "80:80"
depends_on:
backend:
condition: service_healthy
restart: unless-stopped
\ No newline at end of file
server {
listen 80;
server_name _;
# 前端静态文件
root /usr/share/nginx/html;
index index.html;
# SPA 路由(所有非文件路径回退到 index.html)
location / {
try_files $uri $uri/ /index.html;
}
# API 反向代理到后端
location /api/ {
proxy_pass http://backend:8001;
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_read_timeout 300s;
proxy_send_timeout 300s;
}
# WebSocket 反向代理(用于执行进度推送)
location /api/executions/ws/ {
proxy_pass http://backend:8001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400s;
}
# 文件服务(截图等)
location /api/files/ {
proxy_pass http://backend:8001;
proxy_set_header Host $host;
}
# 静态资源缓存(JS/CSS/图片等)
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 7d;
add_header Cache-Control "public, immutable";
}
}
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论