#!/bin/bash # DMS合规性测试工具 - Docker Compose版本部署包创建脚本 # 使用Alpine Linux + 多阶段构建 + Docker Compose管理 # 支持多架构构建 (amd64 + arm64) set -e # 配置变量 EXPORT_DIR="dms-compliance-compose-$(date +%Y%m%d-%H%M%S)" IMAGE_NAME="compliance-dms-mini" ARCHIVE_NAME="$EXPORT_DIR.tar.gz" TARGET_PLATFORMS="linux/amd64,linux/arm64" echo "=== DMS合规性测试工具 Docker Compose版本部署包创建脚本 ===" echo "[信息] 使用Docker Compose管理,完全兼容原版架构" echo "[信息] 目标架构: $TARGET_PLATFORMS" # 检查Docker是否运行 if ! docker info >/dev/null 2>&1; then echo "[错误] Docker未运行或无法访问" exit 1 fi # 检查是否支持buildx(用于跨平台构建) if ! docker buildx version >/dev/null 2>&1; then echo "[警告] Docker buildx不可用,将使用传统构建方式" USE_BUILDX=false TARGET_PLATFORMS="linux/amd64" # 降级到单架构 else echo "[信息] 检测到Docker buildx,支持多架构构建" USE_BUILDX=true # 让用户选择构建架构 echo "" echo "请选择构建架构:" echo "1) 仅 AMD64 (x86_64) - 适用于大多数服务器" echo "2) 仅 ARM64 (aarch64) - 适用于Apple Silicon Mac、ARM服务器" echo "3) 多架构 (AMD64 + ARM64) - 通用兼容,但构建时间较长" echo "" read -p "请输入选择 (1-3,默认3): " -r ARCH_CHOICE case "${ARCH_CHOICE:-3}" in 1) TARGET_PLATFORMS="linux/amd64" echo "[信息] 选择构建架构: AMD64 only" ;; 2) TARGET_PLATFORMS="linux/arm64" echo "[信息] 选择构建架构: ARM64 only" ;; 3|*) TARGET_PLATFORMS="linux/amd64,linux/arm64" echo "[信息] 选择构建架构: 多架构 (AMD64 + ARM64)" ;; esac fi echo "[信息] 最终目标架构: $TARGET_PLATFORMS" # 创建导出目录 echo "[信息] 创建导出目录: $EXPORT_DIR" rm -rf "$EXPORT_DIR" mkdir -p "$EXPORT_DIR" # 1. 创建临时构建目录,只包含必要文件 echo "[信息] 创建临时构建目录..." TEMP_BUILD_DIR=$(mktemp -d) trap "rm -rf $TEMP_BUILD_DIR" EXIT # 白名单:只复制必要的文件 echo "[信息] 复制必要文件(超精简模式)..." mkdir -p "$TEMP_BUILD_DIR"/{ddms_compliance_suite,custom_stages,custom_testcases,templates,static,assets} # 只复制核心Python文件 echo "[信息] 复制核心Python文件..." for file in api_server.py history_viewer.py flask_app.py; do [ -f "$file" ] && cp "$file" "$TEMP_BUILD_DIR/" done # 复制核心目录(排除缓存和临时文件) echo "[信息] 复制核心目录..." rsync -av --exclude='__pycache__' --exclude='*.pyc' --exclude='*.log' ddms_compliance_suite/ "$TEMP_BUILD_DIR/ddms_compliance_suite/" rsync -av --exclude='__pycache__' --exclude='*.pyc' custom_stages/ "$TEMP_BUILD_DIR/custom_stages/" rsync -av --exclude='__pycache__' --exclude='*.pyc' custom_testcases/ "$TEMP_BUILD_DIR/custom_testcases/" # 确保templates目录结构正确 echo "[信息] 复制模板和静态文件..." rsync -av templates/ "$TEMP_BUILD_DIR/templates/" rsync -av static/ "$TEMP_BUILD_DIR/static/" rsync -av assets/ "$TEMP_BUILD_DIR/assets/" # 验证templates目录内容 echo "[信息] 验证templates目录: $(ls "$TEMP_BUILD_DIR/templates/" 2>/dev/null | wc -l) 个文件" echo "[信息] templates文件列表: $(ls "$TEMP_BUILD_DIR/templates/" 2>/dev/null | tr '\n' ' ')" # 复制完整的requirements.txt echo "[信息] 复制完整的requirements.txt..." cp requirements.txt "$TEMP_BUILD_DIR/" # 创建超轻量级Dockerfile echo "[信息] 创建超轻量级Dockerfile..." cat > "$TEMP_BUILD_DIR/Dockerfile" << 'EOF' # 多阶段构建:第一阶段安装依赖 FROM python:3.9-alpine AS builder # 安装构建依赖 RUN apk add --no-cache gcc musl-dev linux-headers # 设置工作目录 WORKDIR /app # 复制requirements并安装Python依赖 COPY requirements.txt . RUN pip install --no-cache-dir --user -r requirements.txt # 第二阶段:运行时镜像 FROM python:3.9-alpine # 安装运行时依赖 RUN apk add --no-cache supervisor curl && \ rm -rf /var/cache/apk/* # 从构建阶段复制Python包 COPY --from=builder /root/.local /root/.local # 设置工作目录 WORKDIR /app # 复制应用代码 COPY . . # 创建supervisor配置 RUN mkdir -p /etc/supervisor/conf.d COPY supervisord.conf /etc/supervisor/conf.d/ # 创建日志目录 RUN mkdir -p /var/log/supervisor /app/logs /app/test_reports /app/uploads # 设置环境变量 ENV PATH=/root/.local/bin:$PATH ENV PYTHONPATH=/app ENV FLASK_ENV=production ENV PYTHONUNBUFFERED=1 # 暴露端口(两个服务的端口) EXPOSE 5050 5051 # 启动supervisor CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"] EOF # 创建supervisor配置 echo "[信息] 创建supervisor配置..." cat > "$TEMP_BUILD_DIR/supervisord.conf" << 'EOF' [supervisord] nodaemon=true logfile=/var/log/supervisor/supervisord.log pidfile=/var/run/supervisord.pid childlogdir=/var/log/supervisor logfile_maxbytes=50MB logfile_backups=10 loglevel=info [unix_http_server] file=/tmp/supervisor.sock chmod=0700 [supervisorctl] serverurl=unix:///tmp/supervisor.sock [rpcinterface:supervisor] supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface # DMS API服务器 (主服务) [program:api_server] command=python api_server.py directory=/app autostart=true autorestart=true redirect_stderr=true stdout_logfile=/var/log/supervisor/api_server.log stdout_logfile_maxbytes=10MB stdout_logfile_backups=5 environment=PYTHONPATH="/app",PYTHONUNBUFFERED="1" # 历史查看器服务 [program:history_viewer] command=python history_viewer.py directory=/app autostart=true autorestart=true redirect_stderr=true stdout_logfile=/var/log/supervisor/history_viewer.log stdout_logfile_maxbytes=10MB stdout_logfile_backups=5 environment=PYTHONPATH="/app",PYTHONUNBUFFERED="1" # 进程组配置 [group:dms_services] programs=api_server,history_viewer priority=999 EOF # 显示构建目录大小 echo "[信息] 临时构建目录大小: $(du -sh "$TEMP_BUILD_DIR" | cut -f1)" # 2. 构建Docker镜像 echo "[信息] 构建超轻量Docker镜像 ($TARGET_PLATFORMS)..." cd "$TEMP_BUILD_DIR" if [ "$USE_BUILDX" = true ]; then # 创建并使用buildx构建器实例 echo "[信息] 创建buildx构建器实例..." docker buildx create --name multiarch-builder --use 2>/dev/null || docker buildx use multiarch-builder 2>/dev/null || true # 检查是否为多架构构建 if [[ "$TARGET_PLATFORMS" == *","* ]]; then echo "[信息] 执行多架构构建,这可能需要几分钟时间..." echo "[提示] 多架构构建会自动推送到本地registry,然后再导出" # 多架构构建需要先推送到registry再导出 # 这里我们使用一个临时的本地registry echo "[信息] 启动临时本地registry..." docker run -d --rm --name temp-registry -p 5555:5000 registry:2 2>/dev/null || true sleep 2 # 构建并推送到临时registry docker buildx build --platform "$TARGET_PLATFORMS" \ --tag "localhost:5555/$IMAGE_NAME:latest" \ --push . # 从registry拉取并重新标记 docker pull "localhost:5555/$IMAGE_NAME:latest" docker tag "localhost:5555/$IMAGE_NAME:latest" "$IMAGE_NAME:latest" # 清理临时registry docker stop temp-registry 2>/dev/null || true else # 单架构构建可以直接load echo "[信息] 执行单架构构建..." docker buildx build --platform "$TARGET_PLATFORMS" --load -t "$IMAGE_NAME:latest" . fi else # 使用传统构建方式 echo "[信息] 使用传统Docker构建..." docker build --platform "$TARGET_PLATFORMS" -t "$IMAGE_NAME:latest" . fi cd - > /dev/null # 3. 导出Docker镜像 echo "[信息] 导出Docker镜像..." docker save "$IMAGE_NAME:latest" | gzip > "$EXPORT_DIR/docker-image.tar.gz" # 4. 创建docker-compose.yml echo "[信息] 创建docker-compose.yml..." cat > "$EXPORT_DIR/docker-compose.yml" << 'EOF' version: '3.8' services: dms-compliance-tool: image: compliance-dms-mini:latest container_name: dms-compliance-mini ports: - "5050:5050" # API服务器端口 - "5051:5051" # 历史查看器端口 volumes: # 持久化测试报告 - ./test_reports:/app/test_reports # 持久化上传文件 - ./uploads:/app/uploads # 持久化日志 - ./logs:/app/logs # 如果需要自定义配置文件 - ./config:/app/config:ro environment: - FLASK_ENV=production - PYTHONUNBUFFERED=1 - TZ=Asia/Shanghai restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5050/"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - dms-network networks: dms-network: driver: bridge volumes: test_reports: uploads: logs: EOF # 5. 创建部署脚本 echo "[信息] 创建部署脚本..." cat > "$EXPORT_DIR/deploy.sh" << 'EOF' #!/bin/bash # DMS合规性测试工具 - Docker Compose版本部署脚本 set -e echo "=== DMS合规性测试工具 Docker Compose版本部署 ===" # 检查Docker和Docker Compose if ! docker info >/dev/null 2>&1; then echo "[错误] Docker未运行" exit 1 fi if ! command -v docker-compose >/dev/null 2>&1 && ! docker compose version >/dev/null 2>&1; then echo "[错误] Docker Compose未安装" echo "请安装Docker Compose或使用Docker Desktop" exit 1 fi # 创建必要的目录 echo "[信息] 创建数据目录..." mkdir -p test_reports uploads logs config # 加载镜像 echo "[信息] 加载Docker镜像..." docker load < docker-image.tar.gz # 停止现有服务 echo "[信息] 停止现有服务..." docker-compose down 2>/dev/null || docker compose down 2>/dev/null || true # 启动服务 echo "[信息] 启动服务..." if command -v docker-compose >/dev/null 2>&1; then docker-compose up -d else docker compose up -d fi echo "[成功] 部署完成!" echo "访问地址: http://localhost:5050 (API服务器)" echo "访问地址: http://localhost:5051 (历史查看器)" echo "" echo "管理命令:" echo "- 查看状态: docker-compose ps" echo "- 查看日志: docker-compose logs" echo "- 停止服务: docker-compose down" echo "- 重启服务: docker-compose restart" echo "" echo "数据目录:" echo "- 测试报告: $(pwd)/test_reports" echo "- 上传文件: $(pwd)/uploads" echo "- 日志文件: $(pwd)/logs" echo "- 配置文件: $(pwd)/config" EOF chmod +x "$EXPORT_DIR/deploy.sh" # 6. 创建README echo "[信息] 创建README..." cat > "$EXPORT_DIR/README.md" << 'EOF' # DMS合规性测试工具 - Docker Compose版本 ## 特点 - 基于Alpine Linux,镜像体积极小(约300MB) - 多阶段构建,优化层结构 - 完全兼容原版架构(5050+5051端口) - 使用Docker Compose管理服务 - 支持数据持久化和健康检查 - 支持多架构:AMD64 (x86_64) 和 ARM64 (aarch64) - 兼容Intel/AMD服务器、Apple Silicon Mac、ARM服务器 ## 部署方法 1. 解压部署包 2. 运行部署脚本: ```bash ./deploy.sh ``` 3. 访问服务: - API服务器: http://localhost:5050 - 历史查看器: http://localhost:5051 ## 管理命令 - 查看服务状态:`docker-compose ps` - 查看日志:`docker-compose logs` - 停止服务:`docker-compose down` - 重启服务:`docker-compose restart` - 查看实时日志:`docker-compose logs -f` ## 文件说明 - `docker-image.tar.gz` - Docker镜像文件 - `docker-compose.yml` - Docker Compose配置文件 - `deploy.sh` - 一键部署脚本 - `README.md` - 说明文档 ## 数据持久化 所有重要数据都会持久化到本地目录: - `test_reports/` - 测试报告 - `uploads/` - 上传文件 - `logs/` - 日志文件 - `config/` - 配置文件(只读) EOF # 7. 显示镜像信息 echo "[信息] Docker镜像信息:" docker images "$IMAGE_NAME:latest" # 8. 压缩最终包 echo "[信息] 压缩最终部署包..." tar -czf "$ARCHIVE_NAME" "$EXPORT_DIR" # 9. 显示结果 echo "" echo "=== 创建完成 ===" echo "部署包: $ARCHIVE_NAME" echo "部署包大小: $(du -sh "$ARCHIVE_NAME" | cut -f1)" echo "Docker镜像大小: $(docker images "$IMAGE_NAME:latest" --format "{{.Size}}" 2>/dev/null || echo "约300MB")" echo "" echo "部署方法:" echo "1. 解压: tar -xzf $ARCHIVE_NAME" echo "2. 进入目录: cd $EXPORT_DIR" echo "3. 运行: ./deploy.sh" echo "" # 清理Docker镜像(可选) read -p "是否删除本地Docker镜像?(y/N): " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then docker rmi "$IMAGE_NAME:latest" echo "[信息] 已删除本地Docker镜像" fi echo "[完成] Docker Compose版本部署包创建完成!"