feat:自动构建
This commit is contained in:
1 parent
183f5e7896
commit
6bcd8f4d09
14 files changed
+752
-112
No files matched your search
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -7,7 +7,7 @@ COPY backend/ ./
|
||||
RUN go build -ldflags="-s -w" -o license-manager cmd/main.go
|
||||
|
||||
FROM alpine:latest
|
||||
RUN apk --no-cache add ca-certificates tzdata
|
||||
RUN apk --no-cache add ca-certificates tzdata curl
|
||||
WORKDIR /app/backend/cmd
|
||||
COPY --from=builder /app/backend/license-manager ./license-manager
|
||||
COPY backend/configs/ ../configs/
|
||||
|
||||
@@ -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。
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
- **前端**:Vue.js 3+ 配合现代化UI组件
|
||||
- **后端**:Go 1.23+ 使用Gin框架、GORM、Viper配置和Logrus日志
|
||||
- **数据库**:PostgreSQL 12+ / MySQL 8+
|
||||
- **数据库**:MySQL 8+
|
||||
- **配置**:YAML格式配置文件
|
||||
- **部署**:Docker、单机部署或系统服务
|
||||
|
||||
@@ -52,73 +52,36 @@
|
||||
```bash
|
||||
# 克隆项目
|
||||
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
|
||||
|
||||
# 配置应用
|
||||
cp config.example.yaml config.yaml
|
||||
# 编辑 config.yaml 配置文件
|
||||
# 配置(二选一)
|
||||
# 1) 在当前目录创建配置文件(程序优先读取工作目录下的 config.yaml)
|
||||
# cp ../configs/config.example.yaml ./config.yaml && 编辑
|
||||
# 2) 直接编辑 ../configs/config.yaml(程序会自动回退读取该文件)
|
||||
|
||||
# 运行应用
|
||||
./license-manager
|
||||
```
|
||||
|
||||
## Docker部署
|
||||
## Docker 部署
|
||||
|
||||
推荐使用 Docker Compose,已提供开发与生产编排文件:
|
||||
|
||||
```bash
|
||||
# 构建Docker镜像(多阶段构建,包含前后端)
|
||||
docker build -t license-manager .
|
||||
# 开发环境(首次建议带 --build)
|
||||
docker compose up -d --build
|
||||
|
||||
# 创建配置文件
|
||||
cp backend/configs/config.example.yaml config.yaml
|
||||
# 编辑 config.yaml 配置数据库等信息
|
||||
# 生产环境
|
||||
docker compose -f docker-compose.prod.yml up -d
|
||||
|
||||
# 使用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
|
||||
```
|
||||
|
||||
### Docker Compose部署(推荐)
|
||||
|
||||
```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:
|
||||
```
|
||||
完整部署说明(反向代理、健康检查、配置挂载等)请参见 `README-Docker.md`。
|
||||
|
||||
## 开源许可证
|
||||
|
||||
|
||||
+22
-53
@@ -22,7 +22,7 @@ License Manager is an independent software licensing platform that provides lice
|
||||
|
||||
- **Frontend**: Vue.js 3+ with modern UI components
|
||||
- **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
|
||||
- **Deployment**: Docker, single machine, or system service
|
||||
|
||||
@@ -63,73 +63,42 @@ GET /tools/{tool} - Tool download
|
||||
```bash
|
||||
# Clone the repository
|
||||
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
|
||||
|
||||
# Configure the application
|
||||
cp config.example.yaml config.yaml
|
||||
# Edit config.yaml with your settings
|
||||
# Configuration (choose one)
|
||||
# 1) Create config.yaml in the working directory (the app looks here first)
|
||||
# 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
|
||||
```
|
||||
|
||||
## Docker Deployment
|
||||
|
||||
We provide ready-to-use Docker Compose files for development and production:
|
||||
|
||||
```bash
|
||||
# Build Docker image (multi-stage build with frontend and backend)
|
||||
docker build -t license-manager .
|
||||
# Development (first run with --build is recommended)
|
||||
docker compose up -d --build
|
||||
|
||||
# Create configuration file
|
||||
cp backend/configs/config.example.yaml config.yaml
|
||||
# Edit config.yaml to configure database and other settings
|
||||
# Production
|
||||
docker compose -f docker-compose.prod.yml up -d
|
||||
|
||||
# Run with Docker
|
||||
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
|
||||
# Verify backend health
|
||||
curl http://localhost:18888/health
|
||||
```
|
||||
|
||||
### Docker Compose Deployment (Recommended)
|
||||
|
||||
```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:
|
||||
```
|
||||
Notes
|
||||
- Backend config is mounted by Compose:
|
||||
- Dev: `backend/configs/config.dev.yaml` → `/app/backend/cmd/config.yaml`
|
||||
- Prod: `backend/configs/config.prod.yaml` → `/app/backend/cmd/config.yaml`
|
||||
- Frontend Nginx proxies `/api/` to `backend:18888` inside the Docker network.
|
||||
- Health checks use `curl`; the backend image includes `curl`.
|
||||
- For full details (reverse proxy, health checks, mounts, troubleshooting), see `README-Docker.md`.
|
||||
|
||||
## Open Source License
|
||||
|
||||
|
||||
@@ -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"]
|
||||
|
||||
|
||||
@@ -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"]
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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` 的故障排查章节(健康检查、反向代理、容器间网络连通性等)。
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||
// 加载环境变量文件(.env)
|
||||
const env = loadEnv(mode, process.cwd())
|
||||
|
||||
const enableVisualizer = isProd && env.VITE_VISUALIZER === 'true'
|
||||
|
||||
return {
|
||||
// 基础公共路径,从环境变量VITE_ADDRESS_BASE_URL获取
|
||||
base: env.VITE_ADDRESS_BASE_URL,
|
||||
@@ -37,8 +39,8 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||
ext: '.gz', // 压缩文件扩展名
|
||||
}),
|
||||
|
||||
// 打包分析插件(仅生产环境启用)
|
||||
isProd && visualizer({ open: true })
|
||||
// 打包分析插件(仅在显式启用时生效;容器/CI 默认不打开浏览器)
|
||||
enableVisualizer && visualizer({ open: false })
|
||||
].filter(Boolean), // 过滤掉false的插件
|
||||
|
||||
// 开发服务器配置
|
||||
|
||||
+3
-2
@@ -39,9 +39,10 @@ server {
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# API proxy to backend (if backend is on the same server)
|
||||
# API proxy to backend (container network)
|
||||
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 X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
Reference in new issue
Block a user