feat:自动构建

This commit is contained in:
wood911010 committed 2025-08-09 01:34:49 +08:00
1 parent 183f5e7896
commit 6bcd8f4d09
14 files changed
+752 -112

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
# 生产环境配置示例
# 复制此文件为 .env 并修改相应配置
# MySQL配置
MYSQL_ROOT_PASSWORD=your-strong-root-password
MYSQL_PASSWORD=your-strong-user-password
MYSQL_PORT=3306
# 应用端口配置
BACKEND_PORT=18888
FRONTEND_PORT=80
# Redis配置 (可选)
REDIS_PASSWORD=your-redis-password
REDIS_PORT=6379
# 镜像配置 (用于生产环境)
BACKEND_IMAGE=ghcr.io/your-org/license-manager-backend:latest
FRONTEND_IMAGE=ghcr.io/your-org/license-manager-frontend:latest
+92
View File
@@ -0,0 +1,92 @@
name: Release Backend Image
on:
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g., v1.0.0)'
required: true
type: string
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}-backend
jobs:
test-and-build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.23'
- name: Cache Go modules
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('backend/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run tests
run: |
cd backend
go mod tidy
go mod verify
go test -v ./...
go build -ldflags="-s -w" -o license-manager cmd/main.go
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest
type=raw,value=${{ github.event.inputs.version }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile.backend
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Generate summary
run: |
echo "## 🚀 Backend Release Successful!" >> $GITHUB_STEP_SUMMARY
echo "**Version:** ${{ github.event.inputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "**Image:** ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" >> $GITHUB_STEP_SUMMARY
echo "**Tags:**" >> $GITHUB_STEP_SUMMARY
echo "- ${{ github.event.inputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "- latest" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Usage:" >> $GITHUB_STEP_SUMMARY
echo '```bash' >> $GITHUB_STEP_SUMMARY
echo "docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.inputs.version }}" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
+69
View File
@@ -0,0 +1,69 @@
name: Release Frontend Image
on:
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g., v1.0.0)'
required: true
type: string
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}-frontend
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest
type=raw,value=${{ github.event.inputs.version }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile.frontend
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Generate summary
run: |
echo "## 🎉 Frontend Release Successful!" >> $GITHUB_STEP_SUMMARY
echo "**Version:** ${{ github.event.inputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "**Image:** ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" >> $GITHUB_STEP_SUMMARY
echo "**Tags:**" >> $GITHUB_STEP_SUMMARY
echo "- ${{ github.event.inputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "- latest" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Usage:" >> $GITHUB_STEP_SUMMARY
echo '```bash' >> $GITHUB_STEP_SUMMARY
echo "docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.inputs.version }}" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
+1 -1
View File
@@ -7,7 +7,7 @@ COPY backend/ ./
RUN go build -ldflags="-s -w" -o license-manager cmd/main.go RUN go build -ldflags="-s -w" -o license-manager cmd/main.go
FROM alpine:latest FROM alpine:latest
RUN apk --no-cache add ca-certificates tzdata RUN apk --no-cache add ca-certificates tzdata curl
WORKDIR /app/backend/cmd WORKDIR /app/backend/cmd
COPY --from=builder /app/backend/license-manager ./license-manager COPY --from=builder /app/backend/license-manager ./license-manager
COPY backend/configs/ ../configs/ COPY backend/configs/ ../configs/
+120
View File
@@ -0,0 +1,120 @@
# Docker 部署指南
本项目提供两种部署:开发环境与生产环境。以下说明已与当前 `docker-compose` 配置、镜像与反向代理实现对齐。
## 开发环境
使用 `docker compose`(Docker Desktop 或 Docker CE 20.10+):
```bash
# 启动(首次建议带 --build)
docker compose up -d --build
# 查看状态/日志
docker compose ps
docker compose logs -f backend
# 停止
docker compose down
```
### 访问地址(开发)
- 前端: http://localhost:18080
- 后端 API: http://localhost:18888
- MySQL: localhost:13306(数据库、用户、密码见 compose)
## 生产环境
使用 `docker-compose.prod.yml`:
```bash
# 启动生产环境
docker compose -f docker-compose.prod.yml up -d
# 查看服务状态
docker compose -f docker-compose.prod.yml ps
```
### 生产配置说明
- 后端配置文件已通过卷挂载至容器内:
- 开发:`backend/configs/config.dev.yaml` → 容器内 `/app/backend/cmd/config.yaml`
- 生产:`backend/configs/config.prod.yaml` → 容器内 `/app/backend/cmd/config.yaml`
- 前端 Nginx 反向代理已指向容器网络内的 `backend:18888`,无需依赖 `host.docker.internal`。
- 健康检查统一使用 `curl`,后端镜像已内置 `curl`。
- 如需隐藏后端对外端口,可在生产 compose 中移除后端端口映射,仅通过前端或网关暴露。
## 服务说明
### MySQL 8.0
- 端口:3306(生产)/ 13306(开发宿主机映射)
- 库:`license_manager`,用户:`license_user`
- 字符集/排序:`utf8mb4`/`utf8mb4_unicode_ci`
- 开启慢查询日志(生产)
### 后端服务
- 端口:18888
- 健康检查:`/health`
- 配置:通过卷挂载 `config.dev.yaml` / `config.prod.yaml` 为容器内 `config.yaml`
- 日志:标准输出 + `./logs` 挂载目录
### 前端服务
- 端口:80(生产)/ 18080(开发映射)
- 反向代理:`/api/` → `backend:18888`
- 静态资源:启用 Gzip 与长缓存
### Redis(可选,仅生产)
- 端口:6379,AOF 持久化
## 常用命令
```bash
# 重新构建镜像
docker compose build
# 启动指定服务
docker compose up -d mysql backend
# 进入容器
docker compose exec backend sh
docker compose exec mysql mysql -uroot -p
# 备份/恢复数据库
docker compose exec mysql mysqldump -uroot -p license_manager > backup.sql
docker compose exec -T mysql mysql -uroot -p license_manager < backup.sql
# 清理未使用资源
docker system prune -f
```
## 故障排查
1) MySQL 启动失败
```bash
docker compose logs mysql
docker compose down -v && docker compose up -d
```
2) 后端连接数据库失败
```bash
# 确认 MySQL 健康
docker compose ps
# 检查容器内配置(已挂载到 /app/backend/cmd/config.yaml)
docker compose exec backend cat /app/backend/cmd/config.yaml
```
3) 前端无法访问后端 API
```bash
# 容器内连通性
docker compose exec frontend sh -c "curl -sS http://backend:18888/health"
# 检查 nginx 配置
docker compose exec frontend cat /etc/nginx/conf.d/default.conf
```
## 注意事项
- 生产环境请修改默认账号、数据库口令与 JWT 秘钥(见 `backend/configs/config.prod.yaml`)。
- 如使用较新 Docker,YAML 顶部 `version` 字段会被忽略,可按需移除提示。
- `deploy.resources` 仅在 Swarm/K8s 生效,单机 Compose 可忽略。
- 如置于公网,建议仅暴露前端端口,通过前端或网关转发后端 API。
+17 -54
View File
@@ -22,7 +22,7 @@
- **前端**:Vue.js 3+ 配合现代化UI组件 - **前端**:Vue.js 3+ 配合现代化UI组件
- **后端**:Go 1.23+ 使用Gin框架、GORM、Viper配置和Logrus日志 - **后端**:Go 1.23+ 使用Gin框架、GORM、Viper配置和Logrus日志
- **数据库**:PostgreSQL 12+ / MySQL 8+ - **数据库**:MySQL 8+
- **配置**:YAML格式配置文件 - **配置**:YAML格式配置文件
- **部署**:Docker、单机部署或系统服务 - **部署**:Docker、单机部署或系统服务
@@ -52,73 +52,36 @@
```bash ```bash
# 克隆项目 # 克隆项目
git clone https://github.com/cedar-v/license-manager.git git clone https://github.com/cedar-v/license-manager.git
cd license-manager/backend/cmd cd license-manager
# 构建应用 # 本地后端构建与运行(可选)
cd backend/cmd
go build -o license-manager go build -o license-manager
# 配置应用 # 配置(二选一)
cp config.example.yaml config.yaml # 1) 在当前目录创建配置文件(程序优先读取工作目录下的 config.yaml)
# 编辑 config.yaml 配置文件 # cp ../configs/config.example.yaml ./config.yaml && 编辑
# 2) 直接编辑 ../configs/config.yaml(程序会自动回退读取该文件)
# 运行应用
./license-manager ./license-manager
``` ```
## Docker部署 ## Docker 部署
推荐使用 Docker Compose,已提供开发与生产编排文件:
```bash ```bash
# 构建Docker镜像(多阶段构建,包含前后端) # 开发环境(首次建议带 --build)
docker build -t license-manager . docker compose up -d --build
# 创建配置文件 # 生产环境
cp backend/configs/config.example.yaml config.yaml docker compose -f docker-compose.prod.yml up -d
# 编辑 config.yaml 配置数据库等信息
# 使用Docker运行 # 验证后端健康
docker run -d \
--name license-manager \
-p 18888:18888 \
-v $(pwd)/config.yaml:/app/config.yaml \
license-manager
# 查看运行状态
docker logs license-manager
# 健康检查
curl http://localhost:18888/health curl http://localhost:18888/health
``` ```
### Docker Compose部署(推荐) 完整部署说明(反向代理、健康检查、配置挂载等)请参见 `README-Docker.md`。
```yaml
# docker-compose.yml
version: '3.8'
services:
license-manager:
build: .
ports:
- "18888:18888"
volumes:
- ./config.yaml:/app/config.yaml
environment:
- GIN_MODE=release
restart: unless-stopped
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root@123
MYSQL_DATABASE: license_manager
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
restart: unless-stopped
volumes:
mysql_data:
```
## 开源许可证 ## 开源许可证
+22 -53
View File
@@ -22,7 +22,7 @@ License Manager is an independent software licensing platform that provides lice
- **Frontend**: Vue.js 3+ with modern UI components - **Frontend**: Vue.js 3+ with modern UI components
- **Backend**: Go 1.23+ with Gin framework, GORM, Viper configuration and Logrus logging - **Backend**: Go 1.23+ with Gin framework, GORM, Viper configuration and Logrus logging
- **Database**: PostgreSQL 12+ / MySQL 8+ - **Database**: MySQL 8+
- **Configuration**: YAML format configuration files - **Configuration**: YAML format configuration files
- **Deployment**: Docker, single machine, or system service - **Deployment**: Docker, single machine, or system service
@@ -63,73 +63,42 @@ GET /tools/{tool} - Tool download
```bash ```bash
# Clone the repository # Clone the repository
git clone https://github.com/cedar-v/license-manager.git git clone https://github.com/cedar-v/license-manager.git
cd license-manager/backend/cmd cd license-manager
# Build the application # Local backend build & run (optional)
cd backend/cmd
go build -o license-manager go build -o license-manager
# Configure the application # Configuration (choose one)
cp config.example.yaml config.yaml # 1) Create config.yaml in the working directory (the app looks here first)
# Edit config.yaml with your settings # cp ../configs/config.example.yaml ./config.yaml && edit it
# 2) Edit ../configs/config.yaml (the app will fall back to this path)
# Run the application
./license-manager ./license-manager
``` ```
## Docker Deployment ## Docker Deployment
We provide ready-to-use Docker Compose files for development and production:
```bash ```bash
# Build Docker image (multi-stage build with frontend and backend) # Development (first run with --build is recommended)
docker build -t license-manager . docker compose up -d --build
# Create configuration file # Production
cp backend/configs/config.example.yaml config.yaml docker compose -f docker-compose.prod.yml up -d
# Edit config.yaml to configure database and other settings
# Run with Docker # Verify backend health
docker run -d \
--name license-manager \
-p 18888:18888 \
-v $(pwd)/config.yaml:/app/config.yaml \
license-manager
# Check running status
docker logs license-manager
# Health check
curl http://localhost:18888/health curl http://localhost:18888/health
``` ```
### Docker Compose Deployment (Recommended) Notes
- Backend config is mounted by Compose:
```yaml - Dev: `backend/configs/config.dev.yaml` → `/app/backend/cmd/config.yaml`
# docker-compose.yml - Prod: `backend/configs/config.prod.yaml` → `/app/backend/cmd/config.yaml`
version: '3.8' - Frontend Nginx proxies `/api/` to `backend:18888` inside the Docker network.
services: - Health checks use `curl`; the backend image includes `curl`.
license-manager: - For full details (reverse proxy, health checks, mounts, troubleshooting), see `README-Docker.md`.
build: .
ports:
- "18888:18888"
volumes:
- ./config.yaml:/app/config.yaml
environment:
- GIN_MODE=release
restart: unless-stopped
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root@123
MYSQL_DATABASE: license_manager
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
restart: unless-stopped
volumes:
mysql_data:
```
## Open Source License ## Open Source License
+43
View File
@@ -0,0 +1,43 @@
server:
host: "0.0.0.0"
port: 18888
mode: "debug"
database:
driver: "mysql"
host: "mysql"
port: 3306
username: "license_user"
password: "license@123"
database: "license_manager"
charset: "utf8mb4"
parse_time: true
loc: "Local"
max_idle_conns: 10
max_open_conns: 100
conn_max_lifetime: 3600
auto_migrate: true
auth:
jwt:
secret: "license-manager-dev-secret-key-32-bytes"
expire_hours: 1
refresh_threshold_minutes: 30
admin:
username: "admin"
password: "admin@123"
security:
max_login_attempts: 5
lockout_duration_minutes: 15
log:
level: "info"
format: "text"
i18n:
enable: true
default_lang: "zh-CN"
config_path: "../configs/i18n/errors"
support_langs: ["zh-CN", "en-US", "ja-JP"]
+43
View File
@@ -0,0 +1,43 @@
server:
host: "0.0.0.0"
port: 18888
mode: "release"
database:
driver: "mysql"
host: "mysql"
port: 3306
username: "license_user"
password: "license@123"
database: "license_manager"
charset: "utf8mb4"
parse_time: true
loc: "Local"
max_idle_conns: 50
max_open_conns: 300
conn_max_lifetime: 3600
auto_migrate: true
auth:
jwt:
secret: "please-change-in-prod"
expire_hours: 1
refresh_threshold_minutes: 30
admin:
username: "admin"
password: "changeMe!"
security:
max_login_attempts: 5
lockout_duration_minutes: 15
log:
level: "info"
format: "json"
i18n:
enable: true
default_lang: "zh-CN"
config_path: "../configs/i18n/errors"
support_langs: ["zh-CN", "en-US", "ja-JP"]
+150
View File
@@ -0,0 +1,150 @@
version: '3.8'
services:
# MySQL 8数据库 - 生产环境优化配置
mysql:
image: mysql:8.0
container_name: license-manager-mysql-prod
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root@123}
MYSQL_DATABASE: license_manager
MYSQL_USER: license_user
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-license@123}
TZ: Asia/Shanghai
ports:
- "${MYSQL_PORT:-3306}:3306"
volumes:
- mysql_data:/var/lib/mysql
- ./mysql/conf.d:/etc/mysql/conf.d
command: >
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
--sql_mode=STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO
--max_connections=2000
--innodb_buffer_pool_size=512M
--innodb_log_file_size=256M
--slow_query_log=1
--slow_query_log_file=/var/lib/mysql/mysql-slow.log
--long_query_time=2
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
networks:
- license-manager-network
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# 后端服务 - 生产环境
backend:
image: ${BACKEND_IMAGE:-license-manager-backend:latest}
container_name: license-manager-backend-prod
restart: unless-stopped
environment:
- TZ=Asia/Shanghai
- GIN_MODE=release
ports:
- "${BACKEND_PORT:-18888}:18888"
volumes:
- ./backend/configs:/app/backend/configs:ro
- ./backend/configs/config.prod.yaml:/app/backend/cmd/config.yaml:ro
- ./logs:/app/logs
- ./data:/app/data
depends_on:
mysql:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:18888/health || exit 1"]
interval: 10s
timeout: 10s
retries: 6
start_period: 60s
networks:
- license-manager-network
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
memory: 512M
reservations:
memory: 256M
# 前端服务 - 生产环境
frontend:
image: ${FRONTEND_IMAGE:-license-manager-frontend:latest}
container_name: license-manager-frontend-prod
restart: unless-stopped
environment:
- TZ=Asia/Shanghai
ports:
- "${FRONTEND_PORT:-80}:80"
depends_on:
backend:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost/ || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
networks:
- license-manager-network
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
memory: 256M
reservations:
memory: 128M
# Redis缓存 (可选,用于session存储和缓存)
redis:
image: redis:7-alpine
container_name: license-manager-redis-prod
restart: unless-stopped
ports:
- "${REDIS_PORT:-6379}:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-redis@123}
healthcheck:
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
networks:
- license-manager-network
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
volumes:
mysql_data:
driver: local
redis_data:
driver: local
networks:
license-manager-network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
+91
View File
@@ -0,0 +1,91 @@
version: '3.8'
services:
# MySQL 8数据库
mysql:
image: mysql:8.0
container_name: license-manager-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: root@123
MYSQL_DATABASE: license_manager
MYSQL_USER: license_user
MYSQL_PASSWORD: license@123
TZ: Asia/Shanghai
ports:
- "13306:3306"
volumes:
- mysql_data:/var/lib/mysql
command: >
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
--sql_mode=STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO
--max_connections=1000
--innodb_buffer_pool_size=256M
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 30s
timeout: 10s
retries: 5
start_period: 30s
networks:
- license-manager-network
# 后端服务
backend:
build:
context: .
dockerfile: Dockerfile.backend
container_name: license-manager-backend
restart: unless-stopped
environment:
- TZ=Asia/Shanghai
ports:
- "18888:18888"
volumes:
- ./backend/configs:/app/backend/configs
- ./logs:/app/logs
- ./backend/configs/config.dev.yaml:/app/backend/cmd/config.yaml:ro
depends_on:
mysql:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:18888/health || exit 1"]
interval: 10s
timeout: 10s
retries: 6
start_period: 60s
networks:
- license-manager-network
# 前端服务
frontend:
build:
context: .
dockerfile: Dockerfile.frontend
container_name: license-manager-frontend
restart: unless-stopped
environment:
- TZ=Asia/Shanghai
ports:
- "18080:80"
depends_on:
backend:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost/ || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
networks:
- license-manager-network
volumes:
mysql_data:
driver: local
networks:
license-manager-network:
driver: bridge
+78
View File
@@ -0,0 +1,78 @@
## 使用 CI 产物镜像替换本地构建的部署方案
本文说明如何使用 GitHub Actions 构建并推送到 GHCR 的镜像,直接替换本地 `docker compose up -d --build` 的构建流程,以实现更一致、更快的部署。
### 前置条件
- 已通过仓库内工作流发布镜像:
- 后端:`.github/workflows/release_backend.yml`
- 前端:`.github/workflows/release_frontend.yml`
- 镜像仓库(GHCR)可访问:`ghcr.io/<owner>/<repo>-backend:<tag>`、`ghcr.io/<owner>/<repo>-frontend:<tag>`
- 已在部署机登录 GHCR:
```bash
docker login ghcr.io -u <YOUR_GITHUB_USER> -p <YOUR_GITHUB_TOKEN>
```
### 方式 A(推荐):直接使用生产编排(支持镜像变量)
生产编排文件 `docker-compose.prod.yml` 已支持通过环境变量替换镜像。
1) 在项目根目录创建 `.env`:
```env
# 指向 GHCR 镜像(可用具体版本号,如 v1.0.0)
BACKEND_IMAGE=ghcr.io/<owner>/<repo>-backend:latest
FRONTEND_IMAGE=ghcr.io/<owner>/<repo>-frontend:latest
# 可选:本地端口映射(如用于开发环境)
MYSQL_PORT=13306
BACKEND_PORT=18888
FRONTEND_PORT=18080
```
2) 启动:
```bash
docker compose -f docker-compose.prod.yml up -d
```
3) 验证:
```bash
curl http://localhost:18888/health
```
说明:
- 该方式同时适用于生产/准生产/本地测试场景,只需通过 `.env` 控制端口与镜像标签即可。
- 若镜像私有,请确保已成功 `docker login ghcr.io`。
### 方式 B:临时覆盖镜像(不创建 .env)
直接在一次性命令中覆盖镜像变量:
```bash
BACKEND_IMAGE=ghcr.io/<owner>/<repo>-backend:v1.0.0 \
FRONTEND_IMAGE=ghcr.io/<owner>/<repo>-frontend:v1.0.0 \
docker compose -f docker-compose.prod.yml up -d
```
### 常用操作
- 拉取新版本并滚动更新:
```bash
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d
```
- 回滚到上一版本:
```bash
# 修改 .env 中的镜像标签为上一个版本
docker compose -f docker-compose.prod.yml up -d
```
### 与开发编排的关系
- 当前开发编排 `docker-compose.yml` 使用 `build` 本地构建。如果希望开发环境也使用远端镜像,推荐直接沿用方式 A(使用 `docker-compose.prod.yml`,并通过 `.env` 调整端口为开发习惯)。
- 也可以手动修改 `docker-compose.yml`:将 `backend`、`frontend` 的 `build` 段替换为 `image: ${BACKEND_IMAGE}` / `image: ${FRONTEND_IMAGE}`,并在 `.env` 中声明对应镜像。
### 标签与架构
- CI 工作流默认推送 `latest` 与手动输入的版本号(如 `v1.0.0`),并构建多架构镜像:`linux/amd64, linux/arm64`。
- 生产环境建议使用显式版本标签部署,避免 `latest` 带来的不可预期变更。
### 故障排查
- 无法拉取镜像:检查 GHCR 登录权限、镜像是否设为公开或部署机是否具备读取私有包权限。
- 拉取缓慢或超时:配置镜像加速器或重试。
- 启动后访问异常:参考 `README-Docker.md` 的故障排查章节(健康检查、反向代理、容器间网络连通性等)。
+4 -2
View File
@@ -18,6 +18,8 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
// 加载环境变量文件(.env) // 加载环境变量文件(.env)
const env = loadEnv(mode, process.cwd()) const env = loadEnv(mode, process.cwd())
const enableVisualizer = isProd && env.VITE_VISUALIZER === 'true'
return { return {
// 基础公共路径,从环境变量VITE_ADDRESS_BASE_URL获取 // 基础公共路径,从环境变量VITE_ADDRESS_BASE_URL获取
base: env.VITE_ADDRESS_BASE_URL, base: env.VITE_ADDRESS_BASE_URL,
@@ -37,8 +39,8 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
ext: '.gz', // 压缩文件扩展名 ext: '.gz', // 压缩文件扩展名
}), }),
// 打包分析插件(仅生产环境启用) // 打包分析插件(仅在显式启用时生效;容器/CI 默认不打开浏览器)
isProd && visualizer({ open: true }) enableVisualizer && visualizer({ open: false })
].filter(Boolean), // 过滤掉false的插件 ].filter(Boolean), // 过滤掉false的插件
// 开发服务器配置 // 开发服务器配置
+3 -2
View File
@@ -39,9 +39,10 @@ server {
access_log off; access_log off;
} }
# API proxy to backend (if backend is on the same server) # API proxy to backend (container network)
location /api/ { location /api/ {
proxy_pass http://host.docker.internal:18888/api/; # Keep original request path; backend service name resolves inside Docker network
proxy_pass http://backend:18888;
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;