From 43fea407a9b1fb50fdba5e9cd0ccf44347262c12 Mon Sep 17 00:00:00 2001 From: tbphp Date: Sat, 12 Jul 2025 23:06:19 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20docker=20=E6=9E=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 15 ++++---- Dockerfile | 71 ++++++------------------------------- docker-compose.yml | 88 +++++++++++++++++++--------------------------- 3 files changed, 53 insertions(+), 121 deletions(-) diff --git a/.env.example b/.env.example index fce39a9..a6aae13 100644 --- a/.env.example +++ b/.env.example @@ -4,12 +4,11 @@ HOST=0.0.0.0 # 服务器读取、写入和空闲连接的超时时间(秒) SERVER_READ_TIMEOUT=120 -SERVER_WRITE_TIMEOUT=1800 -SERVER_GRACEFUL_SHUTDOWN_TIMEOUT=60 +SERVER_WRITE_TIMEOUT=600 +SERVER_GRACEFUL_SHUTDOWN_TIMEOUT=30 SERVER_IDLE_TIMEOUT=120 -# 认证配置 -# AUTH_KEY 是必需的,用于保护管理 API 和 UI 界面 +# 认证配置 是必需的,用于保护管理 API 和 UI 界面 AUTH_KEY=sk-123456 # CORS配置 @@ -25,14 +24,14 @@ KEY_VALIDATION_POOL_SIZE=50 # 数据库配置 # 示例 DSN: user:password@tcp(localhost:3306)/gpt_load?charset=utf8mb4&parseTime=True&loc=Local -DATABASE_DSN= +DATABASE_DSN=root:123456@tcp(mysql:3306)/gpt_load?charset=utf8mb4&parseTime=True&loc=Local # Redis配置 -# 示例 DSN: redis://:password@localhost:6379/1 -REDIS_DSN= +# 示例 DSN: redis://:password@localhost:6379/0 +REDIS_DSN=redis://redis:6379/0 # 日志配置 LOG_LEVEL=info LOG_FORMAT=text LOG_ENABLE_FILE=false -LOG_FILE_PATH=logs/app.log +LOG_FILE_PATH= diff --git a/Dockerfile b/Dockerfile index e8dae89..152beb4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,81 +1,30 @@ -# --- Stage 1: Frontend Builder --- FROM node:20-alpine AS frontend-builder -WORKDIR /app/web - -# Copy web project files -COPY web/package.json web/package-lock.json ./ -COPY web/tsconfig.json web/tsconfig.node.json web/tsconfig.app.json ./ -COPY web/vite.config.ts ./ - -# Install dependencies +WORKDIR /build +COPY ./web . RUN npm install - -# Copy the rest of the web source code -COPY web/ ./ - -# Build the frontend application RUN npm run build -# --- Stage 2: Backend Builder --- -FROM golang:1.22-alpine AS backend-builder -WORKDIR /app +FROM golang:1.24-alpine AS backend-builder -# Install build tools +WORKDIR /build RUN apk add --no-cache git build-base - -# Copy Go module files and download dependencies COPY go.mod go.sum ./ RUN go mod download - -# Copy the entire Go project source code COPY . . +COPY --from=frontend-builder /build/dist ./web/dist -# Copy the built frontend from the previous stage -COPY --from=frontend-builder /app/web/dist ./cmd/gpt-load/dist - -# Build the Go application -# We use CGO_ENABLED=0 to create a static binary -# -ldflags="-w -s" strips debug information and symbols to reduce binary size RUN CGO_ENABLED=0 GOOS=linux go build \ -ldflags="-w -s" \ - -o /gpt-load \ - ./cmd/gpt-load + -o gpt-load + -# --- Stage 3: Final Image --- FROM alpine:latest -# Install necessary runtime dependencies -# ca-certificates for HTTPS connections -# tzdata for time zone information -RUN apk --no-cache add ca-certificates tzdata - -# Create a non-root user and group for security -RUN addgroup -S appgroup && adduser -S appuser -G appgroup - -# Set the working directory WORKDIR /app +RUN apk --no-cache add ca-certificates tzdata +COPY --from=backend-builder /build/gpt-load . -# Copy the compiled binary from the backend-builder stage -COPY --from=backend-builder /gpt-load . - -# Copy the configuration file example -COPY .env.example . - -# Set ownership of the app directory to the non-root user -RUN chown -R appuser:appgroup /app - -# Switch to the non-root user -USER appuser - -# Expose the application port -# This should match the port defined in the configuration -EXPOSE 8080 - -# Healthcheck to ensure the application is running -HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ - CMD [ "wget", "-q", "--spider", "http://localhost:8080/health" ] || exit 1 - -# Set the entrypoint for the container +EXPOSE 3000 ENTRYPOINT ["/app/gpt-load"] diff --git a/docker-compose.yml b/docker-compose.yml index aae33cb..b1d8af8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,70 +1,54 @@ -version: '3.8' - services: - app: - build: - context: . - dockerfile: Dockerfile - container_name: gpt-load-app + gpt-load: + image: ghcr.io/tbphp/gpt-load:latest + # build: + # context: . + # dockerfile: Dockerfile + container_name: gpt-load ports: - - "8080:8080" + - "3000:3000" env_file: - .env - environment: - # Override or set environment variables here - - DB_HOST=db - - DB_PORT=3306 - - DB_USER=${DB_USER} - - DB_PASSWORD=${DB_PASSWORD} - - DB_NAME=${DB_NAME} - - GIN_MODE=release - restart: unless-stopped + restart: always depends_on: - db: + mysql: condition: service_healthy redis: - condition: service_started - networks: - - gpt-load-net - - db: - image: mysql:8.0 - container_name: gpt-load-db - restart: unless-stopped - environment: - MYSQL_DATABASE: ${DB_NAME} - MYSQL_USER: ${DB_USER} - MYSQL_PASSWORD: ${DB_PASSWORD} - MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} - volumes: - - db-data:/var/lib/mysql - ports: - - "3306:3306" + condition: service_healthy healthcheck: - test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "${DB_USER}", "-p${DB_PASSWORD}"] - interval: 10s - timeout: 5s + test: ["CMD", "curl", "-f", "http://localhost:3000/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + + mysql: + image: mysql:8.2 + container_name: gpt-load-mysql + restart: always + # ports: + # - "3306:3306" + environment: + MYSQL_ROOT_PASSWORD: 123456 + MYSQL_DATABASE: gpt_load + volumes: + - mysql_data:/var/lib/mysql + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] + timeout: 10s retries: 5 - networks: - - gpt-load-net redis: - image: redis:7-alpine + image: redis:latest container_name: gpt-load-redis - restart: unless-stopped - ports: - - "6379:6379" + restart: always + # ports: + # - "6379:6379" healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s - retries: 5 - networks: - - gpt-load-net + retries: 3 volumes: - db-data: - -networks: - gpt-load-net: - driver: bridge + mysql_data: