diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index ed5e88d..4bdae01 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -19,6 +19,65 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + # 设置 Go 环境 + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.21' + + # 构建后端 + - name: Build backend + run: | + cd backend + go build -o main . + + # 设置 Node.js 环境 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + cache: 'npm' + cache-dependency-path: frontend/package-lock.json + + # 构建前端 + - name: Build frontend + run: | + cd frontend + npm ci + npm run build + + # 创建 nginx 配置 + - name: Create nginx config + run: | + mkdir -p backend/config + cat > backend/config/nginx.conf << 'EOL' + worker_processes auto; + events { + worker_connections 1024; + } + http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + sendfile on; + keepalive_timeout 65; + gzip on; + server { + listen 80; + server_name localhost; + location / { + root /app/frontend; + index index.html; + try_files $uri $uri/ /index.html; + } + location /api { + proxy_pass http://localhost:8080; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + } + } + EOL + # 设置 QEMU 以支持多架构构建 - name: Set up QEMU uses: docker/setup-qemu-action@v3 diff --git a/Dockerfile b/Dockerfile index 0a8940b..1119ba1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,34 +1,4 @@ -# 第一阶段:构建后端 -FROM golang:1.21-alpine AS backend-builder - -WORKDIR /app/backend - -# 安装依赖 -COPY backend/go.mod backend/go.sum ./ -RUN go mod download - -# 复制后端源代码 -COPY backend/ . - -# 编译后端 -RUN CGO_ENABLED=0 GOOS=linux go build -o main . - -# 第二阶段:构建前端 -FROM node:18-alpine AS frontend-builder - -WORKDIR /app/frontend - -# 安装依赖 -COPY frontend/package.json frontend/package-lock.json ./ -RUN npm ci - -# 复制前端源代码 -COPY frontend/ . - -# 构建前端 -RUN npm run build - -# 第三阶段:最终镜像 +# 使用 Alpine 作为基础镜像 FROM alpine:3.18 WORKDIR /app @@ -36,17 +6,17 @@ WORKDIR /app # 安装 nginx RUN apk add --no-cache nginx -# 创建数据目录 -RUN mkdir -p /app/data +# 创建必要的目录 +RUN mkdir -p /app/data /app/frontend # 复制后端二进制文件 -COPY --from=backend-builder /app/backend/main ./ +COPY backend/main ./ + +# 复制 nginx 配置 COPY backend/config/nginx.conf /etc/nginx/nginx.conf # 复制前端构建产物 -COPY --from=frontend-builder /app/frontend/.next/static /app/frontend/static -COPY --from=frontend-builder /app/frontend/public /app/frontend/public -COPY --from=frontend-builder /app/frontend/.next/standalone /app/frontend +COPY frontend/dist /app/frontend # 复制启动脚本 COPY scripts/start.sh ./ diff --git a/backend/config/nginx.conf b/backend/config/nginx.conf new file mode 100644 index 0000000..bbef603 --- /dev/null +++ b/backend/config/nginx.conf @@ -0,0 +1,72 @@ +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log notice; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + + keepalive_timeout 65; + + gzip on; + gzip_min_length 1k; + gzip_comp_level 6; + gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml; + gzip_vary on; + + server { + listen 80; + server_name localhost; + root /app/frontend; + index index.html; + + # 前端文件缓存设置 + location /assets { + expires 7d; + add_header Cache-Control "public, no-transform"; + } + + # API 反向代理 + location /api { + proxy_pass http://127.0.0.1:8080; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + 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_cache_bypass $http_upgrade; + proxy_buffering off; + proxy_read_timeout 300s; + } + + # SPA 路由支持 + location / { + try_files $uri $uri/ /index.html; + add_header Cache-Control "no-cache, no-store, must-revalidate"; + } + + # 错误页面 + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + } +} \ No newline at end of file