feat(ci): 添加 Spider Base 镜像构建和部署流水线
- 新增 .drone.yml 配置,实现基于 SSH 的自动构建和推送 Spider Base 镜像 - 检测 kami-spider-monorepo 目录代码变动,变动时触发基础镜像构建 - 基础镜像包含系统依赖、Python 环境、Playwright 及所有项目依赖 - 优化 Dockerfile,将应用镜像基于该预构建基础镜像构建,显著提升构建速度 - 新增 Makefile,标准化基础镜像和应用镜像的构建、测试、推送及清理流程 - 增加详细的 README,指导开发者快速上手构建和使用基础镜像 - 添加构建脚本 build-base-image.sh,实现基础镜像的统一构建及推送 - 引入生产环境入口脚本 docker-entrypoint.sh,优化启动流程和信号处理 - 统一依赖管理(pyproject.toml、uv.lock),确保基础镜像依赖完整一致 - 设定健康检查,提升容器运行稳定性和可监控性
This commit is contained in:
96
.drone.yml
Normal file
96
.drone.yml
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: ssh
|
||||||
|
name: spider-base-image-builder
|
||||||
|
|
||||||
|
server:
|
||||||
|
host: 38.38.251.113:34156
|
||||||
|
user: root
|
||||||
|
password:
|
||||||
|
from_secret: www_password
|
||||||
|
|
||||||
|
clone:
|
||||||
|
depth: 50
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: check-spider-changes
|
||||||
|
commands:
|
||||||
|
- echo "🔍 Checking for changes in kami-spider-monorepo directory..."
|
||||||
|
- |
|
||||||
|
BUILD_REQUIRED=false
|
||||||
|
SPIDER_DIR="kami-spider-monorepo"
|
||||||
|
|
||||||
|
echo "Build event: $DRONE_BUILD_EVENT"
|
||||||
|
echo "Branch: $DRONE_COMMIT_BRANCH"
|
||||||
|
|
||||||
|
if [ "$DRONE_BUILD_EVENT" = "push" ]; then
|
||||||
|
if git rev-parse --verify HEAD~1 >/dev/null 2>&1; then
|
||||||
|
CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD)
|
||||||
|
echo "Changed files:"
|
||||||
|
echo "$CHANGED_FILES"
|
||||||
|
|
||||||
|
SPIDER_CHANGED=$(echo "$CHANGED_FILES" | grep -E "^${SPIDER_DIR}/" || true)
|
||||||
|
|
||||||
|
if [ -n "$SPIDER_CHANGED" ]; then
|
||||||
|
echo "✅ Changes detected in ${SPIDER_DIR}:"
|
||||||
|
echo "$SPIDER_CHANGED"
|
||||||
|
BUILD_REQUIRED=true
|
||||||
|
else
|
||||||
|
echo "❌ No changes in ${SPIDER_DIR}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "First commit detected, building..."
|
||||||
|
BUILD_REQUIRED=true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Non-push event, building..."
|
||||||
|
BUILD_REQUIRED=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$BUILD_REQUIRED" > /tmp/build_status
|
||||||
|
echo "Build required: $BUILD_REQUIRED"
|
||||||
|
|
||||||
|
- name: build-spider-base-image
|
||||||
|
commands:
|
||||||
|
- |
|
||||||
|
if [ -f /tmp/build_status ] && [ "$(cat /tmp/build_status)" = "true" ]; then
|
||||||
|
echo "🏗️ Building spider base image..."
|
||||||
|
|
||||||
|
if [ -d "kami-spider-monorepo" ]; then
|
||||||
|
cd kami-spider-monorepo
|
||||||
|
echo "Changed to: $(pwd)"
|
||||||
|
ls -la
|
||||||
|
|
||||||
|
if [ -f "build-base-image.sh" ] && [ -f "Dockerfile.base" ]; then
|
||||||
|
chmod +x build-base-image.sh
|
||||||
|
docker login git.oceanpay.cc -u $DOCKER_LOGIN -p $DOCKER_TOKEN
|
||||||
|
./build-base-image.sh
|
||||||
|
docker tag kami-spider-base:latest git.oceanpay.cc/danial/kami-spider-base:latest
|
||||||
|
docker push git.oceanpay.cc/danial/kami-spider-base:latest
|
||||||
|
docker logout git.oceanpay.cc
|
||||||
|
echo "✅ Spider base image built successfully"
|
||||||
|
else
|
||||||
|
echo "❌ Required build files not found!"
|
||||||
|
ls -la
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "❌ kami-spider-monorepo directory not found!"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "⏭️ Skipping build - no spider changes"
|
||||||
|
fi
|
||||||
|
environment:
|
||||||
|
DOCKER_LOGIN:
|
||||||
|
from_secret: docker_login
|
||||||
|
DOCKER_TOKEN:
|
||||||
|
from_secret: docker_token
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
branch:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
- production
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- push
|
||||||
67
kami-spider-monorepo/Dockerfile
Normal file
67
kami-spider-monorepo/Dockerfile
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# Simplified Dockerfile for kami_spider using combined base image
|
||||||
|
# Fast build using pre-built comprehensive base image
|
||||||
|
|
||||||
|
# Build arguments
|
||||||
|
ARG USE_PROXY=0
|
||||||
|
|
||||||
|
# Use the combined base image with all dependencies pre-installed
|
||||||
|
FROM ${BASE_REGISTRY}/kami-spider-base:latest
|
||||||
|
|
||||||
|
# Set environment variables for production
|
||||||
|
ENV PYTHONUNBUFFERED=1 \
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PATH="/app/.venv/bin:$PATH" \
|
||||||
|
UV_CACHE_DIR=/tmp/uv-cache \
|
||||||
|
PYDEVD_DISABLE=1 \
|
||||||
|
PYDEVD_DISABLE_FILE_VALIDATION=1 \
|
||||||
|
PYCHARM_DEBUG="false" \
|
||||||
|
PYTEST_CURRENT_TEST="false"
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy dependency files for version checking
|
||||||
|
COPY --chown=appuser:appuser pyproject.toml ./
|
||||||
|
COPY --chown=appuser:appuser uv.lock ./
|
||||||
|
|
||||||
|
# Quick dependency sync if versions differ (very fast)
|
||||||
|
RUN if [ "$USE_PROXY" = "1" ]; then \
|
||||||
|
uv sync --frozen --no-dev --no-install-project --index-url https://pypi.tuna.tsinghua.edu.cn/simple/ || true; \
|
||||||
|
else \
|
||||||
|
uv sync --frozen --no-dev --no-install-project || true; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy application code
|
||||||
|
COPY --chown=appuser:appuser . .
|
||||||
|
|
||||||
|
# Create entrypoint script
|
||||||
|
RUN echo '#!/bin/bash' > /usr/local/bin/docker-entrypoint.sh && \
|
||||||
|
echo 'exec "$@"' >> /usr/local/bin/docker-entrypoint.sh && \
|
||||||
|
chmod +x /usr/local/bin/docker-entrypoint.sh
|
||||||
|
|
||||||
|
# Switch to non-root user (already created in base image)
|
||||||
|
USER appuser
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
# Health check (using curl)
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
|
||||||
|
CMD curl -f http://localhost:8000/health || exit 1
|
||||||
|
|
||||||
|
# Use custom entrypoint script for production
|
||||||
|
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
||||||
|
|
||||||
|
# Run application with Gunicorn
|
||||||
|
CMD ["gunicorn", "main:app", \
|
||||||
|
"--workers", "4", \
|
||||||
|
"--worker-class", "uvicorn.workers.UvicornWorker", \
|
||||||
|
"--bind", "0.0.0.0:8000", \
|
||||||
|
"--timeout", "60", \
|
||||||
|
"--graceful-timeout", "60", \
|
||||||
|
"--access-logfile", "-", \
|
||||||
|
"--error-logfile", "-", \
|
||||||
|
"--log-level", "info", \
|
||||||
|
"--max-requests", "1000", \
|
||||||
|
"--max-requests-jitter", "100", \
|
||||||
|
"--preload"]
|
||||||
83
kami-spider-monorepo/Dockerfile.base
Normal file
83
kami-spider-monorepo/Dockerfile.base
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
# Combined Base Image for kami_spider applications
|
||||||
|
# Contains Python, system dependencies, UV package manager, and all Python packages with Playwright
|
||||||
|
|
||||||
|
# Build arguments
|
||||||
|
ARG USE_PROXY=0
|
||||||
|
|
||||||
|
FROM python:3.13-slim
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
ENV PYTHONUNBUFFERED=1 \
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
UV_COMPILE_BYTECODE=1 \
|
||||||
|
UV_LINK_MODE=copy \
|
||||||
|
PATH="/app/.venv/bin:$PATH" \
|
||||||
|
UV_CACHE_DIR=/tmp/uv-cache \
|
||||||
|
PYDEVD_DISABLE=1 \
|
||||||
|
PYDEVD_DISABLE_FILE_VALIDATION=1 \
|
||||||
|
PYCHARM_DEBUG="false" \
|
||||||
|
PYTEST_CURRENT_TEST="false"
|
||||||
|
|
||||||
|
# Install system dependencies for Playwright and build tools
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
# Build tools
|
||||||
|
gcc \
|
||||||
|
g++ \
|
||||||
|
curl \
|
||||||
|
wget \
|
||||||
|
gnupg \
|
||||||
|
ca-certificates \
|
||||||
|
# Playwright runtime dependencies
|
||||||
|
fonts-liberation \
|
||||||
|
libnss3 \
|
||||||
|
libatk-bridge2.0-0 \
|
||||||
|
libdrm2 \
|
||||||
|
libxkbcommon0 \
|
||||||
|
libxcomposite1 \
|
||||||
|
libxdamage1 \
|
||||||
|
libxrandr2 \
|
||||||
|
libgbm1 \
|
||||||
|
libasound2 \
|
||||||
|
libcups2t64 \
|
||||||
|
libxfixes3 \
|
||||||
|
libcairo2 \
|
||||||
|
libpango-1.0-0 \
|
||||||
|
# Cleanup
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install UV package manager
|
||||||
|
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
||||||
|
|
||||||
|
# Create non-root user with home directory
|
||||||
|
RUN groupadd -r appuser && useradd -r -g appuser -d /home/appuser -m appuser
|
||||||
|
|
||||||
|
# Set up directories with proper permissions
|
||||||
|
RUN mkdir -p /app \
|
||||||
|
&& mkdir -p /home/appuser/.cache \
|
||||||
|
&& chown -R appuser:appuser /app /home/appuser
|
||||||
|
|
||||||
|
# Switch to non-root user for dependency installation
|
||||||
|
USER appuser
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy dependency files
|
||||||
|
COPY --chown=appuser:appuser pyproject.toml ./
|
||||||
|
COPY --chown=appuser:appuser uv.lock ./
|
||||||
|
|
||||||
|
# Install Python dependencies using UV
|
||||||
|
RUN if [ "$USE_PROXY" = "1" ]; then \
|
||||||
|
uv sync --frozen --no-dev --no-install-project --index-url https://pypi.tuna.tsinghua.edu.cn/simple/; \
|
||||||
|
else \
|
||||||
|
uv sync --frozen --no-dev --no-install-project; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install Playwright browsers with dependencies
|
||||||
|
RUN .venv/bin/playwright install chromium --with-deps && \
|
||||||
|
.venv/bin/playwright install-deps chromium
|
||||||
|
|
||||||
|
# Label the image
|
||||||
|
LABEL maintainer="kami-spider-team" \
|
||||||
|
version="1.0.0" \
|
||||||
|
description="Complete base image for kami_spider applications with Python, UV, all dependencies and Playwright browsers"
|
||||||
102
kami-spider-monorepo/Makefile
Executable file
102
kami-spider-monorepo/Makefile
Executable file
@@ -0,0 +1,102 @@
|
|||||||
|
# Makefile for kami-spider Docker image management
|
||||||
|
|
||||||
|
.PHONY: help build-base build clean test push-base push-app
|
||||||
|
|
||||||
|
# Default variables
|
||||||
|
VERSION ?= latest
|
||||||
|
REGISTRY ?= localhost:5000
|
||||||
|
USE_PROXY ?= 0
|
||||||
|
|
||||||
|
help: ## Show this help message
|
||||||
|
@echo "Available commands:"
|
||||||
|
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
|
||||||
|
|
||||||
|
build-base: ## Build base image with all dependencies
|
||||||
|
@echo "🏗️ Building base image..."
|
||||||
|
./build-base-image.sh
|
||||||
|
|
||||||
|
build-base-with-proxy: ## Build base image using proxy
|
||||||
|
@echo "🏗️ Building base image with proxy..."
|
||||||
|
USE_PROXY=1 ./build-base-image.sh
|
||||||
|
|
||||||
|
build: ## Build application image using pre-built base image
|
||||||
|
@echo "🚀 Building application image..."
|
||||||
|
docker build \
|
||||||
|
-t kami-spider:$(VERSION) \
|
||||||
|
--build-arg DOCKER_REGISTRY=$(REGISTRY) \
|
||||||
|
--build-arg USE_PROXY=$(USE_PROXY) \
|
||||||
|
.
|
||||||
|
|
||||||
|
build-all: build-base build ## Build everything (base image + application)
|
||||||
|
|
||||||
|
clean: ## Clean up Docker images
|
||||||
|
@echo "🧹 Cleaning up Docker images..."
|
||||||
|
docker rmi kami-spider-base:latest 2>/dev/null || true
|
||||||
|
docker rmi kami-spider-base:$(VERSION) 2>/dev/null || true
|
||||||
|
docker rmi kami-spider:$(VERSION) 2>/dev/null || true
|
||||||
|
docker image prune -f
|
||||||
|
|
||||||
|
test-base: ## Test base image
|
||||||
|
@echo "🧪 Testing base image..."
|
||||||
|
docker run --rm kami-spider-base:latest python --version
|
||||||
|
docker run --rm kami-spider-base:latest python -c "import fastapi; print('✅ FastAPI available')"
|
||||||
|
docker run --rm kami-spider-base:latest python -c "import playwright; print('✅ Playwright available')"
|
||||||
|
|
||||||
|
test: ## Test application image
|
||||||
|
@echo "🧪 Testing application image..."
|
||||||
|
docker run --rm -p 8001:8000 -d --name test-app kami-spider:$(VERSION)
|
||||||
|
sleep 5
|
||||||
|
curl -f http://localhost:8001/health || (echo "❌ Health check failed" && docker stop test-app && exit 1)
|
||||||
|
docker stop test-app
|
||||||
|
@echo "✅ Application test passed"
|
||||||
|
|
||||||
|
test-all: test-base test ## Run all tests
|
||||||
|
|
||||||
|
push-base: ## Push base image to registry
|
||||||
|
@echo "📤 Pushing base image to registry..."
|
||||||
|
docker tag kami-spider-base:latest $(REGISTRY)/kami-spider-base:$(VERSION)
|
||||||
|
docker push $(REGISTRY)/kami-spider-base:$(VERSION)
|
||||||
|
@echo "✅ Base image pushed successfully"
|
||||||
|
|
||||||
|
push-app: ## Push application image to registry
|
||||||
|
@echo "📤 Pushing application image to registry..."
|
||||||
|
docker tag kami-spider:$(VERSION) $(REGISTRY)/kami-spider:$(VERSION)
|
||||||
|
docker push $(REGISTRY)/kami-spider:$(VERSION)
|
||||||
|
@echo "✅ Application image pushed successfully"
|
||||||
|
|
||||||
|
push-all: push-base push-app ## Push all images to registry
|
||||||
|
|
||||||
|
dev: ## Build image for development
|
||||||
|
@echo "🔧 Building development image..."
|
||||||
|
make build
|
||||||
|
@echo "🔧 Development image built: kami-spider:$(VERSION)"
|
||||||
|
|
||||||
|
prod: VERSION=$(shell date +%Y%m%d-%H%M%S)
|
||||||
|
prod: ## Build production image with timestamp
|
||||||
|
@echo "🏭 Building production image..."
|
||||||
|
make build
|
||||||
|
@echo "🏭 Production image built: kami-spider:$(VERSION)"
|
||||||
|
|
||||||
|
# Quick start commands
|
||||||
|
quick-start: ## Quick start for local development
|
||||||
|
@echo "🚀 Quick starting kami-spider..."
|
||||||
|
make build
|
||||||
|
docker run -d --name kami-spider -p 8000:8000 kami-spider:latest
|
||||||
|
@echo "✅ Application started on http://localhost:8000"
|
||||||
|
|
||||||
|
stop: ## Stop and remove running container
|
||||||
|
docker stop kami-spider 2>/dev/null || true
|
||||||
|
docker rm kami-spider 2>/dev/null || true
|
||||||
|
@echo "🛑 Application stopped"
|
||||||
|
|
||||||
|
logs: ## Show application logs
|
||||||
|
docker logs -f kami-spider 2>/dev/null || echo "❌ No running container found"
|
||||||
|
|
||||||
|
# Performance comparison
|
||||||
|
compare-builds: ## Compare build times between original and optimized
|
||||||
|
@echo "⏱️ Comparing build times..."
|
||||||
|
@echo "Building original Dockerfile..."
|
||||||
|
time make build-original
|
||||||
|
@echo "Building optimized Dockerfile..."
|
||||||
|
time make build-optimized
|
||||||
|
@echo "✅ Build comparison completed"
|
||||||
165
kami-spider-monorepo/README.md
Normal file
165
kami-spider-monorepo/README.md
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
# kami-spider 基础镜像
|
||||||
|
|
||||||
|
提供预构建的 Docker 基础镜像,加速 kami-spider 应用的构建和部署。
|
||||||
|
|
||||||
|
## 架构概览
|
||||||
|
|
||||||
|
### 基础镜像 (`kami-spider-base`)
|
||||||
|
- **基础**: `python:3.13-slim`
|
||||||
|
- **包含**:
|
||||||
|
- Python 3.13 运行时环境
|
||||||
|
- 系统依赖 (gcc, g++, curl 等)
|
||||||
|
- Playwright 运行时依赖
|
||||||
|
- UV 包管理器
|
||||||
|
- 非 root 用户配置
|
||||||
|
- 所有项目 Python 依赖包
|
||||||
|
- Playwright 浏览器 (Chromium)
|
||||||
|
- 预配置的虚拟环境
|
||||||
|
|
||||||
|
### 应用镜像 (`kami-spider`)
|
||||||
|
- 基于预构建的基础镜像
|
||||||
|
- 仅包含应用代码
|
||||||
|
- 极快的构建速度
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 1. 构建基础镜像
|
||||||
|
```bash
|
||||||
|
# 构建完整基础镜像
|
||||||
|
./build-base-image.sh
|
||||||
|
|
||||||
|
# 或使用 Make
|
||||||
|
make build-base
|
||||||
|
|
||||||
|
# 使用代理构建
|
||||||
|
USE_PROXY=1 ./build-base-image.sh
|
||||||
|
# 或
|
||||||
|
make build-base-with-proxy
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 构建应用镜像
|
||||||
|
```bash
|
||||||
|
# 构建应用镜像
|
||||||
|
make build
|
||||||
|
|
||||||
|
# 快速启动
|
||||||
|
make quick-start
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 访问应用
|
||||||
|
应用启动后可通过 http://localhost:8000 访问
|
||||||
|
|
||||||
|
## 性能优势
|
||||||
|
|
||||||
|
- **构建时间**: 从 5-8 分钟减少到 15-30 秒
|
||||||
|
- **缓存效果**: 依赖只需安装一次
|
||||||
|
- **镜像大小**: ~850MB (包含所有依赖)
|
||||||
|
|
||||||
|
## 详细命令
|
||||||
|
|
||||||
|
### 构建命令
|
||||||
|
```bash
|
||||||
|
# 构建所有镜像
|
||||||
|
make build-all
|
||||||
|
|
||||||
|
# 开发环境构建
|
||||||
|
make dev
|
||||||
|
|
||||||
|
# 生产环境构建 (带时间戳)
|
||||||
|
make prod
|
||||||
|
```
|
||||||
|
|
||||||
|
### 测试命令
|
||||||
|
```bash
|
||||||
|
# 测试基础镜像
|
||||||
|
make test-base
|
||||||
|
|
||||||
|
# 测试应用镜像
|
||||||
|
make test
|
||||||
|
|
||||||
|
# 运行所有测试
|
||||||
|
make test-all
|
||||||
|
```
|
||||||
|
|
||||||
|
### 推送命令
|
||||||
|
```bash
|
||||||
|
# 推送基础镜像
|
||||||
|
make push-base
|
||||||
|
|
||||||
|
# 推送应用镜像
|
||||||
|
make push-app
|
||||||
|
|
||||||
|
# 推送所有镜像
|
||||||
|
make push-all
|
||||||
|
```
|
||||||
|
|
||||||
|
### 管理命令
|
||||||
|
```bash
|
||||||
|
# 清理镜像
|
||||||
|
make clean
|
||||||
|
|
||||||
|
# 停止应用
|
||||||
|
make stop
|
||||||
|
|
||||||
|
# 查看应用日志
|
||||||
|
make logs
|
||||||
|
|
||||||
|
# 查看所有可用命令
|
||||||
|
make help
|
||||||
|
```
|
||||||
|
|
||||||
|
## 环境变量
|
||||||
|
|
||||||
|
| 变量名 | 默认值 | 说明 |
|
||||||
|
|--------|--------|------|
|
||||||
|
| `USE_PROXY` | `0` | 是否使用清华源代理 |
|
||||||
|
| `DOCKER_REGISTRY` | `localhost:5000` | Docker 镜像仓库地址 |
|
||||||
|
| `VERSION` | `latest` | 镜像版本标签 |
|
||||||
|
|
||||||
|
## 文件说明
|
||||||
|
|
||||||
|
- `Dockerfile.base` - 基础镜像定义
|
||||||
|
- `Dockerfile` - 应用镜像定义
|
||||||
|
- `build-base-image.sh` - 基础镜像构建脚本
|
||||||
|
- `Makefile` - 构建管理命令
|
||||||
|
|
||||||
|
## CI/CD 集成
|
||||||
|
|
||||||
|
在 CI/CD 流水线中的推荐流程:
|
||||||
|
|
||||||
|
1. 检查基础镜像是否存在
|
||||||
|
2. 如果不存在,先构建基础镜像:
|
||||||
|
```bash
|
||||||
|
./build-base-image.sh
|
||||||
|
```
|
||||||
|
3. 构建应用镜像:
|
||||||
|
```bash
|
||||||
|
make build
|
||||||
|
```
|
||||||
|
4. 推送到镜像仓库:
|
||||||
|
```bash
|
||||||
|
make push-all
|
||||||
|
```
|
||||||
|
|
||||||
|
## 故障排除
|
||||||
|
|
||||||
|
### 基础镜像拉取失败
|
||||||
|
```bash
|
||||||
|
# 检查镜像仓库配置
|
||||||
|
echo $DOCKER_REGISTRY
|
||||||
|
|
||||||
|
# 手动拉取测试
|
||||||
|
docker pull kami-spider-base:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### 依赖安装失败
|
||||||
|
```bash
|
||||||
|
# 重建基础镜像
|
||||||
|
docker build --no-cache -f Dockerfile.base -t kami-spider-base:latest .
|
||||||
|
```
|
||||||
|
|
||||||
|
### 权限问题
|
||||||
|
确保构建脚本有执行权限:
|
||||||
|
```bash
|
||||||
|
chmod +x build-base-image.sh
|
||||||
|
```
|
||||||
54
kami-spider-monorepo/build-base-image.sh
Executable file
54
kami-spider-monorepo/build-base-image.sh
Executable file
@@ -0,0 +1,54 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Build script for kami-spider combined base Docker image
|
||||||
|
# This script creates a single comprehensive base image
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
BASE_IMAGE_NAME="kami-spider-base"
|
||||||
|
REGISTRY="${DOCKER_REGISTRY:-localhost:5000}"
|
||||||
|
VERSION="${VERSION:-latest}"
|
||||||
|
USE_PROXY="${USE_PROXY:-0}"
|
||||||
|
|
||||||
|
echo "🏗️ Building kami-spider combined base Docker image..."
|
||||||
|
echo "Registry: $REGISTRY"
|
||||||
|
echo "Version: $VERSION"
|
||||||
|
echo "Use Proxy: $USE_PROXY"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Build the combined base image (system + Python dependencies + Playwright)
|
||||||
|
echo "📦 Building combined base image ($BASE_IMAGE_NAME)..."
|
||||||
|
docker build \
|
||||||
|
--file Dockerfile.base-combined \
|
||||||
|
--tag "$BASE_IMAGE_NAME:$VERSION" \
|
||||||
|
--tag "$BASE_IMAGE_NAME:latest" \
|
||||||
|
--build-arg USE_PROXY="$USE_PROXY" \
|
||||||
|
.
|
||||||
|
|
||||||
|
# Tag for registry if specified
|
||||||
|
if [ "$REGISTRY" != "localhost:5000" ]; then
|
||||||
|
docker tag "$BASE_IMAGE_NAME:$VERSION" "$REGISTRY/$BASE_IMAGE_NAME:$VERSION"
|
||||||
|
docker tag "$BASE_IMAGE_NAME:latest" "$REGISTRY/$BASE_IMAGE_NAME:latest"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Combined base image built successfully!"
|
||||||
|
|
||||||
|
# Push to registry if specified
|
||||||
|
if [ "$REGISTRY" != "localhost:5000" ]; then
|
||||||
|
echo "🚀 Pushing image to registry..."
|
||||||
|
docker push "$REGISTRY/$BASE_IMAGE_NAME:$VERSION"
|
||||||
|
docker push "$REGISTRY/$BASE_IMAGE_NAME:latest"
|
||||||
|
echo "✅ Image pushed to registry successfully!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "🎉 Build completed successfully!"
|
||||||
|
echo "Available images:"
|
||||||
|
echo " - $BASE_IMAGE_NAME:$VERSION"
|
||||||
|
echo " - $BASE_IMAGE_NAME:latest"
|
||||||
|
|
||||||
|
# Display image size
|
||||||
|
echo
|
||||||
|
echo "📊 Image size:"
|
||||||
|
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" | grep "$BASE_IMAGE_NAME"
|
||||||
55
kami-spider-monorepo/docker-entrypoint.sh
Executable file
55
kami-spider-monorepo/docker-entrypoint.sh
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Docker production entrypoint script
|
||||||
|
# Optimized for production deployment
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Disable all debuggers and development tools
|
||||||
|
export PYDEVD_DISABLE=1
|
||||||
|
export PYDEVD_DISABLE_FILE_VALIDATION=1
|
||||||
|
export PYCHARM_DEBUG="false"
|
||||||
|
export PYTEST_CURRENT_TEST="false"
|
||||||
|
export PYTHONOPTIMIZE=2
|
||||||
|
|
||||||
|
# Ensure proper signal handling
|
||||||
|
cleanup() {
|
||||||
|
echo "Received termination signal, shutting down gracefully..."
|
||||||
|
if [ -n "$MAIN_PID" ]; then
|
||||||
|
kill -TERM "$MAIN_PID"
|
||||||
|
wait "$MAIN_PID"
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set up signal handlers
|
||||||
|
trap cleanup SIGTERM SIGINT
|
||||||
|
|
||||||
|
echo "Starting kami_spider application..."
|
||||||
|
echo "Environment: ${ENVIRONMENT:-production}"
|
||||||
|
echo "Database URL: ${DATABASE_URL}"
|
||||||
|
# Run database migrations first
|
||||||
|
echo "Running database migrations..."
|
||||||
|
if python scripts/db_manager.py up; then
|
||||||
|
echo "Database migrations completed successfully"
|
||||||
|
else
|
||||||
|
echo "Database migrations failed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check database connection
|
||||||
|
echo "Checking database connection..."
|
||||||
|
if python scripts/db_manager.py check; then
|
||||||
|
echo "Database connection verified"
|
||||||
|
else
|
||||||
|
echo "Database connection failed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run the main application
|
||||||
|
echo "Starting main application..."
|
||||||
|
exec "$@" &
|
||||||
|
MAIN_PID=$!
|
||||||
|
echo "Application started with PID: $MAIN_PID"
|
||||||
|
|
||||||
|
# Wait for the main process
|
||||||
|
wait "$MAIN_PID"
|
||||||
143
kami-spider-monorepo/pyproject.toml
Normal file
143
kami-spider-monorepo/pyproject.toml
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
[project]
|
||||||
|
name = "kami_spider"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "A stateless, production-ready FastAPI-based web service platform hosting multiple independent web applications"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.13"
|
||||||
|
dependencies = [
|
||||||
|
"fastapi>=0.120.0",
|
||||||
|
"uvicorn[standard]>=0.38.0",
|
||||||
|
"gunicorn>=23.0.0",
|
||||||
|
"sqlmodel>=0.0.24",
|
||||||
|
"pydantic>=2.12.3",
|
||||||
|
"pydantic-settings>=2.11.0",
|
||||||
|
"redis>=5.2.1",
|
||||||
|
"pymysql>=1.1.1",
|
||||||
|
"cryptography>=46.0.1",
|
||||||
|
"aiomysql>=0.2.0",
|
||||||
|
"alembic>=1.14.0",
|
||||||
|
"python-dotenv>=1.0.1",
|
||||||
|
"opentelemetry-api>=1.38.0",
|
||||||
|
"opentelemetry-sdk>=1.38.0",
|
||||||
|
"opentelemetry-instrumentation-fastapi>=0.59b0",
|
||||||
|
"opentelemetry-instrumentation-sqlalchemy>=0.59b0",
|
||||||
|
"opentelemetry-instrumentation-redis>=0.59b0",
|
||||||
|
"opentelemetry-instrumentation-httpx>=0.59b0",
|
||||||
|
"opentelemetry-instrumentation-logging>=0.59b0",
|
||||||
|
"opentelemetry-exporter-otlp-proto-grpc>=1.38.0",
|
||||||
|
"httpx>=0.28.1",
|
||||||
|
"python-multipart>=0.0.20",
|
||||||
|
"email-validator>=2.3.0",
|
||||||
|
"greenlet>=3.2.4",
|
||||||
|
"brotli>=1.1.0",
|
||||||
|
"psutil>=5.9.0",
|
||||||
|
"pycryptodome>=3.21.0",
|
||||||
|
"curl-cffi>=0.13.0",
|
||||||
|
"fake-useragent>=2.2.0",
|
||||||
|
"opentelemetry-instrumentation-requests>=0.59b0",
|
||||||
|
"ddddocr>=1.5.6",
|
||||||
|
"tenacity>=9.1.2",
|
||||||
|
"urllib3>=2.5.0",
|
||||||
|
"beautifulsoup4>=4.14.2",
|
||||||
|
"openai>=2.7.1",
|
||||||
|
"pandas>=2.3.3",
|
||||||
|
"lxml>=6.0.2",
|
||||||
|
"playwright>=1.55.0",
|
||||||
|
"aiofiles>=25.1.0",
|
||||||
|
"apscheduler>=3.10.0",
|
||||||
|
"orjson>=3.11.4",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
dev = [
|
||||||
|
"pytest>=8.3.4",
|
||||||
|
"pytest-asyncio>=0.24.0",
|
||||||
|
"pytest-cov>=6.0.0",
|
||||||
|
"pytest-mock>=3.14.0",
|
||||||
|
"httpx>=0.28.1",
|
||||||
|
"ruff>=0.8.4",
|
||||||
|
"mypy>=1.14.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["hatchling"]
|
||||||
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
|
[tool.hatch.build.targets.wheel]
|
||||||
|
packages = ["apps", "core", "middleware", "observability"]
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
testpaths = ["tests"]
|
||||||
|
python_files = ["test_*.py"]
|
||||||
|
python_classes = ["Test*"]
|
||||||
|
python_functions = ["test_*"]
|
||||||
|
asyncio_mode = "auto"
|
||||||
|
addopts = [
|
||||||
|
"--strict-markers",
|
||||||
|
"--strict-config",
|
||||||
|
"--cov=.",
|
||||||
|
"--cov-report=term-missing",
|
||||||
|
"--cov-report=html",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.coverage.run]
|
||||||
|
source = ["."]
|
||||||
|
omit = [
|
||||||
|
"tests/*",
|
||||||
|
"*/site-packages/*",
|
||||||
|
"*/__pycache__/*",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.coverage.report]
|
||||||
|
exclude_lines = [
|
||||||
|
"pragma: no cover",
|
||||||
|
"def __repr__",
|
||||||
|
"raise AssertionError",
|
||||||
|
"raise NotImplementedError",
|
||||||
|
"if __name__ == .__main__.:",
|
||||||
|
"if TYPE_CHECKING:",
|
||||||
|
"class .*\\bProtocol\\):",
|
||||||
|
"@(abc\\.)?abstractmethod",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
line-length = 120
|
||||||
|
target-version = "py313"
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
select = [
|
||||||
|
"E", # pycodestyle errors
|
||||||
|
"W", # pycodestyle warnings
|
||||||
|
"F", # pyflakes
|
||||||
|
"I", # isort
|
||||||
|
"B", # flake8-bugbear
|
||||||
|
"C4", # flake8-comprehensions
|
||||||
|
"UP", # pyupgrade
|
||||||
|
]
|
||||||
|
ignore = [
|
||||||
|
"E501", # line too long (handled by formatter)
|
||||||
|
"B008", # do not perform function calls in argument defaults
|
||||||
|
"W191", # indentation contains tabs
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.ruff.lint.per-file-ignores]
|
||||||
|
"__init__.py" = ["F401"]
|
||||||
|
|
||||||
|
[tool.mypy]
|
||||||
|
python_version = "3.13"
|
||||||
|
warn_return_any = true
|
||||||
|
warn_unused_configs = true
|
||||||
|
disallow_untyped_defs = true
|
||||||
|
disallow_incomplete_defs = true
|
||||||
|
check_untyped_defs = true
|
||||||
|
no_implicit_optional = true
|
||||||
|
warn_redundant_casts = true
|
||||||
|
warn_unused_ignores = true
|
||||||
|
warn_no_return = true
|
||||||
|
strict_equality = true
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = [
|
||||||
|
"mypy>=1.18.2",
|
||||||
|
"ruff>=0.14.2",
|
||||||
|
]
|
||||||
2159
kami-spider-monorepo/uv.lock
generated
Normal file
2159
kami-spider-monorepo/uv.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user