From 438f74cab5d7ec140482cf52f9d66c4833c58419 Mon Sep 17 00:00:00 2001 From: nanako <469449812@qq.com> Date: Mon, 10 Nov 2025 23:15:36 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9B=BD=E5=86=85docker=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.cn.yml | 61 ++++++++++ docker-mirror-setup.md | 262 +++++++++++++++++++++++++++++++++++++++++ start-docker-cn.sh | 262 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 585 insertions(+) create mode 100644 docker-compose.cn.yml create mode 100644 docker-mirror-setup.md create mode 100644 start-docker-cn.sh diff --git a/docker-compose.cn.yml b/docker-compose.cn.yml new file mode 100644 index 0000000..79c34bd --- /dev/null +++ b/docker-compose.cn.yml @@ -0,0 +1,61 @@ +# Docker Compose 配置文件(国内网络优化版) +# 使用国内镜像源优化的 Dockerfile +# 适用于网络访问 Docker Hub 受限的环境 + +services: + # 后端服务 (Go API) + backend: + build: + context: ./backend + dockerfile: Dockerfile.cn # 使用国内优化版 Dockerfile + container_name: ai-router-backend + restart: unless-stopped + ports: + - "${BACKEND_PORT:-8080}:8080" + environment: + - DB_PATH=${DB_PATH:-/app/data/gateway.db} + - TZ=Asia/Shanghai + volumes: + # 持久化数据库文件 + - backend-data:/app/data + networks: + - ai-router-network + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/api/providers"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + + # 前端服务 (React + Nginx) + frontend: + build: + context: ./frontend + dockerfile: Dockerfile.cn # 使用国内优化版 Dockerfile + container_name: ai-router-frontend + restart: unless-stopped + ports: + - "${FRONTEND_PORT:-3000}:80" + depends_on: + backend: + condition: service_healthy + networks: + - ai-router-network + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:80/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + +# 网络配置 +networks: + ai-router-network: + driver: bridge + name: ai-router-network + +# 数据卷配置 +volumes: + backend-data: + driver: local + name: ai-router-backend-data \ No newline at end of file diff --git a/docker-mirror-setup.md b/docker-mirror-setup.md new file mode 100644 index 0000000..cae0368 --- /dev/null +++ b/docker-mirror-setup.md @@ -0,0 +1,262 @@ +# Docker 镜像加速器配置指南 + +## 问题说明 + +错误信息显示无法连接到 Docker Hub (`registry-1.docker.io`),这是因为网络访问受限导致的。 + +## 解决方案 + +### 方案一:配置 Docker 镜像加速器(推荐) + +#### 1. 创建或编辑 Docker 配置文件 + +```bash +# 创建 docker 配置目录(如果不存在) +sudo mkdir -p /etc/docker + +# 编辑 daemon.json 配置文件 +sudo nano /etc/docker/daemon.json +``` + +#### 2. 添加以下配置 + +```json +{ + "registry-mirrors": [ + "https://docker.mirrors.ustc.edu.cn", + "https://hub-mirror.c.163.com", + "https://mirror.baidubce.com", + "https://docker.nju.edu.cn" + ], + "insecure-registries": [], + "log-driver": "json-file", + "log-opts": { + "max-size": "10m", + "max-file": "3" + } +} +``` + +#### 3. 重启 Docker 服务 + +```bash +# 重新加载配置 +sudo systemctl daemon-reload + +# 重启 Docker +sudo systemctl restart docker + +# 验证配置 +docker info | grep -A 5 "Registry Mirrors" +``` + +#### 4. 测试拉取镜像 + +```bash +# 测试拉取一个小镜像 +docker pull alpine:latest + +# 如果成功,继续构建项目 +cd /home/AIRouter +docker compose up --build -d +``` + +### 方案二:使用国内替代基础镜像 + +如果镜像加速器仍然不稳定,可以修改 Dockerfile 使用国内镜像源。 + +#### 修改后端 Dockerfile + +创建 `backend/Dockerfile.cn`: + +```dockerfile +# 使用国内 Go 镜像源 +FROM golang:1.24-bookworm AS builder + +WORKDIR /app + +# 配置 Go 模块代理(使用国内镜像) +ENV GO111MODULE=on \ + GOPROXY=https://goproxy.cn,https://goproxy.io,direct \ + CGO_ENABLED=1 + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . + +RUN go build -ldflags="-w -s" -o gateway main.go + +# 运行阶段使用清华大学镜像源 +FROM debian:bookworm-slim + +RUN sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list.d/debian.sources && \ + apt-get update && \ + apt-get install -y --no-install-recommends ca-certificates wget && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +COPY --from=builder /app/gateway . + +RUN mkdir -p /app/data + +ENV DB_PATH=/app/data/gateway.db + +EXPOSE 8080 + +CMD ["./gateway"] +``` + +#### 修改前端 Dockerfile + +创建 `frontend/Dockerfile.cn`: + +```dockerfile +FROM node:20-alpine AS builder + +WORKDIR /app + +# 配置 npm 使用国内镜像 +RUN npm config set registry https://registry.npmmirror.com + +COPY package*.json ./ +RUN npm ci + +COPY . . +RUN npm run build + +FROM nginx:1.27-alpine + +COPY --from=builder /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf + +RUN echo "OK" > /usr/share/nginx/html/health + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] +``` + +#### 修改 docker-compose.yml + +```yaml +version: '3.8' + +services: + backend: + build: + context: ./backend + dockerfile: Dockerfile.cn # 使用国内优化版本 + # ... 其他配置保持不变 + + frontend: + build: + context: ./frontend + dockerfile: Dockerfile.cn # 使用国内优化版本 + # ... 其他配置保持不变 +``` + +### 方案三:手动拉取所需镜像 + +```bash +# 使用镜像加速器手动拉取所需的基础镜像 +docker pull golang:1.24-bookworm +docker pull debian:bookworm-slim +docker pull node:20-alpine +docker pull nginx:1.27-alpine + +# 然后再构建项目 +docker compose up --build -d +``` + +### 方案四:使用代理(临时方案) + +如果你有可用的代理服务器: + +```bash +# 设置 Docker 客户端代理 +export HTTP_PROXY="http://your-proxy:port" +export HTTPS_PROXY="http://your-proxy:port" +export NO_PROXY="localhost,127.0.0.1" + +# 然后执行构建 +docker compose up --build -d + +# 构建完成后取消代理 +unset HTTP_PROXY HTTPS_PROXY NO_PROXY +``` + +或者配置 Docker daemon 使用代理: + +```bash +# 创建 systemd 配置目录 +sudo mkdir -p /etc/systemd/system/docker.service.d + +# 创建代理配置文件 +sudo nano /etc/systemd/system/docker.service.d/http-proxy.conf +``` + +添加以下内容: + +```ini +[Service] +Environment="HTTP_PROXY=http://your-proxy:port" +Environment="HTTPS_PROXY=http://your-proxy:port" +Environment="NO_PROXY=localhost,127.0.0.1" +``` + +然后重启 Docker: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart docker +``` + +## 推荐操作步骤 + +1. **首先尝试方案一**(配置镜像加速器)- 最简单且长期有效 +2. 如果方案一不稳定,**使用方案三**(手动拉取镜像) +3. 如果以上都不行,**使用方案二**(国内优化 Dockerfile) + +## 验证成功 + +配置完成后,执行以下命令验证: + +```bash +# 查看 Docker 配置 +docker info + +# 测试拉取镜像速度 +time docker pull alpine:latest + +# 构建项目 +cd /home/AIRouter +docker compose up --build -d + +# 查看构建进度 +docker compose logs -f + +# 检查服务状态 +docker compose ps +``` + +## 常见问题 + +### Q: 镜像加速器配置后仍然超时? +A: 尝试使用不同的镜像源,或者切换到方案二使用国内优化的 Dockerfile。 + +### Q: 某些镜像源不可用? +A: 镜像源可能会变化,可以尝试其他可用的源,或搜索最新的国内 Docker 镜像源。 + +### Q: 构建速度仍然很慢? +A: 考虑使用本地镜像缓存,或者在网络条件好的时候提前拉取所需镜像。 + +## 其他国内可用镜像源 + +- 阿里云:https://your-id.mirror.aliyuncs.com (需要注册获取专属地址) +- 腾讯云:https://mirror.ccs.tencentyun.com +- 南京大学:https://docker.nju.edu.cn +- 中国科技大学:https://docker.mirrors.ustc.edu.cn +- 网易:https://hub-mirror.c.163.com +- 百度云:https://mirror.baidubce.com diff --git a/start-docker-cn.sh b/start-docker-cn.sh new file mode 100644 index 0000000..1e055d8 --- /dev/null +++ b/start-docker-cn.sh @@ -0,0 +1,262 @@ +#!/bin/bash + +# AI Router Docker 国内网络优化版启动脚本 +# 适用于网络访问 Docker Hub 受限的环境 + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 打印带颜色的消息 +print_info() { + echo -e "${BLUE}[信息]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[成功]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[警告]${NC} $1" +} + +print_error() { + echo -e "${RED}[错误]${NC} $1" +} + +# 打印标题 +print_header() { + echo "" + echo -e "${BLUE}========================================${NC}" + echo -e "${BLUE} AI Router Docker 国内优化版部署${NC}" + echo -e "${BLUE}========================================${NC}" + echo "" +} + +# 检查 Docker 是否安装 +check_docker() { + print_info "检查 Docker 安装状态..." + + if ! command -v docker &> /dev/null; then + print_error "Docker 未安装,请先安装 Docker" + print_info "安装指南: https://docs.docker.com/engine/install/" + exit 1 + fi + + if ! command -v docker compose &> /dev/null; then + print_error "Docker Compose 未安装,请先安装 Docker Compose" + print_info "安装指南: https://docs.docker.com/compose/install/" + exit 1 + fi + + print_success "Docker 和 Docker Compose 已安装" + docker --version + docker compose version +} + +# 检查 Docker 服务状态 +check_docker_service() { + print_info "检查 Docker 服务状态..." + + if ! docker info &> /dev/null; then + print_error "Docker 服务未运行,请启动 Docker 服务" + print_info "运行: sudo systemctl start docker" + exit 1 + fi + + print_success "Docker 服务正常运行" +} + +# 配置 Docker 镜像加速器(可选) +configure_mirror() { + print_info "检查 Docker 镜像加速器配置..." + + if docker info 2>/dev/null | grep -q "Registry Mirrors"; then + print_success "已配置 Docker 镜像加速器" + docker info 2>/dev/null | grep -A 5 "Registry Mirrors" + else + print_warning "未配置 Docker 镜像加速器" + print_info "如果构建失败,请参考 docker-mirror-setup.md 配置镜像加速器" + fi +} + +# 清理旧容器和镜像(可选) +cleanup_old() { + read -p "是否清理旧的容器和镜像?(y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + print_info "停止并删除旧容器..." + docker compose -f docker-compose.cn.yml down 2>/dev/null || true + + print_info "删除旧镜像..." + docker rmi ai-router-backend:latest 2>/dev/null || true + docker rmi ai-router-frontend:latest 2>/dev/null || true + + print_success "清理完成" + fi +} + +# 构建镜像 +build_images() { + print_info "开始构建 Docker 镜像(使用国内镜像源)..." + print_warning "首次构建可能需要较长时间,请耐心等待..." + + # 使用国内优化版的 docker-compose 配置 + if docker compose -f docker-compose.cn.yml build --no-cache; then + print_success "镜像构建成功" + else + print_error "镜像构建失败" + print_info "请检查网络连接或参考 docker-mirror-setup.md 配置镜像加速器" + exit 1 + fi +} + +# 启动服务 +start_services() { + print_info "启动服务..." + + if docker compose -f docker-compose.cn.yml up -d; then + print_success "服务启动成功" + else + print_error "服务启动失败" + print_info "查看日志: docker compose -f docker-compose.cn.yml logs" + exit 1 + fi +} + +# 等待服务就绪 +wait_for_services() { + print_info "等待服务启动完成..." + + # 等待后端服务 + print_info "等待后端服务就绪(最多等待 60 秒)..." + TIMEOUT=60 + ELAPSED=0 + while [ $ELAPSED -lt $TIMEOUT ]; do + if docker compose -f docker-compose.cn.yml ps backend | grep -q "healthy"; then + print_success "后端服务已就绪" + break + fi + sleep 2 + ELAPSED=$((ELAPSED + 2)) + echo -n "." + done + echo "" + + if [ $ELAPSED -ge $TIMEOUT ]; then + print_warning "后端服务启动超时,请检查日志" + fi + + # 等待前端服务 + print_info "等待前端服务就绪(最多等待 30 秒)..." + TIMEOUT=30 + ELAPSED=0 + while [ $ELAPSED -lt $TIMEOUT ]; do + if docker compose -f docker-compose.cn.yml ps frontend | grep -q "healthy"; then + print_success "前端服务已就绪" + break + fi + sleep 2 + ELAPSED=$((ELAPSED + 2)) + echo -n "." + done + echo "" + + if [ $ELAPSED -ge $TIMEOUT ]; then + print_warning "前端服务启动超时,请检查日志" + fi +} + +# 显示服务状态 +show_status() { + print_info "服务运行状态:" + echo "" + docker compose -f docker-compose.cn.yml ps + echo "" +} + +# 测试服务 +test_services() { + print_info "测试服务连接..." + + # 测试后端 + if curl -f -s http://localhost:8080/api/providers > /dev/null 2>&1; then + print_success "后端 API 服务正常: http://localhost:8080/api" + else + print_warning "后端 API 服务可能未完全启动,请稍后再试" + fi + + # 测试前端 + if curl -f -s http://localhost:3000/health > /dev/null 2>&1; then + print_success "前端服务正常: http://localhost:3000" + else + print_warning "前端服务可能未完全启动,请稍后再试" + fi +} + +# 显示访问信息 +show_access_info() { + echo "" + echo -e "${GREEN}========================================${NC}" + echo -e "${GREEN} 部署完成!${NC}" + echo -e "${GREEN}========================================${NC}" + echo "" + echo -e " 前端访问地址: ${BLUE}http://localhost:3000${NC}" + echo -e " 后端 API: ${BLUE}http://localhost:8080/api${NC}" + echo "" + echo -e "${YELLOW}常用命令:${NC}" + echo -e " 查看日志: ${BLUE}docker compose -f docker-compose.cn.yml logs -f${NC}" + echo -e " 停止服务: ${BLUE}docker compose -f docker-compose.cn.yml stop${NC}" + echo -e " 重启服务: ${BLUE}docker compose -f docker-compose.cn.yml restart${NC}" + echo -e " 停止并删除: ${BLUE}docker compose -f docker-compose.cn.yml down${NC}" + echo -e " 查看状态: ${BLUE}docker compose -f docker-compose.cn.yml ps${NC}" + echo "" + echo -e "${YELLOW}更多信息请参考:${NC}" + echo -e " 部署文档: ${BLUE}README-DOCKER.md${NC}" + echo -e " 镜像配置: ${BLUE}docker-mirror-setup.md${NC}" + echo "" +} + +# 主函数 +main() { + print_header + + # 检查环境 + check_docker + check_docker_service + configure_mirror + + echo "" + + # 清理旧资源(可选) + cleanup_old + + echo "" + + # 构建和启动 + build_images + start_services + wait_for_services + + echo "" + + # 显示状态 + show_status + test_services + + # 显示访问信息 + show_access_info +} + +# 错误处理 +trap 'print_error "脚本执行失败,请检查错误信息"; exit 1' ERR + +# 运行主函数 +main + +exit 0 \ No newline at end of file