This commit is contained in:
zheng020 2026-01-05 01:46:20 +08:00
parent 09842a2611
commit 3793cc3252
50 changed files with 16740 additions and 0 deletions

7
.gitattributes vendored Normal file
View File

@ -0,0 +1,7 @@
# 强制 shell 脚本、配置文件等使用 LF
*.sh text eol=lf
*.env text eol=lf
.env.* text eol=lf
# 可选:所有文本文件统一用 LF更严格
# * text=auto eol=lf

View File

@ -0,0 +1,309 @@
# Design Document: Docker Deployment
## Overview
本设计文档描述了若依框架项目的前后端分离Docker部署方案。该方案将Vue3前端应用、Spring Boot后端应用和MySQL数据库分别容器化通过Docker Compose进行统一编排和管理。
系统采用微服务架构前端通过Nginx提供静态文件服务并代理API请求到后端服务后端连接到独立的数据库容器实现完全的容器化部署。
## Architecture
### 整体架构图
```mermaid
graph TB
subgraph "Docker Host"
subgraph "Frontend Container"
A[Nginx + Vue3 Static Files]
end
subgraph "Backend Container"
B[Spring Boot Application]
end
subgraph "Database Container"
C[MySQL Database]
end
subgraph "Volumes"
D[Database Data Volume]
E[Log Volume]
F[Config Volume]
end
end
G[External Users] --> A
A --> B
B --> C
C --> D
B --> E
A --> F
B --> F
```
### 网络架构
```mermaid
graph LR
subgraph "External Network"
U[Users]
end
subgraph "Docker Network: anxin-network"
F[Frontend:80]
B[Backend:8080]
D[Database:3306]
end
U -->|HTTP:80| F
F -->|API Proxy| B
B -->|MySQL Connection| D
```
## Components and Interfaces
### 1. Frontend Container (anxin-frontend)
**基础镜像**: nginx:alpine
**构建方式**: 多阶段构建
**第一阶段 - 构建阶段**:
- 基础镜像: node:18-alpine
- 工作目录: /app
- 复制源码并执行npm构建
- 输出: dist目录包含构建后的静态文件
**第二阶段 - 运行阶段**:
- 基础镜像: nginx:alpine
- 复制构建产物到nginx默认目录
- 配置nginx.conf用于静态文件服务和API代理
- 暴露端口: 80
**Nginx配置要点**:
```nginx
server {
listen 80;
server_name localhost;
# 静态文件服务
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
# API代理
location /prod-api/ {
proxy_pass http://anxin-backend:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
```
### 2. Backend Container (anxin-backend)
**基础镜像**: openjdk:8-jre-alpine
**构建方式**: 多阶段构建
**第一阶段 - 构建阶段**:
- 基础镜像: maven:3.8-openjdk-8
- 工作目录: /app
- 复制pom.xml和源码
- 执行Maven构建: mvn clean package -DskipTests
- 输出: target目录包含JAR文件
**第二阶段 - 运行阶段**:
- 基础镜像: openjdk:8-jre-alpine
- 复制JAR文件到容器
- 设置启动命令
- 暴露端口: 8080
**环境变量配置**:
- `SPRING_PROFILES_ACTIVE`: 激活的配置文件
- `SPRING_DATASOURCE_URL`: 数据库连接URL
- `SPRING_DATASOURCE_USERNAME`: 数据库用户名
- `SPRING_DATASOURCE_PASSWORD`: 数据库密码
### 3. Database Container (anxin-mysql)
**基础镜像**: mysql:8.0
**配置要点**:
- 数据持久化: 挂载数据卷到/var/lib/mysql
- 初始化脚本: 挂载SQL文件到/docker-entrypoint-initdb.d/
- 字符集配置: utf8mb4
- 暴露端口: 3306
**环境变量**:
- `MYSQL_ROOT_PASSWORD`: root用户密码
- `MYSQL_DATABASE`: 默认数据库名
- `MYSQL_USER`: 应用用户名
- `MYSQL_PASSWORD`: 应用用户密码
### 4. Docker Compose编排
**服务依赖关系**:
```yaml
services:
anxin-mysql:
# 数据库服务,最先启动
anxin-backend:
depends_on:
- anxin-mysql
# 后端服务,依赖数据库
anxin-frontend:
depends_on:
- anxin-backend
# 前端服务,依赖后端
```
**网络配置**:
- 创建自定义网络: anxin-network
- 所有服务连接到同一网络
- 服务间通过服务名进行通信
**卷挂载**:
- 数据库数据卷: mysql-data
- 日志卷: logs
- 配置文件卷: configs
## Data Models
### 容器配置模型
```yaml
# Docker Compose配置结构
version: '3.8'
services:
service_name:
build:
context: string
dockerfile: string
image: string
container_name: string
ports:
- "host_port:container_port"
environment:
- KEY=VALUE
volumes:
- volume_name:container_path
networks:
- network_name
depends_on:
- dependency_service
```
### 构建脚本配置模型
```bash
# 环境配置结构
ENVIRONMENT=production|staging|development
DB_HOST=string
DB_PORT=number
DB_NAME=string
DB_USER=string
DB_PASSWORD=string
BACKEND_PORT=number
FRONTEND_PORT=number
```
## Correctness Properties
*A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
### Property 1: Container Build Verification
*For any* Docker container build process, the resulting container should contain all required application artifacts (static files for frontend, JAR files for backend)
**Validates: Requirements 1.1, 2.1**
### Property 2: Service Connectivity
*For any* multi-container deployment, when all containers are started, each service should be able to communicate with its dependencies (frontend to backend, backend to database)
**Validates: Requirements 1.2, 1.3, 2.2**
### Property 3: Port Configuration
*For any* container configuration, the specified ports should be correctly exposed and accessible from the host system
**Validates: Requirements 1.5, 2.3, 3.4**
### Property 4: Build Process Execution
*For any* build script execution, the script should successfully complete all build steps (npm build for frontend, Maven build for backend) without errors
**Validates: Requirements 1.4, 2.4**
### Property 5: Database Initialization
*For any* database container startup, the container should successfully initialize the database schema and execute all provided SQL scripts
**Validates: Requirements 3.2, 3.5**
### Property 6: Data Persistence
*For any* database container restart, previously stored data should remain intact through volume mounting
**Validates: Requirements 3.3**
### Property 7: Service Orchestration
*For any* Docker Compose deployment, services should start in the correct dependency order and establish proper network communication
**Validates: Requirements 4.1, 4.2, 4.3, 4.5**
### Property 8: Volume Configuration
*For any* Docker Compose configuration, all specified volumes should be correctly mounted and accessible to their respective containers
**Validates: Requirements 4.4**
### Property 9: Build Script Functionality
*For any* deployment script execution, the script should successfully build all images, pull latest code, and verify service availability
**Validates: Requirements 5.1, 5.2, 5.5**
### Property 10: Environment Configuration Management
*For any* environment parameter change, the build script should correctly apply the new configuration and load the appropriate configuration files
**Validates: Requirements 5.3, 6.1, 6.2, 6.3, 6.4, 6.5**
### Property 11: Logging and Monitoring
*For any* script execution, sufficient logging information should be provided to enable troubleshooting and monitoring
**Validates: Requirements 5.4**
## Error Handling
### 容器启动失败处理
- **数据库连接失败**: 后端容器应实现重试机制,等待数据库容器完全启动
- **端口冲突**: 提供清晰的错误信息并建议解决方案
- **镜像构建失败**: 详细记录构建日志,便于问题定位
### 网络连接问题
- **服务间通信失败**: 验证网络配置和服务发现机制
- **外部访问问题**: 检查端口映射和防火墙配置
- **DNS解析问题**: 确保容器间能够通过服务名正确解析
### 数据持久化问题
- **卷挂载失败**: 验证宿主机目录权限和路径存在性
- **数据丢失**: 实现数据备份和恢复机制
- **存储空间不足**: 监控磁盘使用情况并提供告警
### 构建脚本错误处理
- **依赖下载失败**: 配置镜像源和重试机制
- **权限问题**: 提供明确的权限要求说明
- **环境变量缺失**: 验证必需的环境变量并提供默认值
## Testing Strategy
### 单元测试方法
- **Dockerfile语法验证**: 使用hadolint等工具验证Dockerfile语法
- **配置文件验证**: 验证nginx.conf、docker-compose.yml等配置文件的正确性
- **脚本语法检查**: 使用shellcheck验证shell脚本语法
### 集成测试方法
- **容器构建测试**: 验证每个容器能够成功构建
- **服务启动测试**: 验证所有服务能够正确启动并建立连接
- **端到端测试**: 从外部访问验证整个系统的功能完整性
### 属性测试配置
使用Docker和shell脚本进行属性测试每个属性测试运行最少100次迭代
- **测试框架**: 使用Bash测试框架如bats-core
- **测试环境**: 在隔离的Docker环境中运行测试
- **测试数据**: 使用不同的环境配置和数据集进行测试
- **测试标签格式**: **Feature: docker-deployment, Property {number}: {property_text}**
### 性能测试
- **容器启动时间**: 测量各容器的启动时间
- **资源使用情况**: 监控CPU、内存、磁盘使用情况
- **并发访问测试**: 测试系统在高并发情况下的表现
### 安全测试
- **镜像安全扫描**: 使用工具扫描镜像中的安全漏洞
- **网络安全**: 验证容器间网络隔离和访问控制
- **敏感信息保护**: 确保密码等敏感信息不会暴露在镜像中

View File

@ -0,0 +1,88 @@
# Requirements Document
## Introduction
为若依框架项目创建前后端分离的Docker部署方案包括前端Vue3应用和后端Spring Boot应用的独立容器化部署脚本。
## Glossary
- **Frontend_Container**: Vue3前端应用的Docker容器
- **Backend_Container**: Spring Boot后端应用的Docker容器
- **Docker_Compose**: 用于编排多容器应用的工具
- **Nginx_Proxy**: 用于前端静态文件服务和API代理的反向代理服务器
- **Database_Container**: MySQL数据库容器
- **Build_Script**: 构建和部署脚本
## Requirements
### Requirement 1: 前端容器化部署
**User Story:** 作为运维人员我希望将Vue3前端应用容器化部署以便实现环境一致性和快速部署。
#### Acceptance Criteria
1. THE Frontend_Container SHALL 包含构建好的Vue3静态文件
2. WHEN 前端容器启动时THE Nginx_Proxy SHALL 提供静态文件服务
3. THE Frontend_Container SHALL 配置API代理到后端服务
4. WHEN 构建前端镜像时THE Build_Script SHALL 执行npm构建流程
5. THE Frontend_Container SHALL 暴露80端口用于HTTP访问
### Requirement 2: 后端容器化部署
**User Story:** 作为运维人员我希望将Spring Boot后端应用容器化部署以便实现独立的服务部署和扩展。
#### Acceptance Criteria
1. THE Backend_Container SHALL 包含编译好的Spring Boot JAR文件
2. WHEN 后端容器启动时THE Backend_Container SHALL 连接到数据库
3. THE Backend_Container SHALL 暴露8080端口用于API访问
4. WHEN 构建后端镜像时THE Build_Script SHALL 执行Maven构建流程
5. THE Backend_Container SHALL 配置环境变量用于数据库连接
### Requirement 3: 数据库容器化部署
**User Story:** 作为运维人员,我希望数据库也能容器化部署,以便实现完整的容器化环境。
#### Acceptance Criteria
1. THE Database_Container SHALL 使用MySQL镜像
2. WHEN 数据库容器启动时THE Database_Container SHALL 初始化数据库结构
3. THE Database_Container SHALL 持久化数据到宿主机卷
4. THE Database_Container SHALL 暴露3306端口
5. WHEN 初始化时THE Database_Container SHALL 执行SQL初始化脚本
### Requirement 4: 容器编排和网络配置
**User Story:** 作为运维人员我希望通过Docker Compose统一管理所有容器以便简化部署和维护。
#### Acceptance Criteria
1. THE Docker_Compose SHALL 定义所有服务的依赖关系
2. WHEN 启动服务时THE Docker_Compose SHALL 按正确顺序启动容器
3. THE Docker_Compose SHALL 创建内部网络用于容器间通信
4. THE Docker_Compose SHALL 配置卷挂载用于数据持久化
5. WHEN 服务启动时THE Docker_Compose SHALL 等待依赖服务就绪
### Requirement 5: 构建和部署脚本
**User Story:** 作为开发人员,我希望有自动化的构建和部署脚本,以便快速部署应用到不同环境。
#### Acceptance Criteria
1. THE Build_Script SHALL 提供一键构建所有镜像的功能
2. WHEN 执行部署脚本时THE Build_Script SHALL 自动拉取最新代码
3. THE Build_Script SHALL 支持不同环境的配置切换
4. THE Build_Script SHALL 提供日志输出用于问题排查
5. WHEN 部署完成时THE Build_Script SHALL 验证服务可用性
### Requirement 6: 环境配置管理
**User Story:** 作为运维人员,我希望能够灵活配置不同环境的参数,以便在开发、测试、生产环境中使用。
#### Acceptance Criteria
1. THE Build_Script SHALL 支持通过环境变量配置数据库连接
2. THE Build_Script SHALL 支持配置前端API基础URL
3. THE Build_Script SHALL 支持配置容器资源限制
4. THE Build_Script SHALL 支持配置日志级别和输出路径
5. WHEN 切换环境时THE Build_Script SHALL 加载对应的配置文件

View File

@ -0,0 +1,176 @@
# Implementation Plan: Docker Deployment
## Overview
本实现计划将若依框架项目转换为前后端分离的Docker部署方案。使用Bash脚本实现自动化构建和部署通过Docker Compose编排多容器应用实现完整的容器化部署流程。
## Tasks
- [x] 1. 创建项目Docker化基础结构
- 创建docker目录结构
- 设置基础配置文件模板
- 创建环境变量配置文件
- _Requirements: 6.1, 6.5_
- [ ] 2. 实现前端容器化
- [x] 2.1 创建前端Dockerfile
- 编写多阶段构建的Dockerfile
- 配置Node.js构建环境
- 配置Nginx运行环境
- _Requirements: 1.1, 1.4_
- [ ]* 2.2 编写前端容器构建属性测试
- **Property 1: Container Build Verification (Frontend)**
- **Validates: Requirements 1.1**
- [x] 2.3 创建Nginx配置文件
- 配置静态文件服务
- 配置API代理规则
- 设置端口和路径映射
- _Requirements: 1.2, 1.3, 1.5_
- [ ]* 2.4 编写前端服务连接属性测试
- **Property 2: Service Connectivity (Frontend)**
- **Validates: Requirements 1.2, 1.3**
- [ ] 3. 实现后端容器化
- [x] 3.1 创建后端Dockerfile
- 编写多阶段构建的Dockerfile
- 配置Maven构建环境
- 配置JRE运行环境
- _Requirements: 2.1, 2.4_
- [ ]* 3.2 编写后端容器构建属性测试
- **Property 1: Container Build Verification (Backend)**
- **Validates: Requirements 2.1**
- [x] 3.3 配置后端环境变量和连接
- 设置数据库连接环境变量
- 配置应用端口和网络
- 设置日志和监控配置
- _Requirements: 2.2, 2.3, 2.5_
- [ ]* 3.4 编写后端数据库连接属性测试
- **Property 2: Service Connectivity (Backend)**
- **Validates: Requirements 2.2**
- [ ] 4. 实现数据库容器化
- [x] 4.1 创建数据库Docker配置
- 配置MySQL容器参数
- 设置数据卷挂载
- 配置初始化脚本路径
- _Requirements: 3.1, 3.3, 3.4_
- [x] 4.2 准备数据库初始化脚本
- 复制现有SQL文件到初始化目录
- 配置数据库用户和权限
- 设置字符集和时区
- _Requirements: 3.2, 3.5_
- [ ]* 4.3 编写数据库初始化属性测试
- **Property 5: Database Initialization**
- **Validates: Requirements 3.2, 3.5**
- [ ]* 4.4 编写数据持久化属性测试
- **Property 6: Data Persistence**
- **Validates: Requirements 3.3**
- [ ] 5. 创建Docker Compose编排配置
- [x] 5.1 编写docker-compose.yml
- 定义所有服务配置
- 设置服务依赖关系
- 配置网络和卷
- _Requirements: 4.1, 4.2, 4.3, 4.4_
- [x] 5.2 配置环境特定的compose文件
- 创建开发环境配置
- 创建生产环境配置
- 创建测试环境配置
- _Requirements: 5.3, 6.5_
- [ ]* 5.3 编写服务编排属性测试
- **Property 7: Service Orchestration**
- **Validates: Requirements 4.1, 4.2, 4.3, 4.5**
- [ ]* 5.4 编写卷配置属性测试
- **Property 8: Volume Configuration**
- **Validates: Requirements 4.4**
- [x] 6. 检查点 - 验证容器配置
- 确保所有Dockerfile和配置文件语法正确如有问题请询问用户
- [ ] 7. 实现构建和部署脚本
- [x] 7.1 创建主构建脚本 (build.sh)
- 实现一键构建所有镜像功能
- 添加代码拉取和更新功能
- 实现环境配置切换
- _Requirements: 5.1, 5.2, 5.3_
- [ ]* 7.2 编写构建脚本功能属性测试
- **Property 9: Build Script Functionality**
- **Validates: Requirements 5.1, 5.2, 5.5**
- [x] 7.3 创建部署脚本 (deploy.sh)
- 实现服务启动和停止功能
- 添加服务健康检查
- 实现日志查看功能
- _Requirements: 5.4, 5.5_
- [ ]* 7.4 编写日志和监控属性测试
- **Property 11: Logging and Monitoring**
- **Validates: Requirements 5.4**
- [x] 7.5 创建环境管理脚本 (env-config.sh)
- 实现环境变量配置管理
- 支持不同环境的参数切换
- 添加配置验证功能
- _Requirements: 6.1, 6.2, 6.3, 6.4_
- [ ]* 7.6 编写环境配置管理属性测试
- **Property 10: Environment Configuration Management**
- **Validates: Requirements 6.1, 6.2, 6.3, 6.4, 6.5**
- [ ] 8. 实现端口配置和网络测试
- [ ] 8.1 添加端口配置验证
- 验证所有容器端口正确暴露
- 检查端口冲突
- 测试外部访问连通性
- _Requirements: 1.5, 2.3, 3.4_
- [ ]* 8.2 编写端口配置属性测试
- **Property 3: Port Configuration**
- **Validates: Requirements 1.5, 2.3, 3.4**
- [ ] 8.3 实现构建流程验证
- 验证npm构建流程
- 验证Maven构建流程
- 添加构建错误处理
- _Requirements: 1.4, 2.4_
- [ ]* 8.4 编写构建流程属性测试
- **Property 4: Build Process Execution**
- **Validates: Requirements 1.4, 2.4**
- [ ] 9. 创建文档和使用说明
- [x] 9.1 编写部署文档 (README.md)
- 创建快速开始指南
- 添加环境要求说明
- 提供故障排除指南
- _Requirements: 5.4_
- [x] 9.2 创建配置示例文件
- 提供各环境的配置模板
- 添加配置参数说明
- 创建环境变量示例
- _Requirements: 6.1, 6.2, 6.3, 6.4_
- [ ] 10. 最终检查点 - 完整系统测试
- 确保所有测试通过,完整的端到端部署流程正常工作,如有问题请询问用户
## Notes
- 标记有 `*` 的任务是可选的可以跳过以实现更快的MVP
- 每个任务都引用了具体的需求以确保可追溯性
- 检查点确保增量验证
- 属性测试验证通用正确性属性
- 单元测试验证具体示例和边界情况

26
docker/.gitignore vendored Normal file
View File

@ -0,0 +1,26 @@
# Docker部署相关忽略文件
# 环境配置文件 (除了示例文件)
.env
.env.local
# 数据目录
data/
logs/
# 生成的配置文件
docker-compose.yml
configs/nginx.conf
configs/application-docker.yml
configs/my.cnf
# Docker相关
.docker/
# 临时文件
*.tmp
*.log
# 备份文件
*.bak
*.backup

929
docker/README.md Normal file
View File

@ -0,0 +1,929 @@
# 若依框架 Docker 部署文档
本文档提供若依框架项目的完整Docker化部署方案包括前后端分离架构的容器化部署、环境配置管理和故障排除指南。
## 📋 目录
- [项目概述](#项目概述)
- [快速开始](#快速开始)
- [环境要求](#环境要求)
- [目录结构](#目录结构)
- [详细部署步骤](#详细部署步骤)
- [环境配置](#环境配置)
- [服务管理](#服务管理)
- [监控和日志](#监控和日志)
- [故障排除](#故障排除)
- [性能优化](#性能优化)
- [安全配置](#安全配置)
- [常见问题](#常见问题)
## 🚀 项目概述
本部署方案将若依框架项目容器化,实现:
- **前后端分离**Vue3前端 + Spring Boot后端独立部署
- **数据库容器化**MySQL 8.0容器化部署
- **环境隔离**:支持开发、测试、生产环境配置
- **自动化部署**:一键构建、部署和管理脚本
- **服务监控**:健康检查和日志管理
### 架构图
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Frontend │ │ Backend │ │ Database │
│ (Vue3+Nginx) │───▶│ (Spring Boot) │───▶│ (MySQL) │
│ Port: 80 │ │ Port: 8080 │ │ Port: 3306 │
└─────────────────┘ └─────────────────┘ └─────────────────┘
```
## ⚡ 快速开始
### 1. 环境准备
确保系统已安装必要的软件:
```bash
# 检查Docker版本
docker --version
docker-compose --version
# 检查系统资源
free -h
df -h
```
### 2. 配置环境
```bash
# 1. 进入Docker目录
cd docker
# 2. 复制环境配置文件
cp environments/.env.example environments/.env.development
# 3. 编辑配置文件(根据需要修改)
vim environments/.env.development
```
### 3. 一键部署
```bash
# 开发环境部署
./build.sh deploy -e development
# 或者分步执行
./build.sh build-all -e development # 构建镜像
./deploy.sh start -e development # 启动服务
```
### 4. 验证部署
```bash
# 检查服务状态
./deploy.sh status -e development
# 执行健康检查
./deploy.sh health -e development --wait
# 访问应用
# 前端: http://localhost:80
# 后端API: http://localhost:8080
```
## 🔧 环境要求
### 系统要求
| 组件 | 最低要求 | 推荐配置 |
|------|----------|----------|
| **操作系统** | Linux/macOS/Windows | Ubuntu 20.04+ / CentOS 8+ |
| **CPU** | 2核心 | 4核心+ |
| **内存** | 4GB | 8GB+ |
| **磁盘空间** | 10GB | 20GB+ |
| **网络** | 100Mbps | 1Gbps+ |
### 软件依赖
| 软件 | 版本要求 | 安装命令 |
|------|----------|----------|
| **Docker** | 20.10+ | `curl -fsSL https://get.docker.com \| sh` |
| **Docker Compose** | 2.0+ | 随Docker Desktop安装 |
| **Git** | 2.0+ | `apt install git` / `yum install git` |
| **Bash** | 4.0+ | 系统自带 |
### 端口要求
确保以下端口未被占用:
| 服务 | 默认端口 | 可配置 | 说明 |
|------|----------|--------|------|
| 前端服务 | 80 | ✅ | HTTP访问端口 |
| 后端服务 | 8080 | ✅ | API服务端口 |
| 数据库 | 3306 | ✅ | MySQL连接端口 |
## 📁 目录结构
```
docker/
├── README.md # 本文档
├── build.sh # 主构建脚本
├── deploy.sh # 部署管理脚本
├── docker-compose.yml # 基础编排文件
├── docker-compose.*.yml # 环境特定编排文件
├── validation-report.md # 验证报告
├── frontend/ # 前端容器配置
│ ├── Dockerfile # 前端镜像构建文件
│ └── nginx.conf.* # Nginx配置文件
├── backend/ # 后端容器配置
│ ├── Dockerfile # 后端镜像构建文件
│ └── startup.sh # 启动脚本
├── database/ # 数据库配置
│ ├── docker-compose.database.yml
│ ├── init/ # 初始化脚本
│ └── README.md
├── environments/ # 环境配置
│ ├── .env.example # 配置模板
│ ├── .env.development # 开发环境
│ ├── .env.staging # 测试环境
│ └── .env.production # 生产环境
├── configs/ # 配置文件模板
│ ├── nginx.conf.* # Nginx配置模板
│ ├── application-docker.yml # Spring Boot配置
│ └── my.cnf.* # MySQL配置
├── scripts/ # 辅助脚本
│ ├── env-config.sh # 环境配置管理
│ ├── validate-*.sh # 配置验证脚本
│ ├── backup.sh # 数据备份脚本
│ └── setup-env.sh # 环境初始化
└── data/ # 数据目录(运行时创建)
├── mysql/ # 数据库数据
├── logs/ # 日志文件
└── uploads/ # 上传文件
```
## 📖 详细部署步骤
### 步骤1环境配置
#### 1.1 创建环境配置文件
```bash
# 复制配置模板
cp environments/.env.example environments/.env.development
# 编辑配置文件
vim environments/.env.development
```
#### 1.2 关键配置项说明
```bash
# 基础环境配置
ENVIRONMENT=development # 环境标识
COMPOSE_PROJECT_NAME=anxin # Docker Compose项目名
# 数据库配置
DB_HOST=anxin-mysql # 数据库主机
DB_PORT=3306 # 数据库端口
DB_NAME=anxin # 数据库名
DB_USER=anxin_user # 数据库用户
DB_PASSWORD=your_secure_password # 数据库密码
# 服务端口配置
FRONTEND_PORT=80 # 前端服务端口
BACKEND_PORT=8080 # 后端服务端口
# 资源限制配置
BACKEND_MEMORY_LIMIT=1024 # 后端内存限制(MB)
DATABASE_MEMORY_LIMIT=512 # 数据库内存限制(MB)
```
### 步骤2构建镜像
#### 2.1 构建所有镜像
```bash
# 构建所有镜像(开发环境)
./build.sh build-all -e development
# 构建特定组件
./build.sh build -c frontend -e development
./build.sh build -c backend -e development
# 强制重新构建(不使用缓存)
./build.sh build-all -e development --no-cache
```
#### 2.2 构建选项说明
| 选项 | 说明 | 示例 |
|------|------|------|
| `-e, --env` | 指定环境 | `-e production` |
| `-c, --component` | 指定组件 | `-c frontend` |
| `--pull` | 构建前拉取代码 | `--pull` |
| `--no-cache` | 不使用构建缓存 | `--no-cache` |
| `--clean` | 清理构建缓存 | `--clean` |
| `--verbose` | 显示详细日志 | `--verbose` |
### 步骤3启动服务
#### 3.1 启动所有服务
```bash
# 启动所有服务
./deploy.sh start -e development
# 启动特定服务
./deploy.sh start mysql -e development
./deploy.sh start backend frontend -e development
```
#### 3.2 服务管理命令
```bash
# 查看服务状态
./deploy.sh status -e development
# 重启服务
./deploy.sh restart -e development
# 停止服务
./deploy.sh stop -e development
# 完全清理(删除容器和网络)
./deploy.sh down -e development
```
### 步骤4验证部署
#### 4.1 健康检查
```bash
# 执行健康检查
./deploy.sh health -e development
# 等待所有服务健康
./deploy.sh health -e development --wait --retry 10
```
#### 4.2 访问测试
```bash
# 测试前端访问
curl -I http://localhost:80
# 测试后端API
curl -I http://localhost:8080/actuator/health
# 测试数据库连接
mysql -h localhost -P 3306 -u anxin_user -p
```
## ⚙️ 环境配置
### 开发环境 (Development)
```bash
# 特点:启用调试模式,详细日志,热重载
ENVIRONMENT=development
LOG_LEVEL=DEBUG
SPRING_PROFILES_ACTIVE=docker,dev
```
### 测试环境 (Staging)
```bash
# 特点:接近生产配置,性能测试
ENVIRONMENT=staging
LOG_LEVEL=INFO
SPRING_PROFILES_ACTIVE=docker,staging
```
### 生产环境 (Production)
```bash
# 特点:优化性能,安全配置,监控
ENVIRONMENT=production
LOG_LEVEL=WARN
SPRING_PROFILES_ACTIVE=docker,prod
```
### 环境切换
```bash
# 切换到生产环境
./build.sh deploy -e production --pull
# 切换到开发环境
./deploy.sh restart -e development
```
## 🔄 服务管理
### 启动服务
```bash
# 启动所有服务
./deploy.sh start
# 启动特定服务
./deploy.sh start mysql
./deploy.sh start backend frontend
# 强制重新创建容器
./deploy.sh start --force
```
### 停止服务
```bash
# 停止所有服务
./deploy.sh stop
# 停止特定服务
./deploy.sh stop backend
# 设置停止超时时间
./deploy.sh stop -t 60
```
### 重启服务
```bash
# 重启所有服务
./deploy.sh restart
# 重启特定服务
./deploy.sh restart backend
```
### 服务状态
```bash
# 查看详细状态
./deploy.sh status
# 查看容器列表
./deploy.sh ps
# 查看网络和卷信息
docker network ls | grep anxin
docker volume ls | grep anxin
```
## 📊 监控和日志
### 日志查看
```bash
# 查看所有服务日志
./deploy.sh logs
# 查看特定服务日志
./deploy.sh logs backend
# 实时跟踪日志
./deploy.sh logs -f
# 查看最近100行日志
./deploy.sh logs --tail 100
# 查看最近1小时日志
./deploy.sh logs --since 1h
```
### 健康监控
```bash
# 执行健康检查
./deploy.sh health
# 持续监控(等待所有服务健康)
./deploy.sh health --wait --retry 20 --interval 30
# 查看服务详细信息
docker inspect anxin-backend-development
```
### 性能监控
```bash
# 查看容器资源使用
docker stats
# 查看特定容器资源使用
docker stats anxin-backend-development
# 查看系统资源
free -h
df -h
```
## 🔧 故障排除
### 常见问题诊断
#### 1. 服务启动失败
**症状**:容器无法启动或立即退出
**诊断步骤**
```bash
# 1. 查看容器状态
./deploy.sh status
# 2. 查看容器日志
./deploy.sh logs [service_name]
# 3. 检查配置文件
cat environments/.env.development
# 4. 验证端口占用
netstat -tlnp | grep :80
netstat -tlnp | grep :8080
netstat -tlnp | grep :3306
```
**常见原因及解决方案**
| 问题 | 原因 | 解决方案 |
|------|------|----------|
| 端口被占用 | 其他服务占用端口 | `sudo lsof -i :80` 查找并停止占用进程 |
| 内存不足 | 系统内存不够 | 增加系统内存或调整容器内存限制 |
| 配置错误 | 环境变量配置错误 | 检查并修正 `.env` 文件 |
| 镜像构建失败 | 依赖下载失败 | 检查网络连接,使用 `--no-cache` 重新构建 |
#### 2. 数据库连接失败
**症状**:后端无法连接数据库
**诊断步骤**
```bash
# 1. 检查数据库容器状态
docker ps | grep mysql
# 2. 检查数据库日志
./deploy.sh logs mysql
# 3. 测试数据库连接
docker exec -it anxin-mysql-development mysql -u root -p
# 4. 检查网络连接
docker network inspect anxin-development_default
```
**解决方案**
```bash
# 重启数据库服务
./deploy.sh restart mysql
# 检查数据库初始化
docker exec anxin-mysql-development mysql -u root -p -e "SHOW DATABASES;"
# 重新初始化数据库
./deploy.sh down
rm -rf data/development/mysql
./deploy.sh start
```
#### 3. 前端无法访问后端API
**症状**前端页面加载但API调用失败
**诊断步骤**
```bash
# 1. 检查后端服务状态
curl -I http://localhost:8080/actuator/health
# 2. 检查Nginx配置
docker exec anxin-frontend-development cat /etc/nginx/nginx.conf
# 3. 查看Nginx日志
./deploy.sh logs frontend
# 4. 检查网络连通性
docker exec anxin-frontend-development ping anxin-backend
```
**解决方案**
```bash
# 重启前端服务
./deploy.sh restart frontend
# 检查API代理配置
# 编辑 configs/nginx.conf.development
# 确保 proxy_pass 指向正确的后端服务
```
#### 4. 镜像构建失败
**症状**Docker镜像构建过程中出错
**诊断步骤**
```bash
# 1. 查看构建日志
./build.sh build-all --verbose
# 2. 检查Dockerfile语法
docker run --rm -i hadolint/hadolint < frontend/Dockerfile
# 3. 手动构建测试
cd frontend
docker build -t test-frontend .
```
**解决方案**
```bash
# 清理构建缓存
./build.sh clean
# 强制重新构建
./build.sh build-all --no-cache
# 检查网络连接
ping registry-1.docker.io
```
#### 5. 性能问题
**症状**:服务响应缓慢或资源使用过高
**诊断步骤**
```bash
# 1. 查看资源使用情况
docker stats
# 2. 检查系统负载
top
htop
iostat -x 1
# 3. 分析日志
./deploy.sh logs --since 1h | grep -i error
./deploy.sh logs --since 1h | grep -i slow
```
**解决方案**
```bash
# 调整资源限制
# 编辑 environments/.env.development
BACKEND_MEMORY_LIMIT=2048
DATABASE_MEMORY_LIMIT=1024
# 重启服务应用新配置
./deploy.sh restart
```
### 日志分析
#### 关键日志位置
```bash
# 容器日志
docker logs anxin-backend-development
# 应用日志(挂载到宿主机)
tail -f data/development/backend-logs/application.log
tail -f data/development/mysql-logs/error.log
tail -f data/development/nginx-logs/access.log
```
#### 日志级别说明
| 级别 | 说明 | 使用场景 |
|------|------|----------|
| ERROR | 错误信息 | 生产环境问题排查 |
| WARN | 警告信息 | 潜在问题识别 |
| INFO | 一般信息 | 正常运行监控 |
| DEBUG | 调试信息 | 开发环境调试 |
### 数据备份与恢复
#### 数据备份
```bash
# 使用内置备份脚本
./scripts/backup.sh -e development
# 手动备份数据库
docker exec anxin-mysql-development mysqldump -u root -p anxin > backup.sql
# 备份数据卷
docker run --rm -v anxin-development_mysql-data:/data -v $(pwd):/backup alpine tar czf /backup/mysql-data-backup.tar.gz /data
```
#### 数据恢复
```bash
# 恢复数据库
docker exec -i anxin-mysql-development mysql -u root -p anxin < backup.sql
# 恢复数据卷
docker run --rm -v anxin-development_mysql-data:/data -v $(pwd):/backup alpine tar xzf /backup/mysql-data-backup.tar.gz -C /
```
### 网络问题排查
#### 检查网络配置
```bash
# 查看Docker网络
docker network ls
docker network inspect anxin-development_default
# 检查容器网络连接
docker exec anxin-frontend-development ping anxin-backend
docker exec anxin-backend-development ping anxin-mysql
# 检查端口映射
docker port anxin-frontend-development
docker port anxin-backend-development
```
#### 解决网络问题
```bash
# 重新创建网络
./deploy.sh down
./deploy.sh start
# 检查防火墙设置
sudo ufw status
sudo iptables -L
```
## 🚀 性能优化
### 容器资源优化
#### 内存优化
```bash
# 调整JVM内存设置
JAVA_OPTS=-Xms512m -Xmx1024m -XX:+UseG1GC
# 调整MySQL内存设置
# 编辑 configs/my.cnf.production
innodb_buffer_pool_size = 256M
key_buffer_size = 64M
```
#### CPU优化
```bash
# 设置CPU限制
# 在 docker-compose.yml 中
deploy:
resources:
limits:
cpus: '1.0'
memory: 1024M
```
### 镜像优化
#### 减小镜像大小
```bash
# 使用多阶段构建
# 使用Alpine Linux基础镜像
# 清理不必要的文件和缓存
# 查看镜像大小
docker images | grep anxin
```
#### 构建缓存优化
```bash
# 合理安排Dockerfile层级
# 将变化频率低的操作放在前面
# 使用.dockerignore排除不必要文件
```
### 数据库优化
#### MySQL配置优化
```bash
# 编辑 configs/my.cnf.production
[mysqld]
innodb_buffer_pool_size = 512M
innodb_log_file_size = 128M
max_connections = 200
query_cache_size = 64M
```
#### 索引优化
```sql
-- 分析慢查询
SHOW PROCESSLIST;
SHOW FULL PROCESSLIST;
-- 查看索引使用情况
EXPLAIN SELECT * FROM your_table WHERE condition;
```
## 🔒 安全配置
### 容器安全
#### 用户权限
```bash
# 使用非root用户运行容器
# 在Dockerfile中添加
RUN addgroup -g 1001 appuser && adduser -u 1001 -G appuser -s /bin/sh -D appuser
USER appuser
```
#### 网络安全
```bash
# 限制容器网络访问
# 使用自定义网络
# 关闭不必要的端口映射
```
### 数据安全
#### 密码管理
```bash
# 使用强密码
# 定期更换密码
# 使用Docker secrets管理敏感信息
# 创建密码文件
echo "your_secure_password" | docker secret create db_password -
```
#### 数据加密
```bash
# 启用MySQL SSL
# 配置应用程序使用SSL连接
# 加密敏感数据字段
```
### 访问控制
#### 防火墙配置
```bash
# 配置iptables规则
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 3306 -s 172.20.0.0/16 -j ACCEPT
```
#### 反向代理
```bash
# 使用Nginx作为反向代理
# 配置SSL终止
# 实现负载均衡
```
## ❓ 常见问题
### Q1: 如何更新应用版本?
**A**:
```bash
# 1. 拉取最新代码
./build.sh pull
# 2. 重新构建镜像
./build.sh build-all --no-cache
# 3. 重启服务
./deploy.sh restart
```
### Q2: 如何扩展服务实例?
**A**:
```bash
# 编辑 docker-compose.yml
services:
anxin-backend:
deploy:
replicas: 3
# 重新部署
./deploy.sh restart
```
### Q3: 如何迁移到其他服务器?
**A**:
```bash
# 1. 备份数据
./scripts/backup.sh
# 2. 复制项目文件和备份到新服务器
rsync -av . user@newserver:/path/to/project
# 3. 在新服务器上恢复
./deploy.sh start
# 恢复数据库备份
```
### Q4: 如何配置SSL证书
**A**:
```bash
# 1. 获取SSL证书
# 2. 修改Nginx配置
# 3. 更新docker-compose.yml端口映射
# 4. 重启前端服务
```
### Q5: 如何监控服务健康状态?
**A**:
```bash
# 使用内置健康检查
./deploy.sh health --wait
# 集成外部监控工具
# - Prometheus + Grafana
# - ELK Stack
# - Zabbix
```
### Q6: 如何处理数据库迁移?
**A**:
```bash
# 1. 备份当前数据
./scripts/backup.sh
# 2. 停止服务
./deploy.sh stop
# 3. 更新数据库脚本
# 4. 重启服务(自动执行迁移)
./deploy.sh start
```
---
## 📞 技术支持
如果遇到问题,请按以下步骤获取帮助:
1. **查看日志**`./deploy.sh logs -f`
2. **检查状态**`./deploy.sh health`
3. **查阅文档**:参考本文档故障排除部分
4. **收集信息**:准备错误日志、配置文件、系统信息
5. **寻求帮助**:联系技术支持团队
### 信息收集脚本
```bash
#!/bin/bash
# 收集诊断信息
echo "=== 系统信息 ===" > diagnostic.log
uname -a >> diagnostic.log
docker --version >> diagnostic.log
docker-compose --version >> diagnostic.log
echo "=== 服务状态 ===" >> diagnostic.log
./deploy.sh status >> diagnostic.log
echo "=== 最近日志 ===" >> diagnostic.log
./deploy.sh logs --tail 100 >> diagnostic.log
echo "诊断信息已保存到 diagnostic.log"
```
---
**文档版本**: 1.0.0
**最后更新**: $(date '+%Y-%m-%d')
**维护团队**: 若依框架开发团队

View File

@ -0,0 +1,60 @@
# Docker ignore file for backend build
# 排除不需要的文件和目录以优化构建上下文
# Git相关
.git
.gitignore
.gitattributes
# IDE相关
.idea/
.vscode/
*.iml
*.ipr
*.iws
# 构建产物 (除了需要的JAR文件)
target/
!ruoyi-admin/target/ruoyi-admin.jar
# 日志文件
*.log
logs/
# 临时文件
*.tmp
*.temp
*.swp
*.swo
# 操作系统相关
.DS_Store
Thumbs.db
# Node.js相关 (前端相关,后端不需要)
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Docker相关
Dockerfile
.dockerignore
docker-compose*.yml
# 文档
README.md
doc/
*.md
# 前端相关目录
RuoYi-Vue3/
# 其他Docker目录
docker/frontend/
docker/database/
docker/configs/
docker/scripts/
# 测试相关
.jqwik-database

2
docker/backend/.gitkeep Normal file
View File

@ -0,0 +1,2 @@
# 后端容器配置目录
# 此文件确保目录被Git跟踪

111
docker/backend/Dockerfile Normal file
View File

@ -0,0 +1,111 @@
# 多阶段构建 Dockerfile for 若依后端应用
# Stage 1: 构建阶段 - 使用Maven构建应用
FROM maven:3.8-openjdk-8 AS builder
# 设置工作目录
WORKDIR /app
# 复制Maven配置文件
COPY pom.xml .
COPY ruoyi-admin/pom.xml ruoyi-admin/
COPY ruoyi-framework/pom.xml ruoyi-framework/
COPY ruoyi-system/pom.xml ruoyi-system/
COPY ruoyi-quartz/pom.xml ruoyi-quartz/
COPY ruoyi-generator/pom.xml ruoyi-generator/
COPY ruoyi-common/pom.xml ruoyi-common/
COPY ruoyi-credit/pom.xml ruoyi-credit/
COPY ruoyi-blockchain/pom.xml ruoyi-blockchain/
COPY ruoyi-payment/pom.xml ruoyi-payment/
COPY ruoyi-security/pom.xml ruoyi-security/
COPY ruoyi-notification/pom.xml ruoyi-notification/
COPY ruoyi-analytics/pom.xml ruoyi-analytics/
COPY ruoyi-workflow/pom.xml ruoyi-workflow/
COPY ruoyi-integration/pom.xml ruoyi-integration/
COPY ruoyi-monitor/pom.xml ruoyi-monitor/
# 下载依赖 (利用Docker缓存层优化)
RUN mvn dependency:go-offline -B
# 复制源代码
COPY ruoyi-admin/src ruoyi-admin/src
COPY ruoyi-framework/src ruoyi-framework/src
COPY ruoyi-system/src ruoyi-system/src
COPY ruoyi-quartz/src ruoyi-quartz/src
COPY ruoyi-generator/src ruoyi-generator/src
COPY ruoyi-common/src ruoyi-common/src
COPY ruoyi-credit/src ruoyi-credit/src
COPY ruoyi-blockchain/src ruoyi-blockchain/src
COPY ruoyi-payment/src ruoyi-payment/src
COPY ruoyi-security/src ruoyi-security/src
COPY ruoyi-notification/src ruoyi-notification/src
COPY ruoyi-analytics/src ruoyi-analytics/src
COPY ruoyi-workflow/src ruoyi-workflow/src
COPY ruoyi-integration/src ruoyi-integration/src
COPY ruoyi-monitor/src ruoyi-monitor/src
# 执行Maven构建跳过测试以加快构建速度
RUN mvn clean package -DskipTests -B
# Stage 2: 运行阶段 - 使用轻量级JRE镜像
FROM openjdk:8-jre-alpine
# 设置时区并安装必要工具
RUN apk add --no-cache tzdata netcat-openbsd && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
apk del tzdata
# 创建应用用户 (安全最佳实践)
RUN addgroup -g 1000 anxin && \
adduser -D -s /bin/sh -u 1000 -G anxin anxin
# 设置工作目录
WORKDIR /app
# 从构建阶段复制JAR文件
COPY --from=builder /app/ruoyi-admin/target/ruoyi-admin.jar app.jar
# 复制Docker环境配置文件和脚本
COPY docker/configs/application-docker.yml /app/config/application-docker.yml
COPY docker/configs/backend-env.sh /app/scripts/backend-env.sh
COPY docker/configs/startup.sh /app/scripts/startup.sh
# 创建日志目录、配置目录和脚本目录
RUN mkdir -p /app/logs /app/config /app/uploadPath /app/scripts && \
chown -R anxin:anxin /app && \
chmod +x /app/scripts/backend-env.sh /app/scripts/startup.sh
# 切换到应用用户
USER anxin
# 暴露应用端口
EXPOSE 8080
# 设置环境变量 - 数据库连接配置
ENV DB_HOST=anxin-mysql \
DB_PORT=3306 \
DB_NAME=anxin \
DB_USER=anxin_user \
DB_PASSWORD=anxin_password
# 设置环境变量 - 应用端口和网络配置
ENV SERVER_PORT=8080 \
SPRING_PROFILES_ACTIVE=docker
# 设置环境变量 - 日志和监控配置
ENV LOG_LEVEL=INFO \
LOG_PATH=/app/logs \
LOG_MAX_SIZE=100MB \
LOG_MAX_FILES=10 \
MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE=health,info,metrics
# 设置环境变量 - JVM和性能配置
ENV JAVA_OPTS="-Xms512m -Xmx1024m -Djava.security.egd=file:/dev/./urandom -Dspring.profiles.active=docker" \
TZ=Asia/Shanghai
# 健康检查 - 使用配置的端口
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:${SERVER_PORT}/actuator/health || exit 1
# 启动应用 - 使用启动脚本
ENTRYPOINT ["/app/scripts/startup.sh"]

129
docker/backend/build.bat Normal file
View File

@ -0,0 +1,129 @@
@echo off
REM 后端Docker镜像构建脚本 (Windows版本)
REM 用于构建若依后端应用的Docker镜像
setlocal enabledelayedexpansion
REM 脚本配置
set "SCRIPT_DIR=%~dp0"
set "PROJECT_ROOT=%SCRIPT_DIR%..\..\"
set "IMAGE_NAME=anxin-backend"
set "IMAGE_TAG=latest"
set "NO_CACHE="
set "CLEAN_BUILD="
REM 解析命令行参数
:parse_args
if "%~1"=="" goto :check_docker
if "%~1"=="-t" (
set "IMAGE_TAG=%~2"
shift
shift
goto :parse_args
)
if "%~1"=="--tag" (
set "IMAGE_TAG=%~2"
shift
shift
goto :parse_args
)
if "%~1"=="-n" (
set "IMAGE_NAME=%~2"
shift
shift
goto :parse_args
)
if "%~1"=="--name" (
set "IMAGE_NAME=%~2"
shift
shift
goto :parse_args
)
if "%~1"=="--no-cache" (
set "NO_CACHE=--no-cache"
shift
goto :parse_args
)
if "%~1"=="--clean" (
set "CLEAN_BUILD=true"
shift
goto :parse_args
)
if "%~1"=="-h" goto :show_help
if "%~1"=="--help" goto :show_help
echo [ERROR] 未知参数: %~1
goto :show_help
:show_help
echo.
echo 后端Docker镜像构建脚本
echo.
echo 用法: %~nx0 [选项]
echo.
echo 选项:
echo -t, --tag TAG 设置镜像标签 (默认: latest)
echo -n, --name NAME 设置镜像名称 (默认: anxin-backend)
echo --no-cache 不使用缓存构建
echo --clean 构建前清理Maven缓存
echo -h, --help 显示此帮助信息
echo.
echo 示例:
echo %~nx0 # 使用默认设置构建
echo %~nx0 -t v1.0.0 # 构建并标记为v1.0.0
echo %~nx0 --no-cache # 不使用缓存构建
echo %~nx0 --clean -t dev # 清理后构建dev版本
echo.
exit /b 0
:check_docker
echo [INFO] 检查Docker环境...
docker --version >nul 2>&1
if errorlevel 1 (
echo [ERROR] Docker未安装或不在PATH中
exit /b 1
)
docker info >nul 2>&1
if errorlevel 1 (
echo [ERROR] Docker守护进程未运行
exit /b 1
)
:clean_maven
if "%CLEAN_BUILD%"=="true" (
echo [INFO] 清理Maven缓存...
cd /d "%PROJECT_ROOT%"
where mvn >nul 2>&1
if not errorlevel 1 (
mvn clean
) else (
echo [WARNING] Maven未安装跳过清理步骤
)
)
:build_image
echo [INFO] 开始构建Docker镜像...
echo [INFO] 项目根目录: %PROJECT_ROOT%
echo [INFO] 镜像名称: %IMAGE_NAME%:%IMAGE_TAG%
cd /d "%PROJECT_ROOT%"
echo [INFO] 执行构建命令...
docker build -f docker/backend/Dockerfile -t %IMAGE_NAME%:%IMAGE_TAG% %NO_CACHE% .
if errorlevel 1 (
echo [ERROR] Docker镜像构建失败
exit /b 1
)
echo [SUCCESS] Docker镜像构建成功: %IMAGE_NAME%:%IMAGE_TAG%
:show_image_info
echo [INFO] 镜像信息:
docker images %IMAGE_NAME%:%IMAGE_TAG%
echo [SUCCESS] 构建完成!
echo [INFO] 运行镜像: docker run -d -p 8080:8080 --name anxin-backend-container %IMAGE_NAME%:%IMAGE_TAG%
endlocal

162
docker/backend/build.sh Normal file
View File

@ -0,0 +1,162 @@
#!/bin/bash
# 后端Docker镜像构建脚本
# 用于构建若依后端应用的Docker镜像
set -e # 遇到错误立即退出
# 脚本配置
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
IMAGE_NAME="anxin-backend"
IMAGE_TAG="latest"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 显示帮助信息
show_help() {
cat << EOF
后端Docker镜像构建脚本
用法: $0 [选项]
选项:
-t, --tag TAG 设置镜像标签 (默认: latest)
-n, --name NAME 设置镜像名称 (默认: anxin-backend)
--no-cache 不使用缓存构建
--clean 构建前清理Maven缓存
-h, --help 显示此帮助信息
示例:
$0 # 使用默认设置构建
$0 -t v1.0.0 # 构建并标记为v1.0.0
$0 --no-cache # 不使用缓存构建
$0 --clean -t dev # 清理后构建dev版本
EOF
}
# 解析命令行参数
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-t|--tag)
IMAGE_TAG="$2"
shift 2
;;
-n|--name)
IMAGE_NAME="$2"
shift 2
;;
--no-cache)
NO_CACHE="--no-cache"
shift
;;
--clean)
CLEAN_BUILD=true
shift
;;
-h|--help)
show_help
exit 0
;;
*)
log_error "未知参数: $1"
show_help
exit 1
;;
esac
done
}
# 检查Docker是否可用
check_docker() {
if ! command -v docker &> /dev/null; then
log_error "Docker未安装或不在PATH中"
exit 1
fi
if ! docker info &> /dev/null; then
log_error "Docker守护进程未运行"
exit 1
fi
}
# 清理Maven缓存
clean_maven() {
if [[ "$CLEAN_BUILD" == "true" ]]; then
log_info "清理Maven缓存..."
cd "$PROJECT_ROOT"
if command -v mvn &> /dev/null; then
mvn clean
else
log_warning "Maven未安装跳过清理步骤"
fi
fi
}
# 构建Docker镜像
build_image() {
log_info "开始构建Docker镜像..."
log_info "项目根目录: $PROJECT_ROOT"
log_info "镜像名称: $IMAGE_NAME:$IMAGE_TAG"
cd "$PROJECT_ROOT"
# 构建命令
BUILD_CMD="docker build -f docker/backend/Dockerfile -t $IMAGE_NAME:$IMAGE_TAG $NO_CACHE ."
log_info "执行构建命令: $BUILD_CMD"
if eval "$BUILD_CMD"; then
log_success "Docker镜像构建成功: $IMAGE_NAME:$IMAGE_TAG"
else
log_error "Docker镜像构建失败"
exit 1
fi
}
# 显示镜像信息
show_image_info() {
log_info "镜像信息:"
docker images "$IMAGE_NAME:$IMAGE_TAG" --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.CreatedAt}}\t{{.Size}}"
}
# 主函数
main() {
log_info "开始构建若依后端Docker镜像..."
parse_args "$@"
check_docker
clean_maven
build_image
show_image_info
log_success "构建完成!"
log_info "运行镜像: docker run -d -p 8080:8080 --name anxin-backend-container $IMAGE_NAME:$IMAGE_TAG"
}
# 执行主函数
main "$@"

776
docker/build.sh Normal file
View File

@ -0,0 +1,776 @@
#!/bin/bash
# 主构建脚本 - 若依框架Docker部署方案
# 实现一键构建所有镜像、代码拉取更新和环境配置切换功能
# Requirements: 5.1, 5.2, 5.3
set -e
# ===========================================
# 脚本配置
# ===========================================
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
DOCKER_DIR="$SCRIPT_DIR"
# 默认配置
DEFAULT_ENVIRONMENT="development"
DEFAULT_TAG="latest"
BUILD_ALL=false
PULL_CODE=false
NO_CACHE=false
CLEAN_BUILD=false
VERBOSE=false
# 镜像配置
FRONTEND_IMAGE="anxin-frontend"
BACKEND_IMAGE="anxin-backend"
MYSQL_IMAGE="mysql:8.0"
# ===========================================
# 颜色定义
# ===========================================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# ===========================================
# 日志函数
# ===========================================
log_info() {
echo -e "${BLUE}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_debug() {
if [[ "$VERBOSE" == "true" ]]; then
echo -e "${PURPLE}[DEBUG]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
fi
}
log_step() {
echo -e "${CYAN}[STEP]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
# ===========================================
# 帮助信息
# ===========================================
show_help() {
cat << EOF
若依框架Docker部署 - 主构建脚本
用法: $0 [选项] [命令]
命令:
build 构建指定组件的Docker镜像
build-all 构建所有Docker镜像 (默认)
pull 拉取最新代码
deploy 构建并部署到指定环境
clean 清理构建缓存和临时文件
status 查看当前构建状态
help 显示此帮助信息
选项:
-e, --env ENV 指定环境 (development|staging|production) [默认: development]
-t, --tag TAG 指定镜像标签 [默认: latest]
-c, --component COMP 指定构建组件 (frontend|backend|all) [默认: all]
--pull 构建前拉取最新代码
--no-cache 不使用Docker构建缓存
--clean 构建前清理缓存
--verbose 显示详细日志
-h, --help 显示此帮助信息
环境配置:
development (dev) 开发环境 - 启用调试模式,使用开发配置
staging (stage) 测试环境 - 接近生产的测试配置
production (prod) 生产环境 - 优化的生产配置
示例:
$0 # 构建所有镜像 (开发环境)
$0 build-all -e production # 构建所有镜像 (生产环境)
$0 build -c frontend -t v1.0.0 # 构建前端镜像并标记为v1.0.0
$0 deploy -e staging --pull # 拉取代码并部署到测试环境
$0 pull # 仅拉取最新代码
$0 clean # 清理构建缓存
Requirements Coverage:
5.1 - 一键构建所有镜像功能
5.2 - 代码拉取和更新功能
5.3 - 环境配置切换功能
EOF
}
# ===========================================
# 参数解析
# ===========================================
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
build)
COMMAND="build"
shift
;;
build-all)
COMMAND="build-all"
BUILD_ALL=true
shift
;;
pull)
COMMAND="pull"
shift
;;
deploy)
COMMAND="deploy"
BUILD_ALL=true
shift
;;
clean)
COMMAND="clean"
shift
;;
status)
COMMAND="status"
shift
;;
-e|--env)
ENVIRONMENT="$2"
shift 2
;;
-t|--tag)
TAG="$2"
shift 2
;;
-c|--component)
COMPONENT="$2"
shift 2
;;
--pull)
PULL_CODE=true
shift
;;
--no-cache)
NO_CACHE=true
shift
;;
--clean)
CLEAN_BUILD=true
shift
;;
--verbose)
VERBOSE=true
shift
;;
-h|--help)
show_help
exit 0
;;
*)
log_error "未知参数: $1"
show_help
exit 1
;;
esac
done
# 设置默认值
COMMAND=${COMMAND:-"build-all"}
ENVIRONMENT=${ENVIRONMENT:-$DEFAULT_ENVIRONMENT}
TAG=${TAG:-$DEFAULT_TAG}
COMPONENT=${COMPONENT:-"all"}
# 如果没有指定组件但命令是build则构建所有组件
if [[ "$COMMAND" == "build" && "$COMPONENT" == "all" ]]; then
BUILD_ALL=true
fi
}
# ===========================================
# 环境验证和配置
# ===========================================
validate_environment() {
case $ENVIRONMENT in
development|dev)
ENVIRONMENT="development"
;;
staging|stage)
ENVIRONMENT="staging"
;;
production|prod)
ENVIRONMENT="production"
;;
*)
log_error "无效的环境: $ENVIRONMENT"
log_info "支持的环境: development, staging, production"
exit 1
;;
esac
log_debug "环境验证通过: $ENVIRONMENT"
}
# 加载环境配置
load_environment_config() {
local env_file="${DOCKER_DIR}/environments/.env.${ENVIRONMENT}"
if [[ ! -f "$env_file" ]]; then
log_error "环境配置文件不存在: $env_file"
exit 1
fi
log_info "加载环境配置: $ENVIRONMENT"
source "$env_file"
# 导出关键环境变量
export ENVIRONMENT
export COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME:-"anxin-${ENVIRONMENT}"}
export SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE:-"docker"}
log_debug "环境配置加载完成"
log_debug "项目名称: $COMPOSE_PROJECT_NAME"
log_debug "Spring配置: $SPRING_PROFILES_ACTIVE"
}
# ===========================================
# 系统检查
# ===========================================
check_prerequisites() {
log_step "检查系统依赖..."
# 检查Docker
if ! command -v docker &> /dev/null; then
log_error "Docker未安装或不在PATH中"
exit 1
fi
# 检查Docker Compose
if ! command -v docker-compose &> /dev/null; then
log_error "Docker Compose未安装或不在PATH中"
exit 1
fi
# 检查Docker守护进程
if ! docker info &> /dev/null; then
log_error "Docker守护进程未运行"
exit 1
fi
# 检查Git (如果需要拉取代码)
if [[ "$PULL_CODE" == "true" ]] && ! command -v git &> /dev/null; then
log_error "Git未安装或不在PATH中无法拉取代码"
exit 1
fi
log_success "系统依赖检查通过"
}
# ===========================================
# 代码拉取和更新功能 (Requirement 5.2)
# ===========================================
pull_latest_code() {
log_step "拉取最新代码..."
cd "$PROJECT_ROOT"
# 检查是否为Git仓库
if [[ ! -d ".git" ]]; then
log_warn "当前目录不是Git仓库跳过代码拉取"
return 0
fi
# 获取当前分支
local current_branch=$(git branch --show-current)
log_info "当前分支: $current_branch"
# 检查是否有未提交的更改
if ! git diff-index --quiet HEAD --; then
log_warn "检测到未提交的更改"
read -p "是否继续拉取代码? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "取消代码拉取"
return 1
fi
fi
# 拉取最新代码
log_info "从远程仓库拉取最新代码..."
if git pull origin "$current_branch"; then
log_success "代码拉取成功"
# 检查是否有子模块
if [[ -f ".gitmodules" ]]; then
log_info "更新Git子模块..."
git submodule update --init --recursive
fi
# 显示最新提交信息
log_info "最新提交信息:"
git log --oneline -5
else
log_error "代码拉取失败"
return 1
fi
}
# ===========================================
# 构建准备
# ===========================================
prepare_build() {
log_step "准备构建环境..."
# 创建必要的目录
local data_dirs=(
"${DOCKER_DIR}/data/mysql"
"${DOCKER_DIR}/data/mysql-logs"
"${DOCKER_DIR}/data/backend-logs"
"${DOCKER_DIR}/data/uploads"
"${DOCKER_DIR}/data/nginx-logs"
)
for dir in "${data_dirs[@]}"; do
if [[ ! -d "$dir" ]]; then
log_debug "创建目录: $dir"
mkdir -p "$dir"
fi
done
# 设置目录权限
log_debug "设置目录权限..."
chmod -R 755 "${DOCKER_DIR}/data"
# 清理构建缓存 (如果指定)
if [[ "$CLEAN_BUILD" == "true" ]]; then
clean_build_cache
fi
log_success "构建环境准备完成"
}
# 清理构建缓存
clean_build_cache() {
log_info "清理构建缓存..."
# 清理Docker构建缓存
log_debug "清理Docker构建缓存..."
docker builder prune -f
# 清理Maven缓存 (如果存在)
if command -v mvn &> /dev/null; then
log_debug "清理Maven缓存..."
cd "$PROJECT_ROOT"
mvn clean -q
fi
# 清理npm缓存 (如果存在)
if command -v npm &> /dev/null; then
log_debug "清理npm缓存..."
cd "${PROJECT_ROOT}/RuoYi-Vue3"
if [[ -d "node_modules" ]]; then
rm -rf node_modules
fi
if [[ -f "package-lock.json" ]]; then
rm -f package-lock.json
fi
fi
log_success "构建缓存清理完成"
}
# ===========================================
# 镜像构建功能 (Requirement 5.1)
# ===========================================
build_frontend_image() {
log_step "构建前端镜像..."
local image_name="${FRONTEND_IMAGE}:${TAG}"
local dockerfile_path="${DOCKER_DIR}/frontend/Dockerfile"
local build_args=""
# 根据环境设置构建参数
case $ENVIRONMENT in
production)
build_args="--build-arg NODE_ENV=production --build-arg API_BASE_URL=${API_BASE_URL:-http://localhost:8080}"
;;
staging)
build_args="--build-arg NODE_ENV=production --build-arg API_BASE_URL=${API_BASE_URL:-http://localhost:8080}"
;;
development)
build_args="--build-arg NODE_ENV=development --build-arg API_BASE_URL=${API_BASE_URL:-http://localhost:8080}"
;;
esac
# 构建命令
local build_cmd="docker build -f $dockerfile_path -t $image_name $build_args"
if [[ "$NO_CACHE" == "true" ]]; then
build_cmd="$build_cmd --no-cache"
fi
build_cmd="$build_cmd $PROJECT_ROOT"
log_info "构建前端镜像: $image_name"
log_debug "构建命令: $build_cmd"
if eval "$build_cmd"; then
log_success "前端镜像构建成功: $image_name"
# 显示镜像信息
local image_size=$(docker images --format "table {{.Size}}" "$image_name" | tail -n 1)
log_info "镜像大小: $image_size"
return 0
else
log_error "前端镜像构建失败"
return 1
fi
}
build_backend_image() {
log_step "构建后端镜像..."
local image_name="${BACKEND_IMAGE}:${TAG}"
local dockerfile_path="${DOCKER_DIR}/backend/Dockerfile"
local build_args=""
# 根据环境设置构建参数
case $ENVIRONMENT in
production)
build_args="--build-arg SPRING_PROFILES_ACTIVE=docker,prod"
;;
staging)
build_args="--build-arg SPRING_PROFILES_ACTIVE=docker,staging"
;;
development)
build_args="--build-arg SPRING_PROFILES_ACTIVE=docker,dev"
;;
esac
# 构建命令
local build_cmd="docker build -f $dockerfile_path -t $image_name $build_args"
if [[ "$NO_CACHE" == "true" ]]; then
build_cmd="$build_cmd --no-cache"
fi
build_cmd="$build_cmd $PROJECT_ROOT"
log_info "构建后端镜像: $image_name"
log_debug "构建命令: $build_cmd"
if eval "$build_cmd"; then
log_success "后端镜像构建成功: $image_name"
# 显示镜像信息
local image_size=$(docker images --format "table {{.Size}}" "$image_name" | tail -n 1)
log_info "镜像大小: $image_size"
return 0
else
log_error "后端镜像构建失败"
return 1
fi
}
# 构建所有镜像
build_all_images() {
log_step "开始构建所有镜像..."
local build_start_time=$(date +%s)
local failed_builds=()
# 构建前端镜像
if ! build_frontend_image; then
failed_builds+=("frontend")
fi
# 构建后端镜像
if ! build_backend_image; then
failed_builds+=("backend")
fi
# 拉取MySQL镜像
log_info "拉取MySQL镜像: $MYSQL_IMAGE"
if docker pull "$MYSQL_IMAGE"; then
log_success "MySQL镜像拉取成功"
else
log_warn "MySQL镜像拉取失败将使用本地镜像"
fi
local build_end_time=$(date +%s)
local build_duration=$((build_end_time - build_start_time))
# 构建结果汇总
if [[ ${#failed_builds[@]} -eq 0 ]]; then
log_success "所有镜像构建成功! 耗时: ${build_duration}"
show_build_summary
return 0
else
log_error "以下镜像构建失败: ${failed_builds[*]}"
return 1
fi
}
# 显示构建摘要
show_build_summary() {
log_info "构建摘要:"
echo "----------------------------------------"
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.CreatedAt}}\t{{.Size}}" | grep -E "(anxin-|REPOSITORY)"
echo "----------------------------------------"
}
# ===========================================
# 部署功能
# ===========================================
deploy_to_environment() {
log_step "部署到 $ENVIRONMENT 环境..."
local compose_file="${DOCKER_DIR}/docker-compose.${ENVIRONMENT}.yml"
local env_file="${DOCKER_DIR}/environments/.env.${ENVIRONMENT}"
# 检查文件是否存在
if [[ ! -f "$compose_file" ]]; then
log_error "Docker Compose文件不存在: $compose_file"
return 1
fi
if [[ ! -f "$env_file" ]]; then
log_error "环境配置文件不存在: $env_file"
return 1
fi
# 停止现有服务
log_info "停止现有服务..."
cd "$DOCKER_DIR"
docker-compose -f "$compose_file" --env-file "$env_file" down --remove-orphans || true
# 启动新服务
log_info "启动服务..."
if docker-compose -f "$compose_file" --env-file "$env_file" up -d; then
log_success "服务启动成功"
# 等待服务就绪
log_info "等待服务就绪..."
sleep 15
# 检查服务状态
check_deployment_status "$compose_file" "$env_file"
return 0
else
log_error "服务启动失败"
return 1
fi
}
# 检查部署状态
check_deployment_status() {
local compose_file="$1"
local env_file="$2"
log_info "检查服务状态..."
cd "$DOCKER_DIR"
docker-compose -f "$compose_file" --env-file "$env_file" ps
# 健康检查
local services=("anxin-mysql" "anxin-backend" "anxin-frontend")
local healthy_count=0
for service in "${services[@]}"; do
local container_name="${service}-${ENVIRONMENT}"
if docker ps --format "{{.Names}}" | grep -q "$service"; then
local health=$(docker inspect --format='{{.State.Health.Status}}' "$service" 2>/dev/null || echo "no-healthcheck")
case $health in
"healthy"|"no-healthcheck")
log_success "$service: 运行正常"
((healthy_count++))
;;
"starting")
log_warn "$service: 正在启动中..."
;;
*)
log_error "$service: 健康检查失败 ($health)"
;;
esac
else
log_error "$service: 容器未运行"
fi
done
if [[ $healthy_count -eq ${#services[@]} ]]; then
log_success "所有服务运行正常"
show_access_info
else
log_warn "部分服务可能存在问题,请检查日志"
fi
}
# 显示访问信息
show_access_info() {
log_info "服务访问信息:"
echo "----------------------------------------"
echo "前端应用: http://localhost:${FRONTEND_PORT:-80}"
echo "后端API: http://localhost:${BACKEND_PORT:-8080}"
echo "数据库: localhost:${DB_PORT:-3306}"
echo "----------------------------------------"
echo "查看日志: docker-compose -f docker-compose.${ENVIRONMENT}.yml logs -f"
echo "停止服务: docker-compose -f docker-compose.${ENVIRONMENT}.yml down"
echo "----------------------------------------"
}
# ===========================================
# 状态检查
# ===========================================
show_status() {
log_info "当前构建状态:"
echo "----------------------------------------"
echo "环境: $ENVIRONMENT"
echo "标签: $TAG"
echo "项目根目录: $PROJECT_ROOT"
echo "Docker目录: $DOCKER_DIR"
echo "----------------------------------------"
log_info "Docker镜像:"
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.CreatedAt}}\t{{.Size}}" | grep -E "(anxin-|REPOSITORY)" || echo "未找到相关镜像"
log_info "运行中的容器:"
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep -E "(anxin-|NAMES)" || echo "未找到相关容器"
}
# ===========================================
# 清理功能
# ===========================================
clean_all() {
log_step "清理所有构建产物和缓存..."
# 停止所有相关容器
log_info "停止相关容器..."
docker ps -a --format "{{.Names}}" | grep "anxin-" | xargs -r docker stop
docker ps -a --format "{{.Names}}" | grep "anxin-" | xargs -r docker rm
# 删除相关镜像
log_info "删除相关镜像..."
docker images --format "{{.Repository}}:{{.Tag}}" | grep "anxin-" | xargs -r docker rmi -f
# 清理构建缓存
clean_build_cache
# 清理数据目录 (谨慎操作)
read -p "是否清理数据目录? 这将删除所有持久化数据 (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
log_warn "清理数据目录..."
rm -rf "${DOCKER_DIR}/data"
mkdir -p "${DOCKER_DIR}/data"
fi
log_success "清理完成"
}
# ===========================================
# 主函数
# ===========================================
main() {
# 显示脚本信息
log_info "若依框架Docker部署 - 主构建脚本"
log_info "脚本版本: 1.0.0"
log_info "执行时间: $(date '+%Y-%m-%d %H:%M:%S')"
# 解析参数
parse_args "$@"
# 验证环境
validate_environment
# 加载环境配置
load_environment_config
# 检查系统依赖
check_prerequisites
# 根据命令执行相应操作
case $COMMAND in
pull)
pull_latest_code
;;
build)
if [[ "$PULL_CODE" == "true" ]]; then
pull_latest_code
fi
prepare_build
case $COMPONENT in
frontend)
build_frontend_image
;;
backend)
build_backend_image
;;
all)
build_all_images
;;
*)
log_error "无效的组件: $COMPONENT"
exit 1
;;
esac
;;
build-all)
if [[ "$PULL_CODE" == "true" ]]; then
pull_latest_code
fi
prepare_build
build_all_images
;;
deploy)
if [[ "$PULL_CODE" == "true" ]]; then
pull_latest_code
fi
prepare_build
build_all_images
if [[ $? -eq 0 ]]; then
deploy_to_environment
else
log_error "构建失败,取消部署"
exit 1
fi
;;
status)
show_status
;;
clean)
clean_all
;;
*)
log_error "未知命令: $COMMAND"
show_help
exit 1
;;
esac
log_success "脚本执行完成!"
}
# ===========================================
# 错误处理
# ===========================================
trap 'log_error "脚本执行被中断"; exit 1' INT TERM
# 执行主函数
main "$@"

2
docker/configs/.gitkeep Normal file
View File

@ -0,0 +1,2 @@
# 配置文件模板目录
# 此文件确保目录被Git跟踪

View File

@ -0,0 +1,139 @@
@echo off
REM 后端环境变量配置脚本 (Windows版本)
REM 用于设置不同环境下的后端应用配置
setlocal enabledelayedexpansion
REM 默认环境变量配置
if not defined DB_HOST set DB_HOST=anxin-mysql
if not defined DB_PORT set DB_PORT=3306
if not defined DB_NAME set DB_NAME=anxin
if not defined DB_USER set DB_USER=anxin_user
if not defined DB_PASSWORD set DB_PASSWORD=anxin_password
REM 应用端口和网络配置
if not defined SERVER_PORT set SERVER_PORT=8080
if not defined SPRING_PROFILES_ACTIVE set SPRING_PROFILES_ACTIVE=docker
REM 日志配置
if not defined LOG_LEVEL set LOG_LEVEL=INFO
if not defined LOG_PATH set LOG_PATH=/app/logs
if not defined LOG_MAX_SIZE set LOG_MAX_SIZE=100MB
if not defined LOG_MAX_FILES set LOG_MAX_FILES=10
REM 监控配置
if not defined MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE set MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE=health,info,metrics
REM JVM配置
if not defined JAVA_OPTS set JAVA_OPTS=-Xms512m -Xmx1024m -Djava.security.egd=file:/dev/./urandom
REM 安全配置
if not defined JWT_SECRET set JWT_SECRET=abcdefghijklmnopqrstuvwxyz
if not defined JWT_EXPIRE_TIME set JWT_EXPIRE_TIME=30
REM Druid监控配置
if not defined DRUID_USERNAME set DRUID_USERNAME=admin
if not defined DRUID_PASSWORD set DRUID_PASSWORD=admin123
REM 文件上传路径
if not defined UPLOAD_PATH set UPLOAD_PATH=/app/uploadPath
REM Swagger配置
if not defined SWAGGER_ENABLED set SWAGGER_ENABLED=false
REM 时区配置
if not defined TZ set TZ=Asia/Shanghai
goto :main
:validate_required_env
echo 验证必需的环境变量...
set missing_vars=
if not defined DB_HOST set missing_vars=!missing_vars! DB_HOST
if not defined DB_PORT set missing_vars=!missing_vars! DB_PORT
if not defined DB_NAME set missing_vars=!missing_vars! DB_NAME
if not defined DB_USER set missing_vars=!missing_vars! DB_USER
if not defined DB_PASSWORD set missing_vars=!missing_vars! DB_PASSWORD
if not "!missing_vars!"=="" (
echo 错误: 以下必需的环境变量未设置:
echo !missing_vars!
exit /b 1
)
echo 所有必需的环境变量已设置
exit /b 0
:show_config
echo === 后端应用环境配置 ===
echo 数据库配置:
echo DB_HOST: %DB_HOST%
echo DB_PORT: %DB_PORT%
echo DB_NAME: %DB_NAME%
echo DB_USER: %DB_USER%
echo DB_PASSWORD: [HIDDEN]
echo.
echo 应用配置:
echo SERVER_PORT: %SERVER_PORT%
echo SPRING_PROFILES_ACTIVE: %SPRING_PROFILES_ACTIVE%
echo.
echo 日志配置:
echo LOG_LEVEL: %LOG_LEVEL%
echo LOG_PATH: %LOG_PATH%
echo LOG_MAX_SIZE: %LOG_MAX_SIZE%
echo LOG_MAX_FILES: %LOG_MAX_FILES%
echo.
echo JVM配置:
echo JAVA_OPTS: %JAVA_OPTS%
echo.
echo 其他配置:
echo TZ: %TZ%
echo UPLOAD_PATH: %UPLOAD_PATH%
echo SWAGGER_ENABLED: %SWAGGER_ENABLED%
echo ==========================
exit /b 0
:load_environment
set env_type=%1
if "%env_type%"=="" set env_type=development
if "%env_type%"=="production" (
set LOG_LEVEL=WARN
set SWAGGER_ENABLED=false
set JAVA_OPTS=-Xms1024m -Xmx2048m -Djava.security.egd=file:/dev/./urandom -XX:+UseG1GC
echo 已加载生产环境配置
) else if "%env_type%"=="staging" (
set LOG_LEVEL=INFO
set SWAGGER_ENABLED=true
set JAVA_OPTS=-Xms512m -Xmx1024m -Djava.security.egd=file:/dev/./urandom
echo 已加载预发布环境配置
) else if "%env_type%"=="development" (
set LOG_LEVEL=DEBUG
set SWAGGER_ENABLED=true
set JAVA_OPTS=-Xms256m -Xmx512m -Djava.security.egd=file:/dev/./urandom
echo 已加载开发环境配置
) else (
echo 警告: 未知的环境类型 '%env_type%',使用默认配置
)
exit /b 0
:main
set command=%1
if "%command%"=="" set command=show
if "%command%"=="validate" (
call :validate_required_env
) else if "%command%"=="show" (
call :show_config
) else if "%command%"=="load" (
call :load_environment %2
call :show_config
) else (
echo 用法: %0 {validate^|show^|load [environment]}
echo validate - 验证必需的环境变量
echo show - 显示当前环境配置
echo load - 加载指定环境配置 ^(development^|staging^|production^)
exit /b 1
)
endlocal

View File

@ -0,0 +1,157 @@
#!/bin/bash
# 后端环境变量配置脚本
# 用于设置不同环境下的后端应用配置
set -e
# 默认环境变量配置
export DB_HOST=${DB_HOST:-"anxin-mysql"}
export DB_PORT=${DB_PORT:-"3306"}
export DB_NAME=${DB_NAME:-"anxin"}
export DB_USER=${DB_USER:-"anxin_user"}
export DB_PASSWORD=${DB_PASSWORD:-"anxin_password"}
# 应用端口和网络配置
export SERVER_PORT=${SERVER_PORT:-"8080"}
export SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE:-"docker"}
# 日志配置
export LOG_LEVEL=${LOG_LEVEL:-"INFO"}
export LOG_PATH=${LOG_PATH:-"/app/logs"}
export LOG_MAX_SIZE=${LOG_MAX_SIZE:-"100MB"}
export LOG_MAX_FILES=${LOG_MAX_FILES:-"10"}
# 监控配置
export MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE=${MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE:-"health,info,metrics"}
# JVM配置
export JAVA_OPTS=${JAVA_OPTS:-"-Xms512m -Xmx1024m -Djava.security.egd=file:/dev/./urandom"}
# 安全配置
export JWT_SECRET=${JWT_SECRET:-"abcdefghijklmnopqrstuvwxyz"}
export JWT_EXPIRE_TIME=${JWT_EXPIRE_TIME:-"30"}
# Druid监控配置
export DRUID_USERNAME=${DRUID_USERNAME:-"admin"}
export DRUID_PASSWORD=${DRUID_PASSWORD:-"admin123"}
# 文件上传路径
export UPLOAD_PATH=${UPLOAD_PATH:-"/app/uploadPath"}
# Swagger配置
export SWAGGER_ENABLED=${SWAGGER_ENABLED:-"false"}
# 时区配置
export TZ=${TZ:-"Asia/Shanghai"}
# 函数:验证必需的环境变量
validate_required_env() {
local required_vars=("DB_HOST" "DB_PORT" "DB_NAME" "DB_USER" "DB_PASSWORD")
local missing_vars=()
for var in "${required_vars[@]}"; do
if [[ -z "${!var}" ]]; then
missing_vars+=("$var")
fi
done
if [[ ${#missing_vars[@]} -gt 0 ]]; then
echo "错误: 以下必需的环境变量未设置:"
printf '%s\n' "${missing_vars[@]}"
return 1
fi
echo "所有必需的环境变量已设置"
return 0
}
# 函数:显示当前环境配置
show_config() {
echo "=== 后端应用环境配置 ==="
echo "数据库配置:"
echo " DB_HOST: $DB_HOST"
echo " DB_PORT: $DB_PORT"
echo " DB_NAME: $DB_NAME"
echo " DB_USER: $DB_USER"
echo " DB_PASSWORD: [HIDDEN]"
echo ""
echo "应用配置:"
echo " SERVER_PORT: $SERVER_PORT"
echo " SPRING_PROFILES_ACTIVE: $SPRING_PROFILES_ACTIVE"
echo ""
echo "日志配置:"
echo " LOG_LEVEL: $LOG_LEVEL"
echo " LOG_PATH: $LOG_PATH"
echo " LOG_MAX_SIZE: $LOG_MAX_SIZE"
echo " LOG_MAX_FILES: $LOG_MAX_FILES"
echo ""
echo "JVM配置:"
echo " JAVA_OPTS: $JAVA_OPTS"
echo ""
echo "其他配置:"
echo " TZ: $TZ"
echo " UPLOAD_PATH: $UPLOAD_PATH"
echo " SWAGGER_ENABLED: $SWAGGER_ENABLED"
echo "=========================="
}
# 函数:根据环境类型加载配置
load_environment() {
local env_type=${1:-"development"}
case $env_type in
"production")
export LOG_LEVEL="WARN"
export SWAGGER_ENABLED="false"
export JAVA_OPTS="-Xms1024m -Xmx2048m -Djava.security.egd=file:/dev/./urandom -XX:+UseG1GC"
echo "已加载生产环境配置"
;;
"staging")
export LOG_LEVEL="INFO"
export SWAGGER_ENABLED="true"
export JAVA_OPTS="-Xms512m -Xmx1024m -Djava.security.egd=file:/dev/./urandom"
echo "已加载预发布环境配置"
;;
"development")
export LOG_LEVEL="DEBUG"
export SWAGGER_ENABLED="true"
export JAVA_OPTS="-Xms256m -Xmx512m -Djava.security.egd=file:/dev/./urandom"
echo "已加载开发环境配置"
;;
*)
echo "警告: 未知的环境类型 '$env_type',使用默认配置"
;;
esac
}
# 主函数
main() {
local command=${1:-"show"}
case $command in
"validate")
validate_required_env
;;
"show")
show_config
;;
"load")
local env_type=${2:-"development"}
load_environment "$env_type"
show_config
;;
*)
echo "用法: $0 {validate|show|load [environment]}"
echo " validate - 验证必需的环境变量"
echo " show - 显示当前环境配置"
echo " load - 加载指定环境配置 (development|staging|production)"
exit 1
;;
esac
}
# 如果脚本被直接执行,运行主函数
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi

View File

@ -0,0 +1,71 @@
# MySQL配置文件 - 生产环境
# 针对生产环境优化的MySQL配置
[mysqld]
# 基础配置
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
port = 3306
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
lc-messages-dir = /usr/share/mysql
skip-external-locking
# 字符集配置
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init_connect = 'SET NAMES utf8mb4'
# 网络配置
bind-address = 0.0.0.0
max_connections = 200
max_connect_errors = 100000
max_allowed_packet = 64M
interactive_timeout = 600
wait_timeout = 600
# 缓存配置 - 生产环境优化
key_buffer_size = 256M
max_allowed_packet = 64M
table_open_cache = 4000
sort_buffer_size = 4M
read_buffer_size = 2M
read_rnd_buffer_size = 8M
myisam_sort_buffer_size = 128M
thread_cache_size = 50
query_cache_type = 1
query_cache_size = 128M
query_cache_limit = 2M
# InnoDB配置 - 生产环境优化
innodb_buffer_pool_size = 512M
innodb_log_file_size = 128M
innodb_log_buffer_size = 16M
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 50
innodb_file_per_table = 1
innodb_flush_method = O_DIRECT
# 日志配置
log_error = /var/log/mysql/error.log
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
log_queries_not_using_indexes = 1
# 二进制日志配置 - 生产环境启用
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW
expire_logs_days = 7
max_binlog_size = 100M
# 安全配置
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
[mysql]
default-character-set = utf8mb4
[client]
default-character-set = utf8mb4

View File

@ -0,0 +1,62 @@
# Nginx配置文件 - 开发环境
# 用于Vue3前端静态文件服务和API代理
server {
listen 80;
server_name localhost;
# 开发环境特有配置
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log debug;
# 静态文件服务
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
# 开发环境禁用缓存
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
# API代理到后端服务
location /prod-api/ {
proxy_pass http://anxin-backend:8080/;
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_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering off;
# CORS配置用于开发环境
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
if ($request_method = 'OPTIONS') {
return 204;
}
}
# 开发工具代理 (如果需要)
location /sockjs-node/ {
proxy_pass http://anxin-frontend:24678;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 健康检查端点
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}

View File

@ -0,0 +1,124 @@
# Nginx配置文件 - 生产环境
# 用于Vue3前端静态文件服务和API代理
# HTTP服务器 - 重定向到HTTPS
server {
listen 80;
server_name anxin.com www.anxin.com;
# 强制重定向到HTTPS
return 301 https://$server_name$request_uri;
}
# HTTPS服务器 - 主要配置
server {
listen 443 ssl http2;
server_name anxin.com www.anxin.com;
# SSL配置
ssl_certificate /etc/nginx/ssl/anxin.com.crt;
ssl_certificate_key /etc/nginx/ssl/anxin.com.key;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
# 现代SSL配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# HSTS配置
add_header Strict-Transport-Security "max-age=63072000" always;
# 生产环境日志配置
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log error;
# 安全头配置
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin-when-cross-origin";
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https://api.anxin.com;";
# Gzip压缩配置
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
# 静态文件服务
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
# 生产环境缓存配置
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
location ~* \.(html)$ {
expires 1h;
add_header Cache-Control "public";
}
}
# API代理到后端服务
location /prod-api/ {
proxy_pass http://anxin-backend:8080/;
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_connect_timeout 10s;
proxy_send_timeout 10s;
proxy_read_timeout 10s;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
# 限制请求大小
client_max_body_size 5m;
# 代理缓存配置
proxy_cache_bypass $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Upgrade $http_upgrade;
}
# 健康检查端点
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# 拒绝访问敏感文件
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
location ~ ~$ {
deny all;
access_log off;
log_not_found off;
}
}

View File

@ -0,0 +1,70 @@
# Nginx配置文件 - 测试环境
# 用于Vue3前端静态文件服务和API代理
server {
listen 80;
server_name staging.anxin.com localhost;
# 测试环境日志配置
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log warn;
# 安全头配置
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin-when-cross-origin";
# 静态文件服务
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
# 测试环境缓存配置
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1d;
add_header Cache-Control "public, immutable";
}
location ~* \.(html)$ {
expires 1h;
add_header Cache-Control "public";
}
}
# API代理到后端服务
location /prod-api/ {
proxy_pass http://anxin-backend:8080/;
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_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
# 限制请求大小
client_max_body_size 10m;
}
# 健康检查端点
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# 测试环境状态页面
location /nginx_status {
stub_status on;
access_log off;
allow 172.22.0.0/16;
deny all;
}
}

68
docker/configs/startup.sh Normal file
View File

@ -0,0 +1,68 @@
#!/bin/bash
# 后端应用启动脚本
# 负责验证环境配置并启动Spring Boot应用
set -e
# 导入环境配置脚本
source /app/scripts/backend-env.sh
echo "=== 安信数字信贷系统后端启动 ==="
echo "启动时间: $(date)"
echo "时区: $TZ"
# 验证必需的环境变量
echo "正在验证环境配置..."
if ! validate_required_env; then
echo "环境配置验证失败,退出启动"
exit 1
fi
# 显示当前配置
show_config
# 等待数据库服务可用
echo "正在等待数据库服务可用..."
max_attempts=30
attempt=1
while [ $attempt -le $max_attempts ]; do
if nc -z "$DB_HOST" "$DB_PORT" 2>/dev/null; then
echo "数据库服务已可用 ($DB_HOST:$DB_PORT)"
break
fi
echo "等待数据库服务... (尝试 $attempt/$max_attempts)"
sleep 2
attempt=$((attempt + 1))
done
if [ $attempt -gt $max_attempts ]; then
echo "错误: 无法连接到数据库服务 $DB_HOST:$DB_PORT"
exit 1
fi
# 创建必要的目录
mkdir -p "$LOG_PATH" "$UPLOAD_PATH"
# 设置Spring Boot配置文件路径
export SPRING_CONFIG_LOCATION="classpath:/application.yml,file:/app/config/application-docker.yml"
# 构建完整的Java启动命令
JAVA_CMD="java $JAVA_OPTS \
-Dserver.port=$SERVER_PORT \
-Dspring.profiles.active=$SPRING_PROFILES_ACTIVE \
-Dspring.config.location=$SPRING_CONFIG_LOCATION \
-Dlogging.level.com.ruoyi=$LOG_LEVEL \
-Dlogging.file.name=$LOG_PATH/anxin.log \
-Dspring.datasource.url=jdbc:mysql://$DB_HOST:$DB_PORT/$DB_NAME?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true \
-Dspring.datasource.username=$DB_USER \
-Dspring.datasource.password=$DB_PASSWORD \
-jar app.jar"
echo "启动命令: $JAVA_CMD"
echo "=== 应用启动中... ==="
# 启动应用
exec $JAVA_CMD

2
docker/database/.gitkeep Normal file
View File

@ -0,0 +1,2 @@
# 数据库容器配置目录
# 此文件确保目录被Git跟踪

258
docker/database/README.md Normal file
View File

@ -0,0 +1,258 @@
# 数据库Docker配置
本目录包含MySQL数据库的Docker容器化配置文件和管理脚本。
## 目录结构
```
database/
├── init/ # 数据库初始化脚本目录
│ ├── 01-init-database.sql # 数据库和用户初始化
│ └── 02-schema.sql # 数据库表结构
├── data/ # 数据存储目录(运行时创建)
│ ├── mysql/ # MySQL数据文件
│ └── logs/ # MySQL日志文件
├── backup/ # 数据库备份目录(运行时创建)
├── docker-compose.database.yml # 数据库服务Docker Compose配置
├── .env.database.template # 环境变量配置模板
├── database-manager.sh # 数据库管理脚本Linux/Mac
├── database-manager.bat # 数据库管理脚本Windows
└── README.md # 本文件
```
## 快速开始
### 1. 配置环境变量
复制环境变量模板并根据需要修改:
```bash
# Linux/Mac
cp .env.database.template .env.database
# Windows
copy .env.database.template .env.database
```
编辑 `.env.database` 文件,修改数据库密码等配置。
### 2. 启动数据库
```bash
# Linux/Mac
./database-manager.sh start
# Windows
database-manager.bat start
```
### 3. 检查状态
```bash
# Linux/Mac
./database-manager.sh status
# Windows
database-manager.bat status
```
## 配置说明
### 环境变量配置
主要的环境变量配置项:
| 变量名 | 默认值 | 说明 |
|--------|--------|------|
| `DB_HOST` | anxin-mysql | 数据库主机名 |
| `DB_PORT` | 3306 | 数据库端口 |
| `DB_NAME` | anxin | 数据库名称 |
| `DB_USER` | anxin | 应用数据库用户 |
| `DB_PASSWORD` | anxin123 | 应用数据库密码 |
| `MYSQL_ROOT_PASSWORD` | root123 | MySQL root密码 |
| `DATABASE_MEMORY_LIMIT` | 512M | 内存限制 |
| `DATABASE_CPU_LIMIT` | 0.5 | CPU限制 |
### MySQL配置
MySQL配置文件位于 `../configs/my.cnf.template`,包含以下优化:
- 字符集utf8mb4
- 时区Asia/Shanghai
- 连接数200
- InnoDB缓冲池128M
- 慢查询日志:启用
### 数据持久化
数据持久化通过Docker卷实现
- **mysql-data**: 数据库数据文件,挂载到 `./data/mysql`
- **mysql-logs**: 数据库日志文件,挂载到 `./data/logs/mysql`
### 初始化脚本
初始化脚本按文件名字母顺序执行:
1. `01-init-database.sql`: 创建数据库和用户
2. `02-schema.sql`: 导入数据库表结构
## 管理脚本使用
### 基本操作
```bash
# 启动数据库
./database-manager.sh start
# 停止数据库
./database-manager.sh stop
# 重启数据库
./database-manager.sh restart
# 查看状态
./database-manager.sh status
```
### 日志查看
```bash
# 查看最近100行日志
./database-manager.sh logs
# 查看最近50行日志
./database-manager.sh logs 50
# 实时跟踪日志
./database-manager.sh logs
```
### 数据库连接
```bash
# 进入数据库容器
./database-manager.sh exec
# 直接连接MySQL
./database-manager.sh connect
```
### 备份和恢复
```bash
# 备份数据库
./database-manager.sh backup
# 恢复数据库
./database-manager.sh restore backup/anxin_20250104_120000.sql
```
## 网络配置
数据库容器运行在自定义网络 `anxin-network` 中:
- 网络类型bridge
- 子网172.20.0.0/16
- 网关172.20.0.1
## 安全配置
### 密码安全
- 生产环境请修改默认密码
- 使用强密码策略
- 定期更换密码
### 网络安全
- 数据库端口仅在需要时暴露到宿主机
- 使用内部网络进行容器间通信
- 启用防火墙规则
### 文件权限
- 数据目录权限755
- 配置文件权限644
- 脚本文件权限755
## 故障排除
### 常见问题
1. **容器启动失败**
- 检查端口是否被占用
- 检查数据目录权限
- 查看容器日志
2. **数据库连接失败**
- 检查网络配置
- 验证用户名密码
- 确认数据库已完全启动
3. **初始化脚本执行失败**
- 检查SQL语法
- 查看初始化日志
- 验证文件权限
### 日志位置
- 容器日志:`docker-compose logs`
- MySQL错误日志`./data/logs/mysql/error.log`
- MySQL慢查询日志`./data/logs/mysql/slow.log`
## 性能优化
### 内存配置
根据服务器配置调整内存限制:
```bash
# 开发环境
DATABASE_MEMORY_LIMIT=512M
# 测试环境
DATABASE_MEMORY_LIMIT=1024M
# 生产环境
DATABASE_MEMORY_LIMIT=2048M
```
### InnoDB优化
主要的InnoDB配置项
- `innodb_buffer_pool_size`: 缓冲池大小
- `innodb_log_file_size`: 日志文件大小
- `innodb_flush_log_at_trx_commit`: 事务提交策略
## 监控和维护
### 健康检查
容器配置了健康检查:
- 检查间隔30秒
- 超时时间20秒
- 重试次数10次
- 启动等待60秒
### 定期维护
建议的维护任务:
- 定期备份数据库
- 监控磁盘使用情况
- 检查慢查询日志
- 更新安全补丁
## 集成说明
本数据库配置可以与以下组件集成:
- 后端Spring Boot应用
- 前端Vue3应用
- 监控系统
- 备份系统
通过Docker Compose的依赖配置确保数据库在其他服务之前启动。

View File

@ -0,0 +1,210 @@
@echo off
REM 数据库管理脚本 (Windows版本)
REM 用于管理MySQL数据库容器的启动、停止、备份等操作
setlocal enabledelayedexpansion
REM 脚本配置
set "SCRIPT_DIR=%~dp0"
set "PROJECT_ROOT=%SCRIPT_DIR%..\.."
set "COMPOSE_FILE=%SCRIPT_DIR%docker-compose.database.yml"
set "ENV_FILE=%SCRIPT_DIR%.env.database"
REM 检查环境文件
:check_env_file
if not exist "%ENV_FILE%" (
echo [WARNING] 环境文件不存在: %ENV_FILE%
echo [INFO] 从模板创建环境文件...
copy "%ENV_FILE%.template" "%ENV_FILE%" >nul
echo [SUCCESS] 环境文件已创建,请根据需要修改配置
)
goto :eof
REM 创建必要的目录
:create_directories
set "DATA_DIR=%SCRIPT_DIR%data"
set "MYSQL_DIR=%DATA_DIR%\mysql"
set "LOGS_DIR=%DATA_DIR%\logs\mysql"
echo [INFO] 创建数据目录...
if not exist "%MYSQL_DIR%" mkdir "%MYSQL_DIR%"
if not exist "%LOGS_DIR%" mkdir "%LOGS_DIR%"
echo [SUCCESS] 数据目录创建完成
goto :eof
REM 启动数据库
:start_database
echo [INFO] 启动MySQL数据库容器...
call :check_env_file
call :create_directories
REM 使用docker-compose启动
docker-compose -f "%COMPOSE_FILE%" --env-file "%ENV_FILE%" up -d
echo [SUCCESS] 数据库容器启动完成
echo [INFO] 等待数据库初始化...
REM 等待健康检查通过
set /a max_attempts=30
set /a attempt=1
:wait_loop
if !attempt! gtr !max_attempts! (
echo [ERROR] 数据库启动超时
exit /b 1
)
docker-compose -f "%COMPOSE_FILE%" --env-file "%ENV_FILE%" ps | findstr "healthy" >nul
if !errorlevel! equ 0 (
echo [SUCCESS] 数据库已就绪
goto :eof
)
echo [INFO] 等待数据库启动... (!attempt!/!max_attempts!)
timeout /t 10 /nobreak >nul
set /a attempt+=1
goto wait_loop
REM 停止数据库
:stop_database
echo [INFO] 停止MySQL数据库容器...
docker-compose -f "%COMPOSE_FILE%" --env-file "%ENV_FILE%" down
echo [SUCCESS] 数据库容器已停止
goto :eof
REM 重启数据库
:restart_database
echo [INFO] 重启MySQL数据库容器...
call :stop_database
call :start_database
goto :eof
REM 查看数据库状态
:status_database
echo [INFO] 数据库容器状态:
docker-compose -f "%COMPOSE_FILE%" --env-file "%ENV_FILE%" ps
goto :eof
REM 查看数据库日志
:logs_database
set "lines=%~1"
if "%lines%"=="" set "lines=100"
echo [INFO] 显示数据库日志 (最近 %lines% 行):
docker-compose -f "%COMPOSE_FILE%" --env-file "%ENV_FILE%" logs --tail=%lines% -f
goto :eof
REM 进入数据库容器
:exec_database
echo [INFO] 进入数据库容器...
docker-compose -f "%COMPOSE_FILE%" --env-file "%ENV_FILE%" exec anxin-mysql bash
goto :eof
REM 连接到MySQL
:connect_mysql
echo [INFO] 连接到MySQL数据库...
REM 读取环境变量(简化版本,实际使用时需要解析.env文件
docker-compose -f "%COMPOSE_FILE%" --env-file "%ENV_FILE%" exec anxin-mysql mysql -uanxin -panxin123 anxin
goto :eof
REM 备份数据库
:backup_database
set "backup_file=%SCRIPT_DIR%backup\anxin_%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%%time:~6,2%.sql"
set "backup_dir=%SCRIPT_DIR%backup"
echo [INFO] 备份数据库到: %backup_file%
REM 创建备份目录
if not exist "%backup_dir%" mkdir "%backup_dir%"
REM 执行备份
docker-compose -f "%COMPOSE_FILE%" --env-file "%ENV_FILE%" exec -T anxin-mysql mysqldump -uanxin -panxin123 --single-transaction --routines --triggers anxin > "%backup_file%"
echo [SUCCESS] 数据库备份完成: %backup_file%
goto :eof
REM 恢复数据库
:restore_database
set "backup_file=%~1"
if "%backup_file%"=="" (
echo [ERROR] 请指定有效的备份文件
exit /b 1
)
if not exist "%backup_file%" (
echo [ERROR] 备份文件不存在: %backup_file%
exit /b 1
)
echo [INFO] 从备份文件恢复数据库: %backup_file%
REM 执行恢复
docker-compose -f "%COMPOSE_FILE%" --env-file "%ENV_FILE%" exec -T anxin-mysql mysql -uanxin -panxin123 anxin < "%backup_file%"
echo [SUCCESS] 数据库恢复完成
goto :eof
REM 显示帮助信息
:show_help
echo 数据库管理脚本 (Windows版本)
echo.
echo 用法: %~nx0 [命令] [参数]
echo.
echo 命令:
echo start 启动数据库容器
echo stop 停止数据库容器
echo restart 重启数据库容器
echo status 查看数据库容器状态
echo logs [lines] 查看数据库日志 (默认100行)
echo exec 进入数据库容器
echo connect 连接到MySQL数据库
echo backup 备份数据库
echo restore ^<file^> 从备份文件恢复数据库
echo help 显示此帮助信息
echo.
echo 示例:
echo %~nx0 start # 启动数据库
echo %~nx0 logs 50 # 查看最近50行日志
echo %~nx0 restore backup.sql # 从backup.sql恢复数据库
goto :eof
REM 主函数
:main
set "command=%~1"
if "%command%"=="" set "command=help"
if "%command%"=="start" (
call :start_database
) else if "%command%"=="stop" (
call :stop_database
) else if "%command%"=="restart" (
call :restart_database
) else if "%command%"=="status" (
call :status_database
) else if "%command%"=="logs" (
call :logs_database "%~2"
) else if "%command%"=="exec" (
call :exec_database
) else if "%command%"=="connect" (
call :connect_mysql
) else if "%command%"=="backup" (
call :backup_database
) else if "%command%"=="restore" (
call :restore_database "%~2"
) else if "%command%"=="help" (
call :show_help
) else if "%command%"=="--help" (
call :show_help
) else if "%command%"=="-h" (
call :show_help
) else (
echo [ERROR] 未知命令: %command%
call :show_help
exit /b 1
)
goto :eof
REM 执行主函数
call :main %*

View File

@ -0,0 +1,249 @@
#!/bin/bash
# 数据库管理脚本
# 用于管理MySQL数据库容器的启动、停止、备份等操作
set -e
# 脚本配置
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
COMPOSE_FILE="$SCRIPT_DIR/docker-compose.database.yml"
ENV_FILE="$SCRIPT_DIR/.env.database"
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查环境文件
check_env_file() {
if [ ! -f "$ENV_FILE" ]; then
log_warning "环境文件不存在: $ENV_FILE"
log_info "从模板创建环境文件..."
cp "$ENV_FILE.template" "$ENV_FILE"
log_success "环境文件已创建,请根据需要修改配置"
fi
}
# 创建必要的目录
create_directories() {
local data_dir="$SCRIPT_DIR/data"
local mysql_dir="$data_dir/mysql"
local logs_dir="$data_dir/logs/mysql"
log_info "创建数据目录..."
mkdir -p "$mysql_dir" "$logs_dir"
# 设置权限MySQL需要特定的权限
chmod 755 "$mysql_dir" "$logs_dir"
log_success "数据目录创建完成"
}
# 启动数据库
start_database() {
log_info "启动MySQL数据库容器..."
check_env_file
create_directories
# 使用docker-compose启动
docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d
log_success "数据库容器启动完成"
log_info "等待数据库初始化..."
# 等待健康检查通过
local max_attempts=30
local attempt=1
while [ $attempt -le $max_attempts ]; do
if docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" ps | grep -q "healthy"; then
log_success "数据库已就绪"
return 0
fi
log_info "等待数据库启动... ($attempt/$max_attempts)"
sleep 10
((attempt++))
done
log_error "数据库启动超时"
return 1
}
# 停止数据库
stop_database() {
log_info "停止MySQL数据库容器..."
docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" down
log_success "数据库容器已停止"
}
# 重启数据库
restart_database() {
log_info "重启MySQL数据库容器..."
stop_database
start_database
}
# 查看数据库状态
status_database() {
log_info "数据库容器状态:"
docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" ps
}
# 查看数据库日志
logs_database() {
local lines=${1:-100}
log_info "显示数据库日志 (最近 $lines 行):"
docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" logs --tail="$lines" -f
}
# 进入数据库容器
exec_database() {
log_info "进入数据库容器..."
docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" exec anxin-mysql bash
}
# 连接到MySQL
connect_mysql() {
log_info "连接到MySQL数据库..."
# 从环境文件读取配置
source "$ENV_FILE"
docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" exec anxin-mysql \
mysql -u"$DB_USER" -p"$DB_PASSWORD" "$DB_NAME"
}
# 备份数据库
backup_database() {
local backup_file="$SCRIPT_DIR/backup/anxin_$(date +%Y%m%d_%H%M%S).sql"
local backup_dir="$(dirname "$backup_file")"
log_info "备份数据库到: $backup_file"
# 创建备份目录
mkdir -p "$backup_dir"
# 从环境文件读取配置
source "$ENV_FILE"
# 执行备份
docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" exec -T anxin-mysql \
mysqldump -u"$DB_USER" -p"$DB_PASSWORD" --single-transaction --routines --triggers "$DB_NAME" > "$backup_file"
log_success "数据库备份完成: $backup_file"
}
# 恢复数据库
restore_database() {
local backup_file="$1"
if [ -z "$backup_file" ] || [ ! -f "$backup_file" ]; then
log_error "请指定有效的备份文件"
return 1
fi
log_info "从备份文件恢复数据库: $backup_file"
# 从环境文件读取配置
source "$ENV_FILE"
# 执行恢复
docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" exec -T anxin-mysql \
mysql -u"$DB_USER" -p"$DB_PASSWORD" "$DB_NAME" < "$backup_file"
log_success "数据库恢复完成"
}
# 显示帮助信息
show_help() {
echo "数据库管理脚本"
echo ""
echo "用法: $0 [命令] [参数]"
echo ""
echo "命令:"
echo " start 启动数据库容器"
echo " stop 停止数据库容器"
echo " restart 重启数据库容器"
echo " status 查看数据库容器状态"
echo " logs [lines] 查看数据库日志 (默认100行)"
echo " exec 进入数据库容器"
echo " connect 连接到MySQL数据库"
echo " backup 备份数据库"
echo " restore <file> 从备份文件恢复数据库"
echo " help 显示此帮助信息"
echo ""
echo "示例:"
echo " $0 start # 启动数据库"
echo " $0 logs 50 # 查看最近50行日志"
echo " $0 restore backup.sql # 从backup.sql恢复数据库"
}
# 主函数
main() {
case "${1:-help}" in
start)
start_database
;;
stop)
stop_database
;;
restart)
restart_database
;;
status)
status_database
;;
logs)
logs_database "$2"
;;
exec)
exec_database
;;
connect)
connect_mysql
;;
backup)
backup_database
;;
restore)
restore_database "$2"
;;
help|--help|-h)
show_help
;;
*)
log_error "未知命令: $1"
show_help
exit 1
;;
esac
}
# 执行主函数
main "$@"

View File

@ -0,0 +1,123 @@
# 数据库服务独立配置文件
# 可用于单独启动和管理数据库服务
version: '3.8'
services:
# MySQL数据库服务
anxin-mysql:
image: mysql:8.0
container_name: ${COMPOSE_PROJECT_NAME:-anxin}-mysql
restart: unless-stopped
# 环境变量配置
environment:
# 必需的环境变量
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123}
MYSQL_DATABASE: ${DB_NAME:-anxin}
MYSQL_USER: ${DB_USER:-anxin}
MYSQL_PASSWORD: ${DB_PASSWORD:-anxin123}
# 可选的环境变量
MYSQL_ALLOW_EMPTY_PASSWORD: ${MYSQL_ALLOW_EMPTY_PASSWORD:-no}
MYSQL_RANDOM_ROOT_PASSWORD: ${MYSQL_RANDOM_ROOT_PASSWORD:-no}
# 系统配置
TZ: ${TIMEZONE:-Asia/Shanghai}
# 端口映射
ports:
- "${DB_PORT:-3306}:3306"
# 卷挂载配置
volumes:
# 数据持久化 - 挂载数据目录
- mysql-data:/var/lib/mysql
# 初始化脚本 - 按字母顺序执行
- ./init:/docker-entrypoint-initdb.d:ro
# MySQL配置文件
- ../configs/my.cnf.template:/etc/mysql/conf.d/custom.cnf:ro
# 日志目录
- mysql-logs:/var/log/mysql
# 临时文件目录
- mysql-tmp:/tmp
# 网络配置
networks:
- anxin-network
# 资源限制
deploy:
resources:
limits:
memory: ${DATABASE_MEMORY_LIMIT:-512M}
cpus: '${DATABASE_CPU_LIMIT:-0.5}'
reservations:
memory: ${DATABASE_MEMORY_RESERVATION:-256M}
cpus: '${DATABASE_CPU_RESERVATION:-0.25}'
# 健康检查
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD:-root123}"]
interval: 30s
timeout: 20s
retries: 10
start_period: 60s
# 安全配置
security_opt:
- no-new-privileges:true
# 用户配置(可选,用于安全加固)
# user: "999:999"
# 命令覆盖(可选,用于自定义启动参数)
command: >
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
--default-time-zone='+08:00'
--max-connections=200
--innodb-buffer-pool-size=128M
--innodb-log-file-size=32M
--innodb-flush-log-at-trx-commit=1
--slow-query-log=1
--slow-query-log-file=/var/log/mysql/slow.log
--long-query-time=3
--log-error=/var/log/mysql/error.log
# 网络配置
networks:
anxin-network:
name: ${NETWORK_NAME:-anxin-network}
driver: bridge
ipam:
driver: default
config:
- subnet: ${SUBNET:-172.20.0.0/16}
gateway: ${GATEWAY:-172.20.0.1}
# 卷配置
volumes:
# 数据库数据卷 - 持久化存储
mysql-data:
driver: local
driver_opts:
type: none
o: bind
device: ${MYSQL_DATA_PATH:-./data/mysql}
# 数据库日志卷
mysql-logs:
driver: local
driver_opts:
type: none
o: bind
device: ${MYSQL_LOGS_PATH:-./data/logs/mysql}
# 临时文件卷
mysql-tmp:
driver: local

View File

@ -0,0 +1,33 @@
-- MySQL服务器配置脚本
-- 在数据库和表创建之前执行的配置
-- 设置MySQL服务器全局配置
-- 字符集配置
SET GLOBAL character_set_server = 'utf8mb4';
SET GLOBAL collation_server = 'utf8mb4_unicode_ci';
-- 时区配置
SET GLOBAL time_zone = '+8:00';
-- SQL模式配置兼容性设置
SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO';
-- 连接和性能配置
SET GLOBAL max_connections = 1000;
SET GLOBAL max_allowed_packet = 64*1024*1024; -- 64MB
SET GLOBAL innodb_buffer_pool_size = 128*1024*1024; -- 128MB
-- 日志配置
SET GLOBAL general_log = 'OFF';
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2;
-- 二进制日志配置(用于复制和备份)
SET GLOBAL binlog_format = 'ROW';
SET GLOBAL expire_logs_days = 7;
-- 事务隔离级别
SET GLOBAL transaction_isolation = 'READ-COMMITTED';
-- 显示配置状态
SELECT 'MySQL server configuration completed' as ConfigStatus;

View File

@ -0,0 +1,61 @@
-- 数据库初始化脚本
-- 创建数据库和用户,配置字符集和时区
-- 设置字符集和编码
SET NAMES utf8mb4;
SET character_set_client = utf8mb4;
SET character_set_connection = utf8mb4;
SET character_set_database = utf8mb4;
SET character_set_results = utf8mb4;
SET character_set_server = utf8mb4;
SET collation_connection = utf8mb4_unicode_ci;
SET collation_database = utf8mb4_unicode_ci;
SET collation_server = utf8mb4_unicode_ci;
-- 禁用外键检查以避免初始化时的依赖问题
SET FOREIGN_KEY_CHECKS = 0;
-- 设置时区为中国标准时间
SET time_zone = '+8:00';
SET GLOBAL time_zone = '+8:00';
-- 创建数据库(如果不存在)
CREATE DATABASE IF NOT EXISTS `anxin`
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
-- 使用数据库
USE `anxin`;
-- 创建应用用户(如果不存在)
-- 使用环境变量或默认值
SET @app_user = IFNULL(@MYSQL_USER, 'anxin');
SET @app_password = IFNULL(@MYSQL_PASSWORD, 'anxin123');
-- 创建用户并设置密码
SET @sql = CONCAT('CREATE USER IF NOT EXISTS ''', @app_user, '''@''%'' IDENTIFIED BY ''', @app_password, '''');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 授予数据库权限
SET @sql = CONCAT('GRANT ALL PRIVILEGES ON `anxin`.* TO ''', @app_user, '''@''%''');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 授予必要的系统权限(用于应用正常运行)
SET @sql = CONCAT('GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES ON `anxin`.* TO ''', @app_user, '''@''%''');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 刷新权限
FLUSH PRIVILEGES;
-- 恢复外键检查
SET FOREIGN_KEY_CHECKS = 1;
-- 显示创建的数据库和用户信息
SELECT 'Database anxin created successfully' as Status;
SELECT CONCAT('User ', @app_user, ' created and granted permissions') as UserStatus;

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,52 @@
-- 数据库初始化验证脚本
-- 在所有初始化脚本执行完成后运行
USE `anxin`;
-- 验证数据库字符集
SELECT
SCHEMA_NAME as 'Database',
DEFAULT_CHARACTER_SET_NAME as 'Character Set',
DEFAULT_COLLATION_NAME as 'Collation'
FROM information_schema.SCHEMATA
WHERE SCHEMA_NAME = 'anxin';
-- 验证时区设置
SELECT @@global.time_zone as 'Global Timezone', @@session.time_zone as 'Session Timezone';
-- 验证用户权限
SELECT
User as 'Username',
Host as 'Host',
Select_priv as 'SELECT',
Insert_priv as 'INSERT',
Update_priv as 'UPDATE',
Delete_priv as 'DELETE'
FROM mysql.user
WHERE User IN ('anxin', 'root');
-- 验证数据库表数量
SELECT COUNT(*) as 'Total Tables' FROM information_schema.tables WHERE table_schema = 'anxin';
-- 验证关键表是否存在
SELECT
TABLE_NAME as 'Table Name',
TABLE_ROWS as 'Row Count',
CREATE_TIME as 'Created Time'
FROM information_schema.tables
WHERE table_schema = 'anxin'
AND TABLE_NAME IN (
'sys_user', 'sys_role', 'sys_menu', 'sys_dept',
'dc_service_contract', 'dc_employee', 'dc_financing_application'
)
ORDER BY TABLE_NAME;
-- 验证字符集配置
SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';
-- 显示初始化完成状态
SELECT
'Database initialization completed successfully' as Status,
NOW() as CompletionTime,
@@version as MySQLVersion;

892
docker/deploy.sh Normal file
View File

@ -0,0 +1,892 @@
#!/bin/bash
# 部署脚本 - 若依框架Docker部署方案
# 实现服务启动和停止功能、服务健康检查、日志查看功能
# Requirements: 5.4, 5.5
set -e
# ===========================================
# 脚本配置
# ===========================================
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
DOCKER_DIR="$SCRIPT_DIR"
# 默认配置
DEFAULT_ENVIRONMENT="development"
DEFAULT_ACTION="status"
FOLLOW_LOGS=false
VERBOSE=false
FORCE_RECREATE=false
TIMEOUT=300
# 服务配置
SERVICES=("anxin-mysql" "anxin-backend" "anxin-frontend")
ALL_SERVICES="all"
# ===========================================
# 颜色定义
# ===========================================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# ===========================================
# 日志函数
# ===========================================
log_info() {
echo -e "${BLUE}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_debug() {
if [[ "$VERBOSE" == "true" ]]; then
echo -e "${PURPLE}[DEBUG]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
fi
}
log_step() {
echo -e "${CYAN}[STEP]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
# ===========================================
# 帮助信息
# ===========================================
show_help() {
cat << EOF
若依框架Docker部署 - 部署管理脚本
用法: $0 [选项] [动作] [服务]
动作:
start 启动服务 (默认: 所有服务)
stop 停止服务 (默认: 所有服务)
restart 重启服务 (默认: 所有服务)
status 查看服务状态 (默认动作)
health 执行健康检查
logs 查看服务日志
ps 查看运行中的容器
down 停止并删除所有容器、网络和卷
up 启动所有服务 (等同于start all)
服务:
all 所有服务 (默认)
mysql 数据库服务
backend 后端服务
frontend 前端服务
anxin-mysql 数据库服务 (完整名称)
anxin-backend 后端服务 (完整名称)
anxin-frontend 前端服务 (完整名称)
选项:
-e, --env ENV 指定环境 (development|staging|production) [默认: development]
-f, --follow 跟踪日志输出 (仅用于logs动作)
-t, --timeout SECONDS 设置操作超时时间 [默认: 300秒]
--force 强制重新创建容器
--verbose 显示详细日志
-h, --help 显示此帮助信息
健康检查选项:
--wait 等待所有服务健康后退出
--retry COUNT 健康检查重试次数 [默认: 10]
--interval SECONDS 健康检查间隔 [默认: 30秒]
日志选项:
--tail LINES 显示最后N行日志 [默认: 100]
--since TIME 显示指定时间后的日志 (如: 2h, 30m)
示例:
$0 # 查看服务状态 (开发环境)
$0 start # 启动所有服务
$0 start mysql # 仅启动数据库服务
$0 stop backend frontend # 停止后端和前端服务
$0 restart -e production # 重启生产环境所有服务
$0 health --wait # 等待所有服务健康
$0 logs backend -f # 跟踪后端服务日志
$0 logs --tail 50 --since 1h # 查看最近1小时的50行日志
$0 status -e staging # 查看测试环境状态
Requirements Coverage:
5.4 - 日志输出用于问题排查
5.5 - 验证服务可用性 (健康检查)
EOF
}
# ===========================================
# 参数解析
# ===========================================
parse_args() {
SERVICES_TO_MANAGE=()
while [[ $# -gt 0 ]]; do
case $1 in
start|stop|restart|status|health|logs|ps|down|up)
ACTION="$1"
shift
;;
-e|--env)
ENVIRONMENT="$2"
shift 2
;;
-f|--follow)
FOLLOW_LOGS=true
shift
;;
-t|--timeout)
TIMEOUT="$2"
shift 2
;;
--force)
FORCE_RECREATE=true
shift
;;
--verbose)
VERBOSE=true
shift
;;
--wait)
WAIT_FOR_HEALTH=true
shift
;;
--retry)
HEALTH_RETRY_COUNT="$2"
shift 2
;;
--interval)
HEALTH_CHECK_INTERVAL="$2"
shift 2
;;
--tail)
LOG_TAIL_LINES="$2"
shift 2
;;
--since)
LOG_SINCE="$2"
shift 2
;;
-h|--help)
show_help
exit 0
;;
all|mysql|backend|frontend|anxin-mysql|anxin-backend|anxin-frontend)
# 标准化服务名称
case $1 in
mysql) SERVICES_TO_MANAGE+=("anxin-mysql") ;;
backend) SERVICES_TO_MANAGE+=("anxin-backend") ;;
frontend) SERVICES_TO_MANAGE+=("anxin-frontend") ;;
all) SERVICES_TO_MANAGE=("${SERVICES[@]}") ;;
*) SERVICES_TO_MANAGE+=("$1") ;;
esac
shift
;;
*)
log_error "未知参数: $1"
show_help
exit 1
;;
esac
done
# 设置默认值
ACTION=${ACTION:-$DEFAULT_ACTION}
ENVIRONMENT=${ENVIRONMENT:-$DEFAULT_ENVIRONMENT}
HEALTH_RETRY_COUNT=${HEALTH_RETRY_COUNT:-10}
HEALTH_CHECK_INTERVAL=${HEALTH_CHECK_INTERVAL:-30}
LOG_TAIL_LINES=${LOG_TAIL_LINES:-100}
# 如果没有指定服务,默认为所有服务
if [[ ${#SERVICES_TO_MANAGE[@]} -eq 0 ]]; then
SERVICES_TO_MANAGE=("${SERVICES[@]}")
fi
}
# ===========================================
# 环境验证和配置
# ===========================================
validate_environment() {
case $ENVIRONMENT in
development|dev)
ENVIRONMENT="development"
;;
staging|stage)
ENVIRONMENT="staging"
;;
production|prod)
ENVIRONMENT="production"
;;
*)
log_error "无效的环境: $ENVIRONMENT"
log_info "支持的环境: development, staging, production"
exit 1
;;
esac
log_debug "环境验证通过: $ENVIRONMENT"
}
# 加载环境配置
load_environment_config() {
local env_file="${DOCKER_DIR}/environments/.env.${ENVIRONMENT}"
if [[ ! -f "$env_file" ]]; then
log_error "环境配置文件不存在: $env_file"
exit 1
fi
log_debug "加载环境配置: $ENVIRONMENT"
source "$env_file"
# 设置Docker Compose文件路径
COMPOSE_FILE="${DOCKER_DIR}/docker-compose.${ENVIRONMENT}.yml"
ENV_FILE="$env_file"
if [[ ! -f "$COMPOSE_FILE" ]]; then
log_error "Docker Compose文件不存在: $COMPOSE_FILE"
exit 1
fi
# 导出关键环境变量
export ENVIRONMENT
export COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME:-"anxin-${ENVIRONMENT}"}
log_debug "环境配置加载完成"
log_debug "Compose文件: $COMPOSE_FILE"
log_debug "环境文件: $ENV_FILE"
log_debug "项目名称: $COMPOSE_PROJECT_NAME"
}
# ===========================================
# 系统检查
# ===========================================
check_prerequisites() {
log_debug "检查系统依赖..."
# 检查Docker
if ! command -v docker &> /dev/null; then
log_error "Docker未安装或不在PATH中"
exit 1
fi
# 检查Docker Compose
if ! command -v docker-compose &> /dev/null; then
log_error "Docker Compose未安装或不在PATH中"
exit 1
fi
# 检查Docker守护进程
if ! docker info &> /dev/null; then
log_error "Docker守护进程未运行"
exit 1
fi
log_debug "系统依赖检查通过"
}
# ===========================================
# Docker Compose操作封装
# ===========================================
compose_cmd() {
local cmd="$1"
shift
cd "$DOCKER_DIR"
log_debug "执行: docker-compose -f $COMPOSE_FILE --env-file $ENV_FILE $cmd $*"
docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" "$cmd" "$@"
}
# ===========================================
# 服务启动功能 (Requirement 5.5)
# ===========================================
start_services() {
local services_list=("$@")
if [[ ${#services_list[@]} -eq 0 ]] || [[ "${services_list[*]}" == "${SERVICES[*]}" ]]; then
log_step "启动所有服务..."
services_list=() # 空数组表示所有服务
else
log_step "启动指定服务: ${services_list[*]}"
fi
# 创建必要的数据目录
create_data_directories
# 构建启动命令
local compose_args=("up" "-d")
if [[ "$FORCE_RECREATE" == "true" ]]; then
compose_args+=("--force-recreate")
fi
# 添加服务列表
if [[ ${#services_list[@]} -gt 0 ]]; then
compose_args+=("${services_list[@]}")
fi
# 执行启动命令
log_info "正在启动服务..."
if compose_cmd "${compose_args[@]}"; then
log_success "服务启动命令执行成功"
# 等待服务启动
log_info "等待服务启动完成..."
sleep 10
# 检查服务状态
check_services_status "${services_list[@]}"
# 显示访问信息
show_access_info
else
log_error "服务启动失败"
log_info "查看详细错误信息:"
compose_cmd logs --tail 50
return 1
fi
}
# 创建数据目录
create_data_directories() {
log_debug "创建必要的数据目录..."
local data_dirs=(
"${DOCKER_DIR}/data/${ENVIRONMENT}/mysql"
"${DOCKER_DIR}/data/${ENVIRONMENT}/mysql-logs"
"${DOCKER_DIR}/data/${ENVIRONMENT}/backend-logs"
"${DOCKER_DIR}/data/${ENVIRONMENT}/uploads"
"${DOCKER_DIR}/data/${ENVIRONMENT}/nginx-logs"
)
for dir in "${data_dirs[@]}"; do
if [[ ! -d "$dir" ]]; then
log_debug "创建目录: $dir"
mkdir -p "$dir"
fi
done
# 设置目录权限
chmod -R 755 "${DOCKER_DIR}/data/${ENVIRONMENT}"
}
# ===========================================
# 服务停止功能
# ===========================================
stop_services() {
local services_list=("$@")
if [[ ${#services_list[@]} -eq 0 ]] || [[ "${services_list[*]}" == "${SERVICES[*]}" ]]; then
log_step "停止所有服务..."
services_list=() # 空数组表示所有服务
else
log_step "停止指定服务: ${services_list[*]}"
fi
# 构建停止命令
local compose_args=("stop")
# 添加超时参数
compose_args+=("-t" "$TIMEOUT")
# 添加服务列表
if [[ ${#services_list[@]} -gt 0 ]]; then
compose_args+=("${services_list[@]}")
fi
# 执行停止命令
log_info "正在停止服务..."
if compose_cmd "${compose_args[@]}"; then
log_success "服务停止成功"
# 显示当前状态
show_services_status
else
log_error "服务停止失败"
return 1
fi
}
# ===========================================
# 服务重启功能
# ===========================================
restart_services() {
local services_list=("$@")
log_step "重启服务: ${services_list[*]:-所有服务}"
# 先停止服务
if stop_services "${services_list[@]}"; then
# 等待一段时间确保服务完全停止
log_info "等待服务完全停止..."
sleep 5
# 再启动服务
start_services "${services_list[@]}"
else
log_error "重启失败: 服务停止阶段出错"
return 1
fi
}
# ===========================================
# 服务健康检查功能 (Requirement 5.5)
# ===========================================
check_services_health() {
local services_list=("$@")
local wait_for_health=${WAIT_FOR_HEALTH:-false}
if [[ ${#services_list[@]} -eq 0 ]]; then
services_list=("${SERVICES[@]}")
fi
log_step "执行服务健康检查..."
local healthy_services=()
local unhealthy_services=()
local retry_count=0
local max_retries=$HEALTH_RETRY_COUNT
while [[ $retry_count -lt $max_retries ]]; do
healthy_services=()
unhealthy_services=()
log_info "健康检查 (第 $((retry_count + 1))/$max_retries 次)..."
for service in "${services_list[@]}"; do
local container_name="${service}-${ENVIRONMENT}"
local health_status=$(get_service_health_status "$service")
case $health_status in
"healthy")
log_success "$service: 健康"
healthy_services+=("$service")
;;
"starting")
log_warn "$service: 启动中..."
unhealthy_services+=("$service")
;;
"unhealthy")
log_error "$service: 不健康"
unhealthy_services+=("$service")
;;
"no-healthcheck")
# 对于没有健康检查的服务,检查容器是否运行
if is_service_running "$service"; then
log_success "$service: 运行中 (无健康检查)"
healthy_services+=("$service")
else
log_error "$service: 未运行"
unhealthy_services+=("$service")
fi
;;
"not-found")
log_error "$service: 容器未找到"
unhealthy_services+=("$service")
;;
*)
log_error "$service: 状态未知 ($health_status)"
unhealthy_services+=("$service")
;;
esac
done
# 如果所有服务都健康,或者不需要等待,则退出循环
if [[ ${#unhealthy_services[@]} -eq 0 ]] || [[ "$wait_for_health" != "true" ]]; then
break
fi
# 等待下次检查
if [[ $retry_count -lt $((max_retries - 1)) ]]; then
log_info "等待 ${HEALTH_CHECK_INTERVAL} 秒后重试..."
sleep "$HEALTH_CHECK_INTERVAL"
fi
((retry_count++))
done
# 显示最终结果
echo "========================================"
log_info "健康检查结果:"
log_success "健康服务 (${#healthy_services[@]}): ${healthy_services[*]:-}"
if [[ ${#unhealthy_services[@]} -gt 0 ]]; then
log_error "不健康服务 (${#unhealthy_services[@]}): ${unhealthy_services[*]}"
# 显示不健康服务的详细信息
for service in "${unhealthy_services[@]}"; do
show_service_details "$service"
done
return 1
else
log_success "所有服务健康检查通过!"
return 0
fi
}
# 获取服务健康状态
get_service_health_status() {
local service="$1"
local container_name="${service}-${ENVIRONMENT}"
# 检查容器是否存在
if ! docker ps -a --format "{{.Names}}" | grep -q "^${container_name}$"; then
echo "not-found"
return
fi
# 检查容器是否运行
if ! docker ps --format "{{.Names}}" | grep -q "^${container_name}$"; then
echo "stopped"
return
fi
# 获取健康检查状态
local health_status=$(docker inspect --format='{{.State.Health.Status}}' "$container_name" 2>/dev/null || echo "no-healthcheck")
echo "$health_status"
}
# 检查服务是否运行
is_service_running() {
local service="$1"
local container_name="${service}-${ENVIRONMENT}"
docker ps --format "{{.Names}}" | grep -q "^${container_name}$"
}
# 显示服务详细信息
show_service_details() {
local service="$1"
local container_name="${service}-${ENVIRONMENT}"
log_info "服务详细信息: $service"
echo "----------------------------------------"
# 容器状态
local container_status=$(docker inspect --format='{{.State.Status}}' "$container_name" 2>/dev/null || echo "not-found")
echo "容器状态: $container_status"
# 如果容器存在,显示更多信息
if [[ "$container_status" != "not-found" ]]; then
# 启动时间
local started_at=$(docker inspect --format='{{.State.StartedAt}}' "$container_name" 2>/dev/null)
echo "启动时间: $started_at"
# 重启次数
local restart_count=$(docker inspect --format='{{.RestartCount}}' "$container_name" 2>/dev/null)
echo "重启次数: $restart_count"
# 最近日志
echo "最近日志:"
docker logs --tail 10 "$container_name" 2>&1 | sed 's/^/ /'
fi
echo "----------------------------------------"
}
# ===========================================
# 服务状态查看功能
# ===========================================
show_services_status() {
log_step "查看服务状态..."
# 显示Docker Compose服务状态
log_info "Docker Compose服务状态:"
compose_cmd ps
echo ""
# 显示详细的容器信息
log_info "容器详细信息:"
echo "----------------------------------------"
printf "%-20s %-15s %-15s %-20s %-10s\n" "服务名称" "容器状态" "健康状态" "端口映射" "重启次数"
echo "----------------------------------------"
for service in "${SERVICES[@]}"; do
local container_name="${service}-${ENVIRONMENT}"
# 获取容器信息
if docker ps -a --format "{{.Names}}" | grep -q "^${container_name}$"; then
local status=$(docker inspect --format='{{.State.Status}}' "$container_name" 2>/dev/null)
local health=$(get_service_health_status "$service")
local ports=$(docker port "$container_name" 2>/dev/null | tr '\n' ' ' | sed 's/[[:space:]]*$//')
local restart_count=$(docker inspect --format='{{.RestartCount}}' "$container_name" 2>/dev/null)
# 格式化健康状态显示
case $health in
"healthy") health="✓ 健康" ;;
"starting") health="⚠ 启动中" ;;
"unhealthy") health="✗ 不健康" ;;
"no-healthcheck") health="- 无检查" ;;
*) health="? 未知" ;;
esac
printf "%-20s %-15s %-15s %-20s %-10s\n" "$service" "$status" "$health" "${ports:-}" "$restart_count"
else
printf "%-20s %-15s %-15s %-20s %-10s\n" "$service" "未创建" "-" "-" "-"
fi
done
echo "----------------------------------------"
# 显示网络信息
show_network_info
# 显示卷信息
show_volume_info
}
# 显示网络信息
show_network_info() {
log_info "网络信息:"
local network_name="${COMPOSE_PROJECT_NAME}_default"
if docker network ls --format "{{.Name}}" | grep -q "^${network_name}$"; then
docker network inspect "$network_name" --format "网络名称: {{.Name}}, 驱动: {{.Driver}}, 子网: {{range .IPAM.Config}}{{.Subnet}}{{end}}"
else
echo "网络未创建: $network_name"
fi
}
# 显示卷信息
show_volume_info() {
log_info "数据卷信息:"
echo "----------------------------------------"
local volumes=(
"mysql-data-${ENVIRONMENT}"
"mysql-logs-${ENVIRONMENT}"
"backend-logs-${ENVIRONMENT}"
"backend-uploads-${ENVIRONMENT}"
"frontend-logs-${ENVIRONMENT}"
)
for volume in "${volumes[@]}"; do
local full_volume_name="${COMPOSE_PROJECT_NAME}_${volume}"
if docker volume ls --format "{{.Name}}" | grep -q "^${full_volume_name}$"; then
local mount_point=$(docker volume inspect "$full_volume_name" --format "{{.Mountpoint}}" 2>/dev/null)
echo "$volume -> $mount_point"
else
echo "$volume (未创建)"
fi
done
echo "----------------------------------------"
}
# ===========================================
# 日志查看功能 (Requirement 5.4)
# ===========================================
show_services_logs() {
local services_list=("$@")
if [[ ${#services_list[@]} -eq 0 ]]; then
services_list=("${SERVICES[@]}")
fi
log_step "查看服务日志: ${services_list[*]}"
# 构建日志命令
local compose_args=("logs")
# 添加日志选项
if [[ "$FOLLOW_LOGS" == "true" ]]; then
compose_args+=("-f")
fi
if [[ -n "$LOG_TAIL_LINES" ]]; then
compose_args+=("--tail" "$LOG_TAIL_LINES")
fi
if [[ -n "$LOG_SINCE" ]]; then
compose_args+=("--since" "$LOG_SINCE")
fi
# 添加时间戳
compose_args+=("-t")
# 添加服务列表
compose_args+=("${services_list[@]}")
# 执行日志命令
log_info "日志查看选项: tail=${LOG_TAIL_LINES:-all}, since=${LOG_SINCE:-all}, follow=${FOLLOW_LOGS}"
if [[ "$FOLLOW_LOGS" == "true" ]]; then
log_info "开始跟踪日志 (按 Ctrl+C 退出)..."
fi
compose_cmd "${compose_args[@]}"
}
# ===========================================
# 完整清理功能
# ===========================================
down_all_services() {
log_step "停止并清理所有服务..."
log_warn "这将停止所有容器并删除网络,但保留数据卷"
read -p "确认继续? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "操作已取消"
return 0
fi
# 执行down命令
if compose_cmd down --remove-orphans; then
log_success "服务清理完成"
# 显示清理后的状态
log_info "清理后状态:"
compose_cmd ps
else
log_error "服务清理失败"
return 1
fi
}
# ===========================================
# 显示访问信息
# ===========================================
show_access_info() {
log_info "服务访问信息:"
echo "========================================"
echo "环境: $ENVIRONMENT"
echo "----------------------------------------"
echo "前端应用: http://localhost:${FRONTEND_PORT:-80}"
echo "后端API: http://localhost:${BACKEND_PORT:-8080}"
echo "数据库: localhost:${DB_PORT:-3306}"
echo "----------------------------------------"
echo "管理命令:"
echo " 查看状态: $0 status -e $ENVIRONMENT"
echo " 查看日志: $0 logs -e $ENVIRONMENT"
echo " 健康检查: $0 health -e $ENVIRONMENT"
echo " 停止服务: $0 stop -e $ENVIRONMENT"
echo "========================================"
}
# ===========================================
# 检查服务状态 (内部使用)
# ===========================================
check_services_status() {
local services_list=("$@")
if [[ ${#services_list[@]} -eq 0 ]]; then
services_list=("${SERVICES[@]}")
fi
log_info "检查服务启动状态..."
local running_services=()
local failed_services=()
for service in "${services_list[@]}"; do
if is_service_running "$service"; then
running_services+=("$service")
log_success "$service: 运行中"
else
failed_services+=("$service")
log_error "$service: 未运行"
fi
done
if [[ ${#failed_services[@]} -gt 0 ]]; then
log_warn "部分服务启动失败: ${failed_services[*]}"
log_info "建议执行健康检查: $0 health -e $ENVIRONMENT"
fi
}
# ===========================================
# 主函数
# ===========================================
main() {
# 显示脚本信息
log_info "若依框架Docker部署 - 部署管理脚本"
log_info "脚本版本: 1.0.0"
log_info "执行时间: $(date '+%Y-%m-%d %H:%M:%S')"
# 解析参数
parse_args "$@"
# 验证环境
validate_environment
# 加载环境配置
load_environment_config
# 检查系统依赖
check_prerequisites
# 显示当前配置
log_debug "当前配置:"
log_debug " 动作: $ACTION"
log_debug " 环境: $ENVIRONMENT"
log_debug " 服务: ${SERVICES_TO_MANAGE[*]}"
log_debug " 超时: ${TIMEOUT}"
# 根据动作执行相应操作
case $ACTION in
start|up)
start_services "${SERVICES_TO_MANAGE[@]}"
;;
stop)
stop_services "${SERVICES_TO_MANAGE[@]}"
;;
restart)
restart_services "${SERVICES_TO_MANAGE[@]}"
;;
status|ps)
show_services_status
;;
health)
check_services_health "${SERVICES_TO_MANAGE[@]}"
;;
logs)
show_services_logs "${SERVICES_TO_MANAGE[@]}"
;;
down)
down_all_services
;;
*)
log_error "未知动作: $ACTION"
show_help
exit 1
;;
esac
local exit_code=$?
if [[ $exit_code -eq 0 ]]; then
log_success "操作完成!"
else
log_error "操作失败 (退出代码: $exit_code)"
fi
exit $exit_code
}
# ===========================================
# 错误处理
# ===========================================
trap 'log_error "脚本执行被中断"; exit 1' INT TERM
# 执行主函数
main "$@"

View File

@ -0,0 +1,179 @@
# Docker Compose开发环境配置文件
# 若依框架前后端分离Docker部署方案 - 开发环境
# Requirements: 5.3, 6.5
version: '3.8'
services:
# MySQL数据库服务 - 开发环境配置
anxin-mysql:
image: mysql:8.0
container_name: anxin-mysql-dev
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-dev_root_password}
MYSQL_DATABASE: ${DB_NAME:-anxin_dev}
MYSQL_USER: ${DB_USER:-anxin_dev}
MYSQL_PASSWORD: ${DB_PASSWORD:-dev_password}
TZ: Asia/Shanghai
ports:
- "${DB_PORT:-3306}:3306"
volumes:
- mysql-data-dev:/var/lib/mysql
- ./database/init:/docker-entrypoint-initdb.d:ro
- ./configs/my.cnf:/etc/mysql/conf.d/my.cnf:ro
- mysql-logs-dev:/var/log/mysql
networks:
- anxin-dev-network
deploy:
resources:
limits:
memory: ${DATABASE_MEMORY_LIMIT:-256M}
cpus: '${DATABASE_CPU_LIMIT:-0.25}'
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD:-dev_root_password}"]
timeout: 20s
retries: 10
interval: 30s
start_period: 60s
# Spring Boot后端服务 - 开发环境配置
anxin-backend:
build:
context: ../
dockerfile: docker/backend/Dockerfile
target: development
image: anxin-backend:dev
container_name: anxin-backend-dev
restart: unless-stopped
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-dev}
SPRING_DATASOURCE_URL: jdbc:mysql://anxin-mysql:3306/${DB_NAME:-anxin_dev}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
SPRING_DATASOURCE_USERNAME: ${DB_USER:-anxin_dev}
SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD:-dev_password}
JAVA_OPTS: ${JAVA_OPTS:--Xms256m -Xmx512m -Djava.security.egd=file:/dev/./urandom}
LOG_LEVEL: ${LOG_LEVEL:-DEBUG}
TZ: Asia/Shanghai
# 开发环境特有配置
SPRING_DEVTOOLS_RESTART_ENABLED: true
SPRING_DEVTOOLS_LIVERELOAD_ENABLED: true
LOGGING_LEVEL_COM_RUOYI: DEBUG
LOGGING_LEVEL_ROOT: DEBUG
ports:
- "${BACKEND_PORT:-8080}:8080"
- "35729:35729" # LiveReload端口
volumes:
- backend-logs-dev:/app/logs
- backend-uploads-dev:/app/uploadPath
- ./configs:/app/config:ro
# 开发环境代码热重载
- ../ruoyi-admin/src:/app/src:ro
networks:
- anxin-dev-network
depends_on:
anxin-mysql:
condition: service_healthy
deploy:
resources:
limits:
memory: ${BACKEND_MEMORY_LIMIT:-512M}
cpus: '${BACKEND_CPU_LIMIT:-0.5}'
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/actuator/health || exit 1"]
timeout: 30s
retries: 5
interval: 30s
start_period: 90s
# Vue3前端服务 - 开发环境配置
anxin-frontend:
build:
context: ../
dockerfile: docker/frontend/Dockerfile
target: development
args:
API_BASE_URL: ${API_BASE_URL:-http://localhost:8080}
NODE_ENV: development
image: anxin-frontend:dev
container_name: anxin-frontend-dev
restart: unless-stopped
environment:
TZ: Asia/Shanghai
NODE_ENV: development
ports:
- "${FRONTEND_PORT:-3000}:80"
- "24678:24678" # Vite HMR端口
volumes:
- frontend-logs-dev:/var/log/nginx
- ./configs/nginx.conf.dev:/etc/nginx/conf.d/default.conf:ro
# 开发环境源码挂载用于热重载
- ../RuoYi-Vue3/src:/app/src:ro
networks:
- anxin-dev-network
depends_on:
anxin-backend:
condition: service_healthy
deploy:
resources:
limits:
memory: ${FRONTEND_MEMORY_LIMIT:-128M}
cpus: '${FRONTEND_CPU_LIMIT:-0.25}'
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost/ || exit 1"]
timeout: 10s
retries: 3
interval: 30s
start_period: 30s
# 网络配置 - 开发环境
networks:
anxin-dev-network:
name: ${NETWORK_NAME:-anxin-dev-network}
driver: bridge
ipam:
driver: default
config:
- subnet: ${SUBNET:-172.21.0.0/16}
gateway: ${GATEWAY:-172.21.0.1}
# 卷配置 - 开发环境
volumes:
# 数据库数据持久化卷
mysql-data-dev:
driver: local
driver_opts:
type: none
o: bind
device: ${MYSQL_DATA_PATH:-./data/dev/mysql}
# 数据库日志卷
mysql-logs-dev:
driver: local
driver_opts:
type: none
o: bind
device: ${MYSQL_LOG_PATH:-./data/dev/mysql-logs}
# 后端应用日志卷
backend-logs-dev:
driver: local
driver_opts:
type: none
o: bind
device: ${BACKEND_LOG_PATH:-./data/dev/backend-logs}
# 后端文件上传卷
backend-uploads-dev:
driver: local
driver_opts:
type: none
o: bind
device: ${BACKEND_UPLOAD_PATH:-./data/dev/uploads}
# 前端Nginx日志卷
frontend-logs-dev:
driver: local
driver_opts:
type: none
o: bind
device: ${FRONTEND_LOG_PATH:-./data/dev/nginx-logs}

View File

@ -0,0 +1,291 @@
# Docker Compose生产环境配置文件
# 若依框架前后端分离Docker部署方案 - 生产环境
# Requirements: 5.3, 6.5
version: '3.8'
services:
# MySQL数据库服务 - 生产环境配置
anxin-mysql:
image: mysql:8.0
container_name: anxin-mysql-prod
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${DB_NAME:-anxin_prod}
MYSQL_USER: ${DB_USER:-anxin_prod}
MYSQL_PASSWORD: ${DB_PASSWORD}
TZ: Asia/Shanghai
ports:
- "127.0.0.1:${DB_PORT:-3306}:3306" # 生产环境仅绑定本地接口
volumes:
- mysql-data-prod:/var/lib/mysql
- ./database/init:/docker-entrypoint-initdb.d:ro
- ./configs/my.cnf.prod:/etc/mysql/conf.d/my.cnf:ro
- mysql-logs-prod:/var/log/mysql
networks:
- anxin-prod-network
deploy:
resources:
limits:
memory: ${DATABASE_MEMORY_LIMIT:-1024M}
cpus: '${DATABASE_CPU_LIMIT:-1.0}'
reservations:
memory: 512M
cpus: '0.5'
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
timeout: 20s
retries: 10
interval: 30s
start_period: 60s
logging:
driver: "json-file"
options:
max-size: "${LOG_MAX_SIZE:-200m}"
max-file: "${LOG_MAX_FILES:-15}"
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
- /var/run/mysqld
# Spring Boot后端服务 - 生产环境配置
anxin-backend:
build:
context: ../
dockerfile: docker/backend/Dockerfile
target: production
image: anxin-backend:prod
container_name: anxin-backend-prod
restart: always
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-prod}
SPRING_DATASOURCE_URL: jdbc:mysql://anxin-mysql:3306/${DB_NAME:-anxin_prod}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&requireSSL=true
SPRING_DATASOURCE_USERNAME: ${DB_USER:-anxin_prod}
SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD}
JAVA_OPTS: ${JAVA_OPTS:--Xms1024m -Xmx2048m -Djava.security.egd=file:/dev/./urandom -XX:+UseG1GC -XX:+UseStringDeduplication}
LOG_LEVEL: ${LOG_LEVEL:-WARN}
TZ: Asia/Shanghai
# 生产环境特有配置
MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE: health,info,metrics
MANAGEMENT_ENDPOINT_HEALTH_SHOW_DETAILS: never
LOGGING_LEVEL_COM_RUOYI: WARN
LOGGING_LEVEL_ROOT: WARN
# 安全配置
SPRING_SECURITY_REQUIRE_SSL: true
SERVER_SSL_ENABLED: false # 通过反向代理处理SSL
ports:
- "127.0.0.1:${BACKEND_PORT:-8080}:8080" # 生产环境仅绑定本地接口
volumes:
- backend-logs-prod:/app/logs
- backend-uploads-prod:/app/uploadPath
- ./configs:/app/config:ro
networks:
- anxin-prod-network
depends_on:
anxin-mysql:
condition: service_healthy
deploy:
resources:
limits:
memory: ${BACKEND_MEMORY_LIMIT:-2048M}
cpus: '${BACKEND_CPU_LIMIT:-2.0}'
reservations:
memory: 1024M
cpus: '1.0'
replicas: ${BACKEND_REPLICAS:-1}
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/actuator/health || exit 1"]
timeout: 30s
retries: 5
interval: 30s
start_period: 120s
logging:
driver: "json-file"
options:
max-size: "${LOG_MAX_SIZE:-200m}"
max-file: "${LOG_MAX_FILES:-15}"
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
# Vue3前端服务 - 生产环境配置
anxin-frontend:
build:
context: ../
dockerfile: docker/frontend/Dockerfile
target: production
args:
API_BASE_URL: ${API_BASE_URL:-https://api.anxin.com}
NODE_ENV: production
image: anxin-frontend:prod
container_name: anxin-frontend-prod
restart: always
environment:
TZ: Asia/Shanghai
NODE_ENV: production
ports:
- "${FRONTEND_PORT:-80}:80"
- "${FRONTEND_SSL_PORT:-443}:443"
volumes:
- frontend-logs-prod:/var/log/nginx
- ./configs/nginx.conf.prod:/etc/nginx/conf.d/default.conf:ro
- ./configs/ssl:/etc/nginx/ssl:ro # SSL证书
networks:
- anxin-prod-network
depends_on:
anxin-backend:
condition: service_healthy
deploy:
resources:
limits:
memory: ${FRONTEND_MEMORY_LIMIT:-512M}
cpus: '${FRONTEND_CPU_LIMIT:-1.0}'
reservations:
memory: 256M
cpus: '0.5'
replicas: ${FRONTEND_REPLICAS:-1}
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost/ || exit 1"]
timeout: 10s
retries: 3
interval: 30s
start_period: 30s
logging:
driver: "json-file"
options:
max-size: "${LOG_MAX_SIZE:-200m}"
max-file: "${LOG_MAX_FILES:-15}"
security_opt:
- no-new-privileges:true
# 生产环境专用服务 - 数据库备份服务
anxin-db-backup:
image: mysql:8.0
container_name: anxin-db-backup-prod
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
BACKUP_SCHEDULE: ${BACKUP_SCHEDULE:-0 2 * * *} # 每天凌晨2点备份
BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-30}
volumes:
- mysql-data-prod:/var/lib/mysql:ro
- backup-data-prod:/backup
- ./scripts/backup-prod.sh:/backup.sh:ro
networks:
- anxin-prod-network
depends_on:
anxin-mysql:
condition: service_healthy
command: >
sh -c "
echo 'Starting database backup service for production environment...'
echo '${BACKUP_SCHEDULE} /backup.sh' | crontab -
crond -f
"
deploy:
resources:
limits:
memory: 256M
cpus: '0.2'
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "5"
# 生产环境专用服务 - 监控服务
anxin-monitor:
image: prom/node-exporter:latest
container_name: anxin-monitor-prod
restart: always
ports:
- "127.0.0.1:9100:9100"
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
networks:
- anxin-prod-network
command:
- '--path.procfs=/host/proc'
- '--path.rootfs=/rootfs'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
deploy:
resources:
limits:
memory: 128M
cpus: '0.1'
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# 网络配置 - 生产环境
networks:
anxin-prod-network:
name: ${NETWORK_NAME:-anxin-prod-network}
driver: bridge
ipam:
driver: default
config:
- subnet: ${SUBNET:-172.23.0.0/16}
gateway: ${GATEWAY:-172.23.0.1}
driver_opts:
com.docker.network.bridge.name: anxin-prod-br0
# 卷配置 - 生产环境
volumes:
# 数据库数据持久化卷
mysql-data-prod:
driver: local
driver_opts:
type: none
o: bind
device: ${MYSQL_DATA_PATH:-/var/lib/anxin/mysql}
# 数据库日志卷
mysql-logs-prod:
driver: local
driver_opts:
type: none
o: bind
device: ${MYSQL_LOG_PATH:-/var/log/anxin/mysql}
# 后端应用日志卷
backend-logs-prod:
driver: local
driver_opts:
type: none
o: bind
device: ${BACKEND_LOG_PATH:-/var/log/anxin/backend}
# 后端文件上传卷
backend-uploads-prod:
driver: local
driver_opts:
type: none
o: bind
device: ${BACKEND_UPLOAD_PATH:-/var/lib/anxin/uploads}
# 前端Nginx日志卷
frontend-logs-prod:
driver: local
driver_opts:
type: none
o: bind
device: ${FRONTEND_LOG_PATH:-/var/log/anxin/nginx}
# 数据库备份卷
backup-data-prod:
driver: local
driver_opts:
type: none
o: bind
device: ${BACKUP_DATA_PATH:-/var/lib/anxin/backups}

View File

@ -0,0 +1,225 @@
# Docker Compose测试环境配置文件
# 若依框架前后端分离Docker部署方案 - 测试环境
# Requirements: 5.3, 6.5
version: '3.8'
services:
# MySQL数据库服务 - 测试环境配置
anxin-mysql:
image: mysql:8.0
container_name: anxin-mysql-staging
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-staging_root_password}
MYSQL_DATABASE: ${DB_NAME:-anxin_staging}
MYSQL_USER: ${DB_USER:-anxin_staging}
MYSQL_PASSWORD: ${DB_PASSWORD:-staging_password}
TZ: Asia/Shanghai
ports:
- "${DB_PORT:-3306}:3306"
volumes:
- mysql-data-staging:/var/lib/mysql
- ./database/init:/docker-entrypoint-initdb.d:ro
- ./configs/my.cnf:/etc/mysql/conf.d/my.cnf:ro
- mysql-logs-staging:/var/log/mysql
networks:
- anxin-staging-network
deploy:
resources:
limits:
memory: ${DATABASE_MEMORY_LIMIT:-384M}
cpus: '${DATABASE_CPU_LIMIT:-0.5}'
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD:-staging_root_password}"]
timeout: 20s
retries: 10
interval: 30s
start_period: 60s
logging:
driver: "json-file"
options:
max-size: "${LOG_MAX_SIZE:-100m}"
max-file: "${LOG_MAX_FILES:-7}"
# Spring Boot后端服务 - 测试环境配置
anxin-backend:
build:
context: ../
dockerfile: docker/backend/Dockerfile
target: production
image: anxin-backend:staging
container_name: anxin-backend-staging
restart: unless-stopped
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-staging}
SPRING_DATASOURCE_URL: jdbc:mysql://anxin-mysql:3306/${DB_NAME:-anxin_staging}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
SPRING_DATASOURCE_USERNAME: ${DB_USER:-anxin_staging}
SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD:-staging_password}
JAVA_OPTS: ${JAVA_OPTS:--Xms512m -Xmx768m -Djava.security.egd=file:/dev/./urandom}
LOG_LEVEL: ${LOG_LEVEL:-INFO}
TZ: Asia/Shanghai
# 测试环境特有配置
SPRING_JPA_SHOW_SQL: true
LOGGING_LEVEL_COM_RUOYI: INFO
MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE: health,info,metrics,prometheus
ports:
- "${BACKEND_PORT:-8080}:8080"
volumes:
- backend-logs-staging:/app/logs
- backend-uploads-staging:/app/uploadPath
- ./configs:/app/config:ro
networks:
- anxin-staging-network
depends_on:
anxin-mysql:
condition: service_healthy
deploy:
resources:
limits:
memory: ${BACKEND_MEMORY_LIMIT:-768M}
cpus: '${BACKEND_CPU_LIMIT:-0.75}'
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/actuator/health || exit 1"]
timeout: 30s
retries: 5
interval: 30s
start_period: 90s
logging:
driver: "json-file"
options:
max-size: "${LOG_MAX_SIZE:-100m}"
max-file: "${LOG_MAX_FILES:-7}"
# Vue3前端服务 - 测试环境配置
anxin-frontend:
build:
context: ../
dockerfile: docker/frontend/Dockerfile
target: production
args:
API_BASE_URL: ${API_BASE_URL:-http://staging-api.anxin.com}
NODE_ENV: production
image: anxin-frontend:staging
container_name: anxin-frontend-staging
restart: unless-stopped
environment:
TZ: Asia/Shanghai
NODE_ENV: production
ports:
- "${FRONTEND_PORT:-80}:80"
volumes:
- frontend-logs-staging:/var/log/nginx
- ./configs/nginx.conf.staging:/etc/nginx/conf.d/default.conf:ro
networks:
- anxin-staging-network
depends_on:
anxin-backend:
condition: service_healthy
deploy:
resources:
limits:
memory: ${FRONTEND_MEMORY_LIMIT:-192M}
cpus: '${FRONTEND_CPU_LIMIT:-0.5}'
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost/ || exit 1"]
timeout: 10s
retries: 3
interval: 30s
start_period: 30s
logging:
driver: "json-file"
options:
max-size: "${LOG_MAX_SIZE:-100m}"
max-file: "${LOG_MAX_FILES:-7}"
# 测试环境专用服务 - 数据库备份服务
anxin-db-backup:
image: mysql:8.0
container_name: anxin-db-backup-staging
restart: "no"
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-staging_root_password}
volumes:
- mysql-data-staging:/var/lib/mysql:ro
- backup-data-staging:/backup
- ./scripts/backup.sh:/backup.sh:ro
networks:
- anxin-staging-network
depends_on:
anxin-mysql:
condition: service_healthy
command: >
sh -c "
echo 'Starting database backup service for staging environment...'
while true; do
sleep 86400
/backup.sh
done
"
deploy:
resources:
limits:
memory: 128M
cpus: '0.1'
# 网络配置 - 测试环境
networks:
anxin-staging-network:
name: ${NETWORK_NAME:-anxin-staging-network}
driver: bridge
ipam:
driver: default
config:
- subnet: ${SUBNET:-172.22.0.0/16}
gateway: ${GATEWAY:-172.22.0.1}
# 卷配置 - 测试环境
volumes:
# 数据库数据持久化卷
mysql-data-staging:
driver: local
driver_opts:
type: none
o: bind
device: ${MYSQL_DATA_PATH:-./data/staging/mysql}
# 数据库日志卷
mysql-logs-staging:
driver: local
driver_opts:
type: none
o: bind
device: ${MYSQL_LOG_PATH:-./data/staging/mysql-logs}
# 后端应用日志卷
backend-logs-staging:
driver: local
driver_opts:
type: none
o: bind
device: ${BACKEND_LOG_PATH:-./data/staging/backend-logs}
# 后端文件上传卷
backend-uploads-staging:
driver: local
driver_opts:
type: none
o: bind
device: ${BACKEND_UPLOAD_PATH:-./data/staging/uploads}
# 前端Nginx日志卷
frontend-logs-staging:
driver: local
driver_opts:
type: none
o: bind
device: ${FRONTEND_LOG_PATH:-./data/staging/nginx-logs}
# 数据库备份卷
backup-data-staging:
driver: local
driver_opts:
type: none
o: bind
device: ${BACKUP_DATA_PATH:-./data/staging/backups}

View File

@ -0,0 +1,44 @@
# 开发环境配置 (Requirements 6.5)
ENVIRONMENT=development
COMPOSE_PROJECT_NAME=anxin-dev
# 数据库配置
DB_HOST=anxin-mysql
DB_PORT=3306
DB_NAME=anxin_dev
DB_USER=anxin_dev
DB_PASSWORD=dev_password
MYSQL_ROOT_PASSWORD=dev_root_password
# 后端服务配置
BACKEND_PORT=8080
SPRING_PROFILES_ACTIVE=dev
JAVA_OPTS=-Xms256m -Xmx512m
# 前端服务配置
FRONTEND_PORT=3000
API_BASE_URL=http://localhost:8080
# 容器资源配置 (开发环境使用较少资源)
FRONTEND_MEMORY_LIMIT=128
BACKEND_MEMORY_LIMIT=512
DATABASE_MEMORY_LIMIT=256
FRONTEND_CPU_LIMIT=0.25
BACKEND_CPU_LIMIT=0.5
DATABASE_CPU_LIMIT=0.25
# 日志配置 (开发环境使用DEBUG级别)
LOG_LEVEL=DEBUG
LOG_PATH=./logs/dev
LOG_MAX_SIZE=50MB
LOG_MAX_FILES=5
# 网络配置
NETWORK_NAME=anxin-dev-network
SUBNET=172.21.0.0/16
# 卷配置
MYSQL_DATA_PATH=./data/dev/mysql
LOG_DATA_PATH=./data/dev/logs
CONFIG_DATA_PATH=./data/dev/configs

View File

@ -0,0 +1,44 @@
# 生产环境配置 (Requirements 6.5)
ENVIRONMENT=production
COMPOSE_PROJECT_NAME=anxin-prod
# 数据库配置
DB_HOST=anxin-mysql
DB_PORT=3306
DB_NAME=anxin_prod
DB_USER=anxin_prod
DB_PASSWORD=CHANGE_ME_PRODUCTION_PASSWORD
MYSQL_ROOT_PASSWORD=CHANGE_ME_ROOT_PASSWORD
# 后端服务配置
BACKEND_PORT=8080
SPRING_PROFILES_ACTIVE=prod
JAVA_OPTS=-Xms1024m -Xmx2048m
# 前端服务配置
FRONTEND_PORT=80
API_BASE_URL=https://api.anxin.com
# 容器资源配置 (生产环境使用更多资源)
FRONTEND_MEMORY_LIMIT=512
BACKEND_MEMORY_LIMIT=2048
DATABASE_MEMORY_LIMIT=1024
FRONTEND_CPU_LIMIT=1.0
BACKEND_CPU_LIMIT=2.0
DATABASE_CPU_LIMIT=1.0
# 日志配置 (生产环境使用WARN级别)
LOG_LEVEL=WARN
LOG_PATH=./logs/prod
LOG_MAX_SIZE=200MB
LOG_MAX_FILES=15
# 网络配置
NETWORK_NAME=anxin-prod-network
SUBNET=172.23.0.0/16
# 卷配置
MYSQL_DATA_PATH=./data/prod/mysql
LOG_DATA_PATH=./data/prod/logs
CONFIG_DATA_PATH=./data/prod/configs

View File

@ -0,0 +1,44 @@
# 测试环境配置 (Requirements 6.5)
ENVIRONMENT=staging
COMPOSE_PROJECT_NAME=anxin-staging
# 数据库配置
DB_HOST=anxin-mysql
DB_PORT=3306
DB_NAME=anxin_staging
DB_USER=anxin_staging
DB_PASSWORD=staging_password
MYSQL_ROOT_PASSWORD=staging_root_password
# 后端服务配置
BACKEND_PORT=8080
SPRING_PROFILES_ACTIVE=staging
JAVA_OPTS=-Xms512m -Xmx768m
# 前端服务配置
FRONTEND_PORT=80
API_BASE_URL=http://staging-api.anxin.com
# 容器资源配置 (测试环境使用中等资源)
FRONTEND_MEMORY_LIMIT=192
BACKEND_MEMORY_LIMIT=768
DATABASE_MEMORY_LIMIT=384
FRONTEND_CPU_LIMIT=0.5
BACKEND_CPU_LIMIT=0.75
DATABASE_CPU_LIMIT=0.5
# 日志配置
LOG_LEVEL=INFO
LOG_PATH=./logs/staging
LOG_MAX_SIZE=100MB
LOG_MAX_FILES=7
# 网络配置
NETWORK_NAME=anxin-staging-network
SUBNET=172.22.0.0/16
# 卷配置
MYSQL_DATA_PATH=./data/staging/mysql
LOG_DATA_PATH=./data/staging/logs
CONFIG_DATA_PATH=./data/staging/configs

View File

@ -0,0 +1,40 @@
# Node modules
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Build outputs
dist
.tmp
.cache
# IDE files
.vscode
.idea
*.swp
*.swo
# OS files
.DS_Store
Thumbs.db
# Git
.git
.gitignore
# Documentation
README.md
*.md
# Test files
tests
__tests__
*.test.js
*.spec.js
# Environment files
.env.local
.env.development.local
.env.test.local
.env.production.local

2
docker/frontend/.gitkeep Normal file
View File

@ -0,0 +1,2 @@
# 前端容器配置目录
# 此文件确保目录被Git跟踪

View File

@ -0,0 +1,43 @@
# 多阶段构建 Dockerfile for 若依 Vue3 前端应用
# 第一阶段:构建阶段
FROM node:18-alpine AS build-stage
# 设置工作目录
WORKDIR /app
# 复制 package.json 和 package-lock.json如果存在
COPY RuoYi-Vue3/package*.json ./
# 安装依赖
RUN npm install --registry=https://registry.npmmirror.com
# 复制源代码
COPY RuoYi-Vue3/ .
# 构建应用
RUN npm run build:prod
# 第二阶段:运行阶段
FROM nginx:alpine AS production-stage
# 安装 tzdata 用于时区设置
RUN apk add --no-cache tzdata
# 设置时区
ENV TZ=Asia/Shanghai
# 从构建阶段复制构建产物到 nginx 默认目录
COPY --from=build-stage /app/dist /usr/share/nginx/html
# 复制 nginx 配置文件
COPY docker/configs/nginx.conf.template /etc/nginx/conf.d/default.conf
# 创建日志目录
RUN mkdir -p /var/log/nginx
# 暴露端口
EXPOSE 80
# 启动 nginx
CMD ["nginx", "-g", "daemon off;"]

67
docker/frontend/build.sh Normal file
View File

@ -0,0 +1,67 @@
#!/bin/bash
# 前端容器构建脚本
# 用于构建若依 Vue3 前端 Docker 镜像
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查 Docker 是否安装
if ! command -v docker &> /dev/null; then
log_error "Docker 未安装或不在 PATH 中"
exit 1
fi
# 设置变量
IMAGE_NAME="anxin-frontend"
TAG="${1:-latest}"
DOCKERFILE_PATH="docker/frontend/Dockerfile"
log_info "开始构建前端 Docker 镜像..."
log_info "镜像名称: ${IMAGE_NAME}:${TAG}"
log_info "Dockerfile 路径: ${DOCKERFILE_PATH}"
# 检查 Dockerfile 是否存在
if [ ! -f "${DOCKERFILE_PATH}" ]; then
log_error "Dockerfile 不存在: ${DOCKERFILE_PATH}"
exit 1
fi
# 检查前端源码目录是否存在
if [ ! -d "RuoYi-Vue3" ]; then
log_error "前端源码目录不存在: RuoYi-Vue3"
exit 1
fi
# 构建镜像
log_info "正在构建镜像..."
if docker build -t "${IMAGE_NAME}:${TAG}" -f "${DOCKERFILE_PATH}" .; then
log_info "镜像构建成功: ${IMAGE_NAME}:${TAG}"
# 显示镜像信息
log_info "镜像信息:"
docker images "${IMAGE_NAME}:${TAG}"
else
log_error "镜像构建失败"
exit 1
fi
log_info "前端镜像构建完成!"

2
docker/scripts/.gitkeep Normal file
View File

@ -0,0 +1,2 @@
# 构建和部署脚本目录
# 此文件确保目录被Git跟踪

View File

@ -0,0 +1,104 @@
#!/bin/bash
# 生产环境数据库备份脚本
# Requirements: 5.3, 6.5
set -e
# 配置变量
BACKUP_DIR="/backup"
DATE=$(date +%Y%m%d_%H%M%S)
DB_NAME=${DB_NAME:-anxin_prod}
DB_USER=${DB_USER:-anxin_prod}
DB_PASSWORD=${DB_PASSWORD}
MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
RETENTION_DAYS=${BACKUP_RETENTION_DAYS:-30}
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
# 创建备份目录
mkdir -p "${BACKUP_DIR}/daily"
mkdir -p "${BACKUP_DIR}/weekly"
mkdir -p "${BACKUP_DIR}/monthly"
# 执行数据库备份
log "Starting database backup for production environment..."
# 全量备份
BACKUP_FILE="${BACKUP_DIR}/daily/${DB_NAME}_${DATE}.sql.gz"
log "Creating full backup: ${BACKUP_FILE}"
mysqldump -h anxin-mysql \
-u root \
-p"${MYSQL_ROOT_PASSWORD}" \
--single-transaction \
--routines \
--triggers \
--events \
--hex-blob \
--opt \
--lock-tables=false \
"${DB_NAME}" | gzip > "${BACKUP_FILE}"
if [ $? -eq 0 ]; then
log "Database backup completed successfully"
# 验证备份文件
if [ -f "${BACKUP_FILE}" ] && [ -s "${BACKUP_FILE}" ]; then
log "Backup file verification passed: $(du -h ${BACKUP_FILE} | cut -f1)"
else
log "ERROR: Backup file verification failed"
exit 1
fi
else
log "ERROR: Database backup failed"
exit 1
fi
# 周备份 (每周日)
if [ $(date +%u) -eq 7 ]; then
WEEKLY_BACKUP="${BACKUP_DIR}/weekly/${DB_NAME}_week_${DATE}.sql.gz"
log "Creating weekly backup: ${WEEKLY_BACKUP}"
cp "${BACKUP_FILE}" "${WEEKLY_BACKUP}"
fi
# 月备份 (每月1号)
if [ $(date +%d) -eq 01 ]; then
MONTHLY_BACKUP="${BACKUP_DIR}/monthly/${DB_NAME}_month_${DATE}.sql.gz"
log "Creating monthly backup: ${MONTHLY_BACKUP}"
cp "${BACKUP_FILE}" "${MONTHLY_BACKUP}"
fi
# 清理过期备份
log "Cleaning up old backups..."
# 清理日备份 (保留指定天数)
find "${BACKUP_DIR}/daily" -name "*.sql.gz" -mtime +${RETENTION_DAYS} -delete
log "Cleaned up daily backups older than ${RETENTION_DAYS} days"
# 清理周备份 (保留12周)
find "${BACKUP_DIR}/weekly" -name "*.sql.gz" -mtime +84 -delete
log "Cleaned up weekly backups older than 12 weeks"
# 清理月备份 (保留12个月)
find "${BACKUP_DIR}/monthly" -name "*.sql.gz" -mtime +365 -delete
log "Cleaned up monthly backups older than 12 months"
# 备份统计
DAILY_COUNT=$(ls -1 "${BACKUP_DIR}/daily"/*.sql.gz 2>/dev/null | wc -l)
WEEKLY_COUNT=$(ls -1 "${BACKUP_DIR}/weekly"/*.sql.gz 2>/dev/null | wc -l)
MONTHLY_COUNT=$(ls -1 "${BACKUP_DIR}/monthly"/*.sql.gz 2>/dev/null | wc -l)
log "Backup statistics: Daily: ${DAILY_COUNT}, Weekly: ${WEEKLY_COUNT}, Monthly: ${MONTHLY_COUNT}"
# 发送备份状态通知 (如果配置了通知)
if [ -n "${BACKUP_NOTIFICATION_URL}" ]; then
curl -X POST "${BACKUP_NOTIFICATION_URL}" \
-H "Content-Type: application/json" \
-d "{\"status\":\"success\",\"message\":\"Production database backup completed\",\"timestamp\":\"${DATE}\"}" \
2>/dev/null || log "Failed to send backup notification"
fi
log "Production database backup process completed successfully"

65
docker/scripts/backup.sh Normal file
View File

@ -0,0 +1,65 @@
#!/bin/bash
# 测试环境数据库备份脚本
# Requirements: 5.3, 6.5
set -e
# 配置变量
BACKUP_DIR="/backup"
DATE=$(date +%Y%m%d_%H%M%S)
DB_NAME=${DB_NAME:-anxin_staging}
DB_USER=${DB_USER:-anxin_staging}
DB_PASSWORD=${DB_PASSWORD:-staging_password}
MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-staging_root_password}
RETENTION_DAYS=${BACKUP_RETENTION_DAYS:-7}
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
# 创建备份目录
mkdir -p "${BACKUP_DIR}"
# 执行数据库备份
log "Starting database backup for staging environment..."
BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_${DATE}.sql.gz"
log "Creating backup: ${BACKUP_FILE}"
mysqldump -h anxin-mysql \
-u root \
-p"${MYSQL_ROOT_PASSWORD}" \
--single-transaction \
--routines \
--triggers \
--hex-blob \
--opt \
--lock-tables=false \
"${DB_NAME}" | gzip > "${BACKUP_FILE}"
if [ $? -eq 0 ]; then
log "Database backup completed successfully"
# 验证备份文件
if [ -f "${BACKUP_FILE}" ] && [ -s "${BACKUP_FILE}" ]; then
log "Backup file verification passed: $(du -h ${BACKUP_FILE} | cut -f1)"
else
log "ERROR: Backup file verification failed"
exit 1
fi
else
log "ERROR: Database backup failed"
exit 1
fi
# 清理过期备份
log "Cleaning up old backups..."
find "${BACKUP_DIR}" -name "*.sql.gz" -mtime +${RETENTION_DAYS} -delete
log "Cleaned up backups older than ${RETENTION_DAYS} days"
# 备份统计
BACKUP_COUNT=$(ls -1 "${BACKUP_DIR}"/*.sql.gz 2>/dev/null | wc -l)
log "Current backup count: ${BACKUP_COUNT}"
log "Staging database backup process completed successfully"

View File

@ -0,0 +1,701 @@
#!/bin/bash
# 环境配置管理脚本 (env-config.sh)
# 实现环境变量配置管理、支持不同环境的参数切换、添加配置验证功能
# Requirements: 6.1, 6.2, 6.3, 6.4
set -e
# 脚本目录和项目路径
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DOCKER_DIR="$(dirname "$SCRIPT_DIR")"
PROJECT_ROOT="$(dirname "$DOCKER_DIR")"
ENVIRONMENTS_DIR="${DOCKER_DIR}/environments"
CONFIGS_DIR="${DOCKER_DIR}/configs"
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_debug() {
echo -e "${BLUE}[DEBUG]${NC} $1"
}
log_success() {
echo -e "${CYAN}[SUCCESS]${NC} $1"
}
# 显示帮助信息
show_help() {
cat << EOF
环境配置管理脚本 - 若依框架Docker部署
用法: $0 [命令] [环境] [选项]
命令:
validate 验证环境配置文件
switch 切换到指定环境配置
show 显示环境配置信息
compare 比较不同环境配置
backup 备份当前环境配置
restore 恢复环境配置
template 生成环境配置模板
check 检查配置完整性
list 列出所有可用环境
help 显示此帮助信息
环境:
development (dev) 开发环境
staging (stage) 测试环境
production (prod) 生产环境
选项:
--force 强制执行操作(跳过确认)
--verbose 详细输出模式
--dry-run 预览模式(不实际执行)
示例:
$0 validate development # 验证开发环境配置
$0 switch production # 切换到生产环境
$0 show staging # 显示测试环境配置
$0 compare dev prod # 比较开发和生产环境配置
$0 backup # 备份当前配置
$0 template development # 生成开发环境配置模板
EOF
}
# 验证环境参数
validate_environment() {
local env=$1
case $env in
development|dev)
echo "development"
;;
staging|stage)
echo "staging"
;;
production|prod)
echo "production"
;;
*)
log_error "无效的环境: $env"
log_info "支持的环境: development, staging, production"
exit 1
;;
esac
}
# 获取环境配置文件路径
get_env_file() {
local env=$1
echo "${ENVIRONMENTS_DIR}/.env.${env}"
}
# 获取当前活动的环境配置文件路径
get_active_env_file() {
echo "${DOCKER_DIR}/.env"
}
# 检查环境配置文件是否存在
check_env_file_exists() {
local env=$1
local env_file=$(get_env_file $env)
if [ ! -f "$env_file" ]; then
log_error "环境配置文件不存在: $env_file"
return 1
fi
return 0
}
# 验证环境配置文件 (Requirements 6.1, 6.2, 6.3, 6.4)
validate_env_config() {
local env=$1
local env_file=$(get_env_file $env)
local errors=0
log_info "验证 $env 环境配置文件: $env_file"
if ! check_env_file_exists $env; then
return 1
fi
# 必需的配置项列表
local required_vars=(
"ENVIRONMENT"
"COMPOSE_PROJECT_NAME"
"DB_HOST"
"DB_PORT"
"DB_NAME"
"DB_USER"
"DB_PASSWORD"
"MYSQL_ROOT_PASSWORD"
"BACKEND_PORT"
"FRONTEND_PORT"
"SPRING_PROFILES_ACTIVE"
"API_BASE_URL"
"LOG_LEVEL"
"NETWORK_NAME"
"MYSQL_DATA_PATH"
)
# 检查必需的环境变量
log_debug "检查必需的环境变量..."
for var in "${required_vars[@]}"; do
if ! grep -q "^${var}=" "$env_file"; then
log_error "缺少必需的环境变量: $var"
((errors++))
else
local value=$(grep "^${var}=" "$env_file" | cut -d'=' -f2-)
if [ -z "$value" ] || [ "$value" = "CHANGE_ME_PRODUCTION_PASSWORD" ] || [ "$value" = "CHANGE_ME_ROOT_PASSWORD" ]; then
log_warn "环境变量 $var 需要设置有效值"
((errors++))
fi
fi
done
# 验证数据库连接配置 (Requirement 6.1)
log_debug "验证数据库连接配置..."
local db_port=$(grep "^DB_PORT=" "$env_file" | cut -d'=' -f2)
if [ -n "$db_port" ] && ! [[ "$db_port" =~ ^[0-9]+$ ]]; then
log_error "DB_PORT 必须是数字: $db_port"
((errors++))
fi
# 验证前端API基础URL配置 (Requirement 6.2)
log_debug "验证前端API基础URL配置..."
local api_url=$(grep "^API_BASE_URL=" "$env_file" | cut -d'=' -f2)
if [ -n "$api_url" ] && ! [[ "$api_url" =~ ^https?:// ]]; then
log_error "API_BASE_URL 必须是有效的HTTP/HTTPS URL: $api_url"
((errors++))
fi
# 验证容器资源限制配置 (Requirement 6.3)
log_debug "验证容器资源限制配置..."
local memory_vars=("FRONTEND_MEMORY_LIMIT" "BACKEND_MEMORY_LIMIT" "DATABASE_MEMORY_LIMIT")
for var in "${memory_vars[@]}"; do
local value=$(grep "^${var}=" "$env_file" | cut -d'=' -f2)
if [ -n "$value" ] && ! [[ "$value" =~ ^[0-9]+$ ]]; then
log_error "$var 必须是数字 (MB): $value"
((errors++))
fi
done
local cpu_vars=("FRONTEND_CPU_LIMIT" "BACKEND_CPU_LIMIT" "DATABASE_CPU_LIMIT")
for var in "${cpu_vars[@]}"; do
local value=$(grep "^${var}=" "$env_file" | cut -d'=' -f2)
if [ -n "$value" ] && ! [[ "$value" =~ ^[0-9]+\.?[0-9]*$ ]]; then
log_error "$var 必须是有效的CPU限制值: $value"
((errors++))
fi
done
# 验证日志级别和输出路径配置 (Requirement 6.4)
log_debug "验证日志配置..."
local log_level=$(grep "^LOG_LEVEL=" "$env_file" | cut -d'=' -f2)
if [ -n "$log_level" ] && ! [[ "$log_level" =~ ^(DEBUG|INFO|WARN|ERROR)$ ]]; then
log_error "LOG_LEVEL 必须是 DEBUG, INFO, WARN 或 ERROR: $log_level"
((errors++))
fi
local log_path=$(grep "^LOG_PATH=" "$env_file" | cut -d'=' -f2)
if [ -n "$log_path" ] && [[ "$log_path" =~ ^/ ]] && [ ! -d "$(dirname "$log_path")" ]; then
log_warn "日志路径的父目录不存在: $(dirname "$log_path")"
fi
# 验证网络配置
log_debug "验证网络配置..."
local subnet=$(grep "^SUBNET=" "$env_file" | cut -d'=' -f2)
if [ -n "$subnet" ] && ! [[ "$subnet" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$ ]]; then
log_error "SUBNET 必须是有效的CIDR格式: $subnet"
((errors++))
fi
# 验证端口配置
log_debug "验证端口配置..."
local ports=("BACKEND_PORT" "FRONTEND_PORT" "DB_PORT")
for port_var in "${ports[@]}"; do
local port=$(grep "^${port_var}=" "$env_file" | cut -d'=' -f2)
if [ -n "$port" ]; then
if ! [[ "$port" =~ ^[0-9]+$ ]] || [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then
log_error "$port_var 必须是1-65535之间的数字: $port"
((errors++))
fi
fi
done
# 报告验证结果
if [ $errors -eq 0 ]; then
log_success "$env 环境配置验证通过"
return 0
else
log_error "$env 环境配置验证失败,发现 $errors 个错误"
return 1
fi
}
# 切换环境配置
switch_environment() {
local env=$1
local force=${2:-false}
local dry_run=${3:-false}
log_info "切换到 $env 环境配置..."
# 验证目标环境配置
if ! validate_env_config $env; then
log_error "目标环境配置验证失败,无法切换"
return 1
fi
local source_file=$(get_env_file $env)
local target_file=$(get_active_env_file)
# 备份当前配置
if [ -f "$target_file" ] && [ "$force" != "true" ]; then
local backup_file="${target_file}.backup.$(date +%Y%m%d_%H%M%S)"
if [ "$dry_run" != "true" ]; then
cp "$target_file" "$backup_file"
log_info "当前配置已备份到: $backup_file"
else
log_info "[DRY-RUN] 将备份当前配置到: $backup_file"
fi
fi
# 复制环境配置
if [ "$dry_run" != "true" ]; then
cp "$source_file" "$target_file"
log_success "已切换到 $env 环境配置"
# 显示关键配置信息
show_key_config "$env"
else
log_info "[DRY-RUN] 将复制 $source_file$target_file"
fi
}
# 显示环境配置信息
show_env_config() {
local env=$1
local env_file=$(get_env_file $env)
if ! check_env_file_exists $env; then
return 1
fi
log_info "显示 $env 环境配置:"
echo "----------------------------------------"
# 显示关键配置项
local key_vars=(
"ENVIRONMENT"
"COMPOSE_PROJECT_NAME"
"DB_NAME"
"DB_USER"
"BACKEND_PORT"
"FRONTEND_PORT"
"API_BASE_URL"
"LOG_LEVEL"
"SPRING_PROFILES_ACTIVE"
)
for var in "${key_vars[@]}"; do
local value=$(grep "^${var}=" "$env_file" | cut -d'=' -f2-)
if [ -n "$value" ]; then
printf "%-25s: %s\n" "$var" "$value"
fi
done
echo "----------------------------------------"
}
# 显示关键配置信息
show_key_config() {
local env=$1
local env_file=$(get_env_file $env)
echo
log_info "当前环境关键配置:"
echo " 环境: $(grep "^ENVIRONMENT=" "$env_file" | cut -d'=' -f2)"
echo " 项目: $(grep "^COMPOSE_PROJECT_NAME=" "$env_file" | cut -d'=' -f2)"
echo " 前端端口: $(grep "^FRONTEND_PORT=" "$env_file" | cut -d'=' -f2)"
echo " 后端端口: $(grep "^BACKEND_PORT=" "$env_file" | cut -d'=' -f2)"
echo " 数据库: $(grep "^DB_NAME=" "$env_file" | cut -d'=' -f2)"
echo " 日志级别: $(grep "^LOG_LEVEL=" "$env_file" | cut -d'=' -f2)"
echo
}
# 比较不同环境配置
compare_environments() {
local env1=$1
local env2=$2
log_info "比较 $env1$env2 环境配置..."
if ! check_env_file_exists $env1 || ! check_env_file_exists $env2; then
return 1
fi
local file1=$(get_env_file $env1)
local file2=$(get_env_file $env2)
echo "=========================================="
echo "配置差异 ($env1 vs $env2):"
echo "=========================================="
# 使用diff命令比较文件
if command -v diff &> /dev/null; then
diff -u "$file1" "$file2" || true
else
log_warn "diff命令不可用使用基本比较"
# 基本比较逻辑
local vars1=$(grep "^[A-Z]" "$file1" | cut -d'=' -f1 | sort)
local vars2=$(grep "^[A-Z]" "$file2" | cut -d'=' -f1 | sort)
# 找出差异变量
local all_vars=$(echo -e "$vars1\n$vars2" | sort -u)
for var in $all_vars; do
local val1=$(grep "^${var}=" "$file1" | cut -d'=' -f2- 2>/dev/null || echo "")
local val2=$(grep "^${var}=" "$file2" | cut -d'=' -f2- 2>/dev/null || echo "")
if [ "$val1" != "$val2" ]; then
printf "%-25s: %-20s | %s\n" "$var" "$val1" "$val2"
fi
done
fi
echo "=========================================="
}
# 备份环境配置
backup_config() {
local timestamp=$(date +%Y%m%d_%H%M%S)
local backup_dir="${DOCKER_DIR}/backups/config_${timestamp}"
log_info "备份环境配置到: $backup_dir"
mkdir -p "$backup_dir"
# 备份所有环境配置文件
cp -r "$ENVIRONMENTS_DIR" "$backup_dir/"
# 备份当前活动配置
if [ -f "$(get_active_env_file)" ]; then
cp "$(get_active_env_file)" "$backup_dir/active.env"
fi
# 创建备份信息文件
cat > "$backup_dir/backup_info.txt" << EOF
备份时间: $(date)
备份内容: 环境配置文件
备份路径: $backup_dir
当前环境: $(grep "^ENVIRONMENT=" "$(get_active_env_file)" 2>/dev/null | cut -d'=' -f2 || echo "未知")
EOF
log_success "配置备份完成: $backup_dir"
}
# 恢复环境配置
restore_config() {
local backup_path=$1
if [ -z "$backup_path" ]; then
log_error "请指定备份路径"
return 1
fi
if [ ! -d "$backup_path" ]; then
log_error "备份路径不存在: $backup_path"
return 1
fi
log_info "从备份恢复环境配置: $backup_path"
# 确认操作
read -p "确认恢复配置? 这将覆盖当前配置 (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
# 恢复环境配置目录
if [ -d "$backup_path/environments" ]; then
cp -r "$backup_path/environments/"* "$ENVIRONMENTS_DIR/"
log_info "环境配置文件已恢复"
fi
# 恢复活动配置
if [ -f "$backup_path/active.env" ]; then
cp "$backup_path/active.env" "$(get_active_env_file)"
log_info "活动配置文件已恢复"
fi
log_success "配置恢复完成"
else
log_info "取消恢复操作"
fi
}
# 生成环境配置模板
generate_template() {
local env=$1
local template_file="${ENVIRONMENTS_DIR}/.env.${env}.template"
log_info "生成 $env 环境配置模板: $template_file"
cat > "$template_file" << EOF
# $env 环境配置模板
# 复制此文件为 .env.$env 并根据实际环境修改配置
ENVIRONMENT=$env
COMPOSE_PROJECT_NAME=anxin-$env
# 数据库配置 (Requirement 6.1)
DB_HOST=anxin-mysql
DB_PORT=3306
DB_NAME=anxin_$env
DB_USER=anxin_$env
DB_PASSWORD=CHANGE_ME_PASSWORD
MYSQL_ROOT_PASSWORD=CHANGE_ME_ROOT_PASSWORD
# 后端服务配置
BACKEND_PORT=8080
SPRING_PROFILES_ACTIVE=$env
JAVA_OPTS=-Xms512m -Xmx1024m
# 前端服务配置 (Requirement 6.2)
FRONTEND_PORT=80
API_BASE_URL=http://localhost:8080
# 容器资源配置 (Requirement 6.3)
FRONTEND_MEMORY_LIMIT=256
BACKEND_MEMORY_LIMIT=1024
DATABASE_MEMORY_LIMIT=512
FRONTEND_CPU_LIMIT=0.5
BACKEND_CPU_LIMIT=1.0
DATABASE_CPU_LIMIT=0.5
# 日志配置 (Requirement 6.4)
LOG_LEVEL=INFO
LOG_PATH=./logs/$env
LOG_MAX_SIZE=100MB
LOG_MAX_FILES=10
# 网络配置
NETWORK_NAME=anxin-$env-network
SUBNET=172.20.0.0/16
# 卷配置
MYSQL_DATA_PATH=./data/$env/mysql
LOG_DATA_PATH=./data/$env/logs
CONFIG_DATA_PATH=./data/$env/configs
EOF
log_success "模板生成完成: $template_file"
}
# 检查配置完整性
check_config_integrity() {
log_info "检查所有环境配置完整性..."
local environments=("development" "staging" "production")
local total_errors=0
for env in "${environments[@]}"; do
echo
if validate_env_config $env; then
log_success "$env 环境配置完整"
else
((total_errors++))
fi
done
echo
if [ $total_errors -eq 0 ]; then
log_success "所有环境配置检查通过"
return 0
else
log_error "发现 $total_errors 个环境配置问题"
return 1
fi
}
# 列出所有可用环境
list_environments() {
log_info "可用环境配置:"
for env_file in "$ENVIRONMENTS_DIR"/.env.*; do
if [ -f "$env_file" ] && [[ ! "$env_file" =~ \.template$ ]] && [[ ! "$env_file" =~ \.example$ ]]; then
local env_name=$(basename "$env_file" | sed 's/^\.env\.//')
local env_desc=""
case $env_name in
development)
env_desc="开发环境"
;;
staging)
env_desc="测试环境"
;;
production)
env_desc="生产环境"
;;
*)
env_desc="自定义环境"
;;
esac
printf " %-12s - %s\n" "$env_name" "$env_desc"
# 显示关键信息
if [ -f "$env_file" ]; then
local project=$(grep "^COMPOSE_PROJECT_NAME=" "$env_file" | cut -d'=' -f2)
local frontend_port=$(grep "^FRONTEND_PORT=" "$env_file" | cut -d'=' -f2)
local backend_port=$(grep "^BACKEND_PORT=" "$env_file" | cut -d'=' -f2)
printf " 项目: %s, 前端: %s, 后端: %s\n" "$project" "$frontend_port" "$backend_port"
fi
fi
done
echo
# 显示当前活动环境
local active_file=$(get_active_env_file)
if [ -f "$active_file" ]; then
local current_env=$(grep "^ENVIRONMENT=" "$active_file" | cut -d'=' -f2)
log_info "当前活动环境: $current_env"
else
log_warn "未找到活动环境配置"
fi
}
# 解析命令行参数
parse_args() {
FORCE=false
VERBOSE=false
DRY_RUN=false
while [[ $# -gt 0 ]]; do
case $1 in
--force)
FORCE=true
shift
;;
--verbose)
VERBOSE=true
shift
;;
--dry-run)
DRY_RUN=true
shift
;;
*)
break
;;
esac
done
COMMAND=$1
ENVIRONMENT=$2
ENVIRONMENT2=$3
}
# 主函数
main() {
parse_args "$@"
case $COMMAND in
validate)
if [ -z "$ENVIRONMENT" ]; then
log_error "请指定环境"
show_help
exit 1
fi
env=$(validate_environment "$ENVIRONMENT")
validate_env_config "$env"
;;
switch)
if [ -z "$ENVIRONMENT" ]; then
log_error "请指定环境"
show_help
exit 1
fi
env=$(validate_environment "$ENVIRONMENT")
switch_environment "$env" "$FORCE" "$DRY_RUN"
;;
show)
if [ -z "$ENVIRONMENT" ]; then
log_error "请指定环境"
show_help
exit 1
fi
env=$(validate_environment "$ENVIRONMENT")
show_env_config "$env"
;;
compare)
if [ -z "$ENVIRONMENT" ] || [ -z "$ENVIRONMENT2" ]; then
log_error "请指定两个环境进行比较"
show_help
exit 1
fi
env1=$(validate_environment "$ENVIRONMENT")
env2=$(validate_environment "$ENVIRONMENT2")
compare_environments "$env1" "$env2"
;;
backup)
backup_config
;;
restore)
restore_config "$ENVIRONMENT"
;;
template)
if [ -z "$ENVIRONMENT" ]; then
log_error "请指定环境"
show_help
exit 1
fi
env=$(validate_environment "$ENVIRONMENT")
generate_template "$env"
;;
check)
check_config_integrity
;;
list)
list_environments
;;
help|--help|-h)
show_help
;;
*)
log_error "未知命令: $COMMAND"
show_help
exit 1
;;
esac
}
# 检查必要的目录
if [ ! -d "$ENVIRONMENTS_DIR" ]; then
log_error "环境配置目录不存在: $ENVIRONMENTS_DIR"
exit 1
fi
# 执行主函数
main "$@"

View File

@ -0,0 +1,346 @@
@echo off
REM 环境管理脚本 - Windows版本
REM 用于切换不同环境的Docker Compose配置
REM Requirements: 5.3, 6.5
setlocal enabledelayedexpansion
REM 设置脚本目录
set "SCRIPT_DIR=%~dp0"
set "DOCKER_DIR=%SCRIPT_DIR%.."
set "PROJECT_ROOT=%DOCKER_DIR%\.."
REM 颜色定义 (Windows不支持颜色使用文本标识)
set "INFO=[INFO]"
set "WARN=[WARN]"
set "ERROR=[ERROR]"
set "DEBUG=[DEBUG]"
REM 显示帮助信息
:show_help
echo 环境管理脚本 - 若依框架Docker部署 (Windows版本)
echo.
echo 用法: %~nx0 [命令] [环境]
echo.
echo 命令:
echo deploy 部署指定环境
echo stop 停止指定环境
echo restart 重启指定环境
echo status 查看指定环境状态
echo logs 查看指定环境日志
echo clean 清理指定环境
echo backup 备份指定环境数据
echo list 列出所有可用环境
echo help 显示此帮助信息
echo.
echo 环境:
echo development (dev) 开发环境
echo staging (stage) 测试环境
echo production (prod) 生产环境
echo.
echo 示例:
echo %~nx0 deploy development # 部署开发环境
echo %~nx0 stop prod # 停止生产环境
echo %~nx0 logs staging # 查看测试环境日志
echo %~nx0 status dev # 查看开发环境状态
echo.
goto :eof
REM 验证环境参数
:validate_environment
set "input_env=%1"
if "%input_env%"=="development" set "validated_env=development" & goto :eof
if "%input_env%"=="dev" set "validated_env=development" & goto :eof
if "%input_env%"=="staging" set "validated_env=staging" & goto :eof
if "%input_env%"=="stage" set "validated_env=staging" & goto :eof
if "%input_env%"=="production" set "validated_env=production" & goto :eof
if "%input_env%"=="prod" set "validated_env=production" & goto :eof
echo %ERROR% 无效的环境: %input_env%
echo %INFO% 支持的环境: development, staging, production
exit /b 1
REM 获取compose文件路径
:get_compose_file
set "compose_file=%DOCKER_DIR%\docker-compose.%1.yml"
goto :eof
REM 获取环境配置文件路径
:get_env_file
set "env_file=%DOCKER_DIR%\environments\.env.%1"
goto :eof
REM 检查文件是否存在
:check_files
call :get_compose_file %1
call :get_env_file %1
if not exist "%compose_file%" (
echo %ERROR% Compose文件不存在: %compose_file%
exit /b 1
)
if not exist "%env_file%" (
echo %ERROR% 环境配置文件不存在: %env_file%
exit /b 1
)
echo %DEBUG% 文件检查通过: %compose_file%, %env_file%
goto :eof
REM 创建数据目录
:create_directories
set "env=%1"
echo %INFO% 创建数据目录...
REM 创建基础目录结构
if not exist "%DOCKER_DIR%\data\%env%" mkdir "%DOCKER_DIR%\data\%env%"
if not exist "%DOCKER_DIR%\data\%env%\mysql" mkdir "%DOCKER_DIR%\data\%env%\mysql"
if not exist "%DOCKER_DIR%\data\%env%\mysql-logs" mkdir "%DOCKER_DIR%\data\%env%\mysql-logs"
if not exist "%DOCKER_DIR%\data\%env%\backend-logs" mkdir "%DOCKER_DIR%\data\%env%\backend-logs"
if not exist "%DOCKER_DIR%\data\%env%\uploads" mkdir "%DOCKER_DIR%\data\%env%\uploads"
if not exist "%DOCKER_DIR%\data\%env%\nginx-logs" mkdir "%DOCKER_DIR%\data\%env%\nginx-logs"
if not "%env%"=="development" (
if not exist "%DOCKER_DIR%\data\%env%\backups" mkdir "%DOCKER_DIR%\data\%env%\backups"
)
goto :eof
REM 部署环境
:deploy_environment
set "env=%1"
echo %INFO% 开始部署 %env% 环境...
call :check_files %env%
if errorlevel 1 exit /b 1
call :create_directories %env%
echo %INFO% 启动Docker Compose服务...
cd /d "%DOCKER_DIR%"
docker-compose -f "%compose_file%" --env-file "%env_file%" up -d
if errorlevel 1 (
echo %ERROR% Docker Compose启动失败
exit /b 1
)
echo %INFO% 等待服务启动...
timeout /t 10 /nobreak >nul
call :check_services %env%
echo %INFO% %env% 环境部署完成!
goto :eof
REM 停止环境
:stop_environment
set "env=%1"
echo %INFO% 停止 %env% 环境...
call :get_compose_file %env%
call :get_env_file %env%
cd /d "%DOCKER_DIR%"
docker-compose -f "%compose_file%" --env-file "%env_file%" down
echo %INFO% %env% 环境已停止
goto :eof
REM 重启环境
:restart_environment
set "env=%1"
echo %INFO% 重启 %env% 环境...
call :stop_environment %env%
timeout /t 5 /nobreak >nul
call :deploy_environment %env%
goto :eof
REM 查看环境状态
:check_services
set "env=%1"
echo %INFO% 检查 %env% 环境服务状态...
call :get_compose_file %env%
call :get_env_file %env%
cd /d "%DOCKER_DIR%"
docker-compose -f "%compose_file%" --env-file "%env_file%" ps
echo %INFO% 执行健康检查...
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | findstr anxin-%env%
goto :eof
REM 查看日志
:view_logs
set "env=%1"
set "service=%2"
call :get_compose_file %env%
call :get_env_file %env%
cd /d "%DOCKER_DIR%"
if "%service%"=="" (
echo %INFO% 查看 %env% 环境所有服务日志...
docker-compose -f "%compose_file%" --env-file "%env_file%" logs -f
) else (
echo %INFO% 查看 %env% 环境 %service% 服务日志...
docker-compose -f "%compose_file%" --env-file "%env_file%" logs -f %service%
)
goto :eof
REM 清理环境
:clean_environment
set "env=%1"
echo %WARN% 即将清理 %env% 环境 (包括数据卷)...
set /p "confirm=确认继续? (y/N): "
if /i "%confirm%"=="y" (
echo %INFO% 清理 %env% 环境...
call :get_compose_file %env%
call :get_env_file %env%
cd /d "%DOCKER_DIR%"
docker-compose -f "%compose_file%" --env-file "%env_file%" down -v --remove-orphans
docker system prune -f
echo %INFO% %env% 环境清理完成
) else (
echo %INFO% 取消清理操作
)
goto :eof
REM 备份环境数据
:backup_environment
set "env=%1"
echo %INFO% 备份 %env% 环境数据...
if "%env%"=="production" (
docker exec anxin-mysql-prod /backup.sh
) else if "%env%"=="staging" (
docker exec anxin-mysql-staging /backup.sh
) else if "%env%"=="development" (
echo %WARN% 开发环境通常不需要备份
)
echo %INFO% %env% 环境数据备份完成
goto :eof
REM 列出所有环境
:list_environments
echo %INFO% 可用环境:
echo development (dev) - 开发环境
echo staging (stage) - 测试环境
echo production (prod) - 生产环境
echo.
echo %INFO% 当前运行的容器:
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | findstr anxin
if errorlevel 1 echo 无运行中的容器
goto :eof
REM 检查Docker是否安装
:check_docker
docker --version >nul 2>&1
if errorlevel 1 (
echo %ERROR% Docker未安装或不在PATH中
exit /b 1
)
docker-compose --version >nul 2>&1
if errorlevel 1 (
echo %ERROR% Docker Compose未安装或不在PATH中
exit /b 1
)
goto :eof
REM 主函数
:main
call :check_docker
if errorlevel 1 exit /b 1
set "command=%1"
set "environment=%2"
if "%command%"=="deploy" (
if "%environment%"=="" (
echo %ERROR% 请指定环境
call :show_help
exit /b 1
)
call :validate_environment %environment%
if errorlevel 1 exit /b 1
call :deploy_environment !validated_env!
) else if "%command%"=="stop" (
if "%environment%"=="" (
echo %ERROR% 请指定环境
call :show_help
exit /b 1
)
call :validate_environment %environment%
if errorlevel 1 exit /b 1
call :stop_environment !validated_env!
) else if "%command%"=="restart" (
if "%environment%"=="" (
echo %ERROR% 请指定环境
call :show_help
exit /b 1
)
call :validate_environment %environment%
if errorlevel 1 exit /b 1
call :restart_environment !validated_env!
) else if "%command%"=="status" (
if "%environment%"=="" (
echo %ERROR% 请指定环境
call :show_help
exit /b 1
)
call :validate_environment %environment%
if errorlevel 1 exit /b 1
call :check_services !validated_env!
) else if "%command%"=="logs" (
if "%environment%"=="" (
echo %ERROR% 请指定环境
call :show_help
exit /b 1
)
call :validate_environment %environment%
if errorlevel 1 exit /b 1
call :view_logs !validated_env! %3
) else if "%command%"=="clean" (
if "%environment%"=="" (
echo %ERROR% 请指定环境
call :show_help
exit /b 1
)
call :validate_environment %environment%
if errorlevel 1 exit /b 1
call :clean_environment !validated_env!
) else if "%command%"=="backup" (
if "%environment%"=="" (
echo %ERROR% 请指定环境
call :show_help
exit /b 1
)
call :validate_environment %environment%
if errorlevel 1 exit /b 1
call :backup_environment !validated_env!
) else if "%command%"=="list" (
call :list_environments
) else if "%command%"=="help" (
call :show_help
) else if "%command%"=="--help" (
call :show_help
) else if "%command%"=="-h" (
call :show_help
) else (
echo %ERROR% 未知命令: %command%
call :show_help
exit /b 1
)
goto :eof
REM 执行主函数
call :main %*

View File

@ -0,0 +1,379 @@
#!/bin/bash
# 环境管理脚本 - 用于切换不同环境的Docker Compose配置
# Requirements: 5.3, 6.5
set -e
# 脚本目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DOCKER_DIR="$(dirname "$SCRIPT_DIR")"
PROJECT_ROOT="$(dirname "$DOCKER_DIR")"
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_debug() {
echo -e "${BLUE}[DEBUG]${NC} $1"
}
# 显示帮助信息
show_help() {
cat << EOF
环境管理脚本 - 若依框架Docker部署
用法: $0 [命令] [环境]
命令:
deploy 部署指定环境
stop 停止指定环境
restart 重启指定环境
status 查看指定环境状态
logs 查看指定环境日志
clean 清理指定环境
backup 备份指定环境数据
list 列出所有可用环境
help 显示此帮助信息
环境:
development (dev) 开发环境
staging (stage) 测试环境
production (prod) 生产环境
示例:
$0 deploy development # 部署开发环境
$0 stop prod # 停止生产环境
$0 logs staging # 查看测试环境日志
$0 status dev # 查看开发环境状态
EOF
}
# 验证环境参数
validate_environment() {
local env=$1
case $env in
development|dev)
echo "development"
;;
staging|stage)
echo "staging"
;;
production|prod)
echo "production"
;;
*)
log_error "无效的环境: $env"
log_info "支持的环境: development, staging, production"
exit 1
;;
esac
}
# 获取compose文件路径
get_compose_file() {
local env=$1
echo "${DOCKER_DIR}/docker-compose.${env}.yml"
}
# 获取环境配置文件路径
get_env_file() {
local env=$1
echo "${DOCKER_DIR}/environments/.env.${env}"
}
# 检查文件是否存在
check_files() {
local env=$1
local compose_file=$(get_compose_file $env)
local env_file=$(get_env_file $env)
if [ ! -f "$compose_file" ]; then
log_error "Compose文件不存在: $compose_file"
exit 1
fi
if [ ! -f "$env_file" ]; then
log_error "环境配置文件不存在: $env_file"
exit 1
fi
log_debug "文件检查通过: $compose_file, $env_file"
}
# 部署环境
deploy_environment() {
local env=$1
local compose_file=$(get_compose_file $env)
local env_file=$(get_env_file $env)
log_info "开始部署 $env 环境..."
# 检查文件
check_files $env
# 创建必要的目录
log_info "创建数据目录..."
source "$env_file"
mkdir -p "${MYSQL_DATA_PATH:-./data/$env/mysql}"
mkdir -p "${MYSQL_LOG_PATH:-./data/$env/mysql-logs}"
mkdir -p "${BACKEND_LOG_PATH:-./data/$env/backend-logs}"
mkdir -p "${BACKEND_UPLOAD_PATH:-./data/$env/uploads}"
mkdir -p "${FRONTEND_LOG_PATH:-./data/$env/nginx-logs}"
if [ "$env" != "development" ]; then
mkdir -p "${BACKUP_DATA_PATH:-./data/$env/backups}"
fi
# 部署服务
log_info "启动Docker Compose服务..."
cd "$DOCKER_DIR"
docker-compose -f "$compose_file" --env-file "$env_file" up -d
# 等待服务启动
log_info "等待服务启动..."
sleep 10
# 检查服务状态
check_services $env
log_info "$env 环境部署完成!"
}
# 停止环境
stop_environment() {
local env=$1
local compose_file=$(get_compose_file $env)
local env_file=$(get_env_file $env)
log_info "停止 $env 环境..."
cd "$DOCKER_DIR"
docker-compose -f "$compose_file" --env-file "$env_file" down
log_info "$env 环境已停止"
}
# 重启环境
restart_environment() {
local env=$1
log_info "重启 $env 环境..."
stop_environment $env
sleep 5
deploy_environment $env
}
# 查看环境状态
check_services() {
local env=$1
local compose_file=$(get_compose_file $env)
local env_file=$(get_env_file $env)
log_info "检查 $env 环境服务状态..."
cd "$DOCKER_DIR"
docker-compose -f "$compose_file" --env-file "$env_file" ps
# 健康检查
log_info "执行健康检查..."
local services=("anxin-mysql-${env}" "anxin-backend-${env}" "anxin-frontend-${env}")
for service in "${services[@]}"; do
if docker ps --format "table {{.Names}}" | grep -q "$service"; then
local health=$(docker inspect --format='{{.State.Health.Status}}' "$service" 2>/dev/null || echo "no-healthcheck")
if [ "$health" = "healthy" ] || [ "$health" = "no-healthcheck" ]; then
log_info "$service: 运行正常"
else
log_warn "$service: 健康检查失败 ($health)"
fi
else
log_error "$service: 未运行"
fi
done
}
# 查看日志
view_logs() {
local env=$1
local service=$2
local compose_file=$(get_compose_file $env)
local env_file=$(get_env_file $env)
cd "$DOCKER_DIR"
if [ -n "$service" ]; then
log_info "查看 $env 环境 $service 服务日志..."
docker-compose -f "$compose_file" --env-file "$env_file" logs -f "$service"
else
log_info "查看 $env 环境所有服务日志..."
docker-compose -f "$compose_file" --env-file "$env_file" logs -f
fi
}
# 清理环境
clean_environment() {
local env=$1
local compose_file=$(get_compose_file $env)
local env_file=$(get_env_file $env)
log_warn "即将清理 $env 环境 (包括数据卷)..."
read -p "确认继续? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
log_info "清理 $env 环境..."
cd "$DOCKER_DIR"
docker-compose -f "$compose_file" --env-file "$env_file" down -v --remove-orphans
docker system prune -f
log_info "$env 环境清理完成"
else
log_info "取消清理操作"
fi
}
# 备份环境数据
backup_environment() {
local env=$1
log_info "备份 $env 环境数据..."
case $env in
production)
docker exec anxin-mysql-prod /backup.sh
;;
staging)
docker exec anxin-mysql-staging /backup.sh
;;
development)
log_warn "开发环境通常不需要备份"
;;
esac
log_info "$env 环境数据备份完成"
}
# 列出所有环境
list_environments() {
log_info "可用环境:"
echo " development (dev) - 开发环境"
echo " staging (stage) - 测试环境"
echo " production (prod) - 生产环境"
echo
log_info "当前运行的容器:"
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep anxin || echo " 无运行中的容器"
}
# 主函数
main() {
local command=$1
local environment=$2
case $command in
deploy)
if [ -z "$environment" ]; then
log_error "请指定环境"
show_help
exit 1
fi
env=$(validate_environment "$environment")
deploy_environment "$env"
;;
stop)
if [ -z "$environment" ]; then
log_error "请指定环境"
show_help
exit 1
fi
env=$(validate_environment "$environment")
stop_environment "$env"
;;
restart)
if [ -z "$environment" ]; then
log_error "请指定环境"
show_help
exit 1
fi
env=$(validate_environment "$environment")
restart_environment "$env"
;;
status)
if [ -z "$environment" ]; then
log_error "请指定环境"
show_help
exit 1
fi
env=$(validate_environment "$environment")
check_services "$env"
;;
logs)
if [ -z "$environment" ]; then
log_error "请指定环境"
show_help
exit 1
fi
env=$(validate_environment "$environment")
view_logs "$env" "$3"
;;
clean)
if [ -z "$environment" ]; then
log_error "请指定环境"
show_help
exit 1
fi
env=$(validate_environment "$environment")
clean_environment "$env"
;;
backup)
if [ -z "$environment" ]; then
log_error "请指定环境"
show_help
exit 1
fi
env=$(validate_environment "$environment")
backup_environment "$env"
;;
list)
list_environments
;;
help|--help|-h)
show_help
;;
*)
log_error "未知命令: $command"
show_help
exit 1
;;
esac
}
# 检查Docker是否安装
if ! command -v docker &> /dev/null; then
log_error "Docker未安装或不在PATH中"
exit 1
fi
if ! command -v docker-compose &> /dev/null; then
log_error "Docker Compose未安装或不在PATH中"
exit 1
fi
# 执行主函数
main "$@"

View File

@ -0,0 +1,10 @@
@echo off
REM 设置脚本文件权限 (Windows环境)
REM 在Linux/Unix环境中运行: chmod +x *.sh
echo Setting executable permissions for backup scripts...
echo Note: On Windows, this is for documentation only.
echo On Linux/Unix systems, run: chmod +x docker/scripts/*.sh
echo Backup scripts are ready for use.
pause

View File

@ -0,0 +1,254 @@
@echo off
REM 环境设置脚本 (Windows版本)
REM 用于初始化Docker部署环境和配置文件
setlocal enabledelayedexpansion
REM 设置颜色代码
set "RED=[91m"
set "GREEN=[92m"
set "YELLOW=[93m"
set "BLUE=[94m"
set "NC=[0m"
REM 日志函数
:log_info
echo %BLUE%[INFO]%NC% %~1
goto :eof
:log_success
echo %GREEN%[SUCCESS]%NC% %~1
goto :eof
:log_warning
echo %YELLOW%[WARNING]%NC% %~1
goto :eof
:log_error
echo %RED%[ERROR]%NC% %~1
goto :eof
REM 检查必要的命令
:check_requirements
call :log_info "检查系统要求..."
docker --version >nul 2>&1
if errorlevel 1 (
call :log_error "Docker 未安装,请先安装 Docker Desktop"
exit /b 1
)
docker-compose --version >nul 2>&1
if errorlevel 1 (
call :log_error "Docker Compose 未安装,请先安装 Docker Compose"
exit /b 1
)
call :log_success "系统要求检查通过"
goto :eof
REM 创建必要的目录
:create_directories
call :log_info "创建必要的目录结构..."
REM 数据目录
if not exist "data" mkdir data
if not exist "data\mysql" mkdir data\mysql
if not exist "data\logs" mkdir data\logs
if not exist "data\configs" mkdir data\configs
if not exist "data\dev" mkdir data\dev
if not exist "data\dev\mysql" mkdir data\dev\mysql
if not exist "data\dev\logs" mkdir data\dev\logs
if not exist "data\dev\configs" mkdir data\dev\configs
if not exist "data\staging" mkdir data\staging
if not exist "data\staging\mysql" mkdir data\staging\mysql
if not exist "data\staging\logs" mkdir data\staging\logs
if not exist "data\staging\configs" mkdir data\staging\configs
if not exist "data\prod" mkdir data\prod
if not exist "data\prod\mysql" mkdir data\prod\mysql
if not exist "data\prod\logs" mkdir data\prod\logs
if not exist "data\prod\configs" mkdir data\prod\configs
REM 日志目录
if not exist "logs" mkdir logs
if not exist "logs\dev" mkdir logs\dev
if not exist "logs\staging" mkdir logs\staging
if not exist "logs\prod" mkdir logs\prod
call :log_success "目录结构创建完成"
goto :eof
REM 设置环境配置
:setup_environment
set env=%~1
if "%env%"=="" set env=development
call :log_info "设置 %env% 环境配置..."
REM 检查环境配置文件是否存在
if not exist "environments\.env.%env%" (
call :log_error "环境配置文件 .env.%env% 不存在"
exit /b 1
)
REM 复制环境配置文件
copy "environments\.env.%env%" ".env" >nul
REM 复制Docker Compose配置
copy "docker-compose.yml.template" "docker-compose.yml" >nul
REM 复制配置文件模板
copy "configs\nginx.conf.template" "configs\nginx.conf" >nul
copy "configs\application-docker.yml.template" "configs\application-docker.yml" >nul
copy "configs\my.cnf.template" "configs\my.cnf" >nul
call :log_success "%env% 环境配置设置完成"
goto :eof
REM 验证配置
:validate_config
call :log_info "验证配置文件..."
REM 检查 .env 文件
if not exist ".env" (
call :log_error ".env 文件不存在,请先运行环境设置"
exit /b 1
)
REM 检查 docker-compose.yml 文件
if not exist "docker-compose.yml" (
call :log_error "docker-compose.yml 文件不存在"
exit /b 1
)
REM 验证 Docker Compose 配置语法
docker-compose config >nul 2>&1
if errorlevel 1 (
call :log_error "Docker Compose 配置文件语法错误"
exit /b 1
)
call :log_success "配置文件验证通过"
goto :eof
REM 显示帮助信息
:show_help
echo 用法: %~nx0 [选项] [环境]
echo.
echo 选项:
echo -h, --help 显示此帮助信息
echo -c, --check 仅检查系统要求
echo -v, --validate 仅验证配置
echo.
echo 环境:
echo development 开发环境 (默认)
echo staging 测试环境
echo production 生产环境
echo.
echo 示例:
echo %~nx0 # 设置开发环境
echo %~nx0 production # 设置生产环境
echo %~nx0 --check # 仅检查系统要求
goto :eof
REM 主函数
:main
set environment=development
set check_only=false
set validate_only=false
REM 解析命令行参数
:parse_args
if "%~1"=="" goto :start_setup
if "%~1"=="-h" goto :show_help_and_exit
if "%~1"=="--help" goto :show_help_and_exit
if "%~1"=="-c" (
set check_only=true
shift
goto :parse_args
)
if "%~1"=="--check" (
set check_only=true
shift
goto :parse_args
)
if "%~1"=="-v" (
set validate_only=true
shift
goto :parse_args
)
if "%~1"=="--validate" (
set validate_only=true
shift
goto :parse_args
)
if "%~1"=="development" (
set environment=%~1
shift
goto :parse_args
)
if "%~1"=="staging" (
set environment=%~1
shift
goto :parse_args
)
if "%~1"=="production" (
set environment=%~1
shift
goto :parse_args
)
call :log_error "未知参数: %~1"
call :show_help
exit /b 1
:show_help_and_exit
call :show_help
exit /b 0
:start_setup
REM 切换到docker目录
cd /d "%~dp0\.."
call :log_info "开始设置Docker部署环境..."
REM 检查系统要求
call :check_requirements
if errorlevel 1 exit /b 1
if "%check_only%"=="true" (
call :log_success "系统要求检查完成"
exit /b 0
)
if "%validate_only%"=="true" (
call :validate_config
if errorlevel 1 exit /b 1
call :log_success "配置验证完成"
exit /b 0
)
REM 创建目录结构
call :create_directories
REM 设置环境配置
call :setup_environment "%environment%"
if errorlevel 1 exit /b 1
REM 验证配置
call :validate_config
if errorlevel 1 exit /b 1
call :log_success "Docker部署环境设置完成"
call :log_info "下一步:"
call :log_info "1. 检查并修改 .env 文件中的配置"
call :log_info "2. 运行 'scripts\build.bat' 构建镜像"
call :log_info "3. 运行 'scripts\deploy.bat start' 启动服务"
goto :eof
REM 执行主函数
call :main %*

220
docker/scripts/setup-env.sh Normal file
View File

@ -0,0 +1,220 @@
#!/bin/bash
# 环境设置脚本
# 用于初始化Docker部署环境和配置文件
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查必要的命令
check_requirements() {
log_info "检查系统要求..."
if ! command -v docker &> /dev/null; then
log_error "Docker 未安装,请先安装 Docker"
exit 1
fi
if ! command -v docker-compose &> /dev/null; then
log_error "Docker Compose 未安装,请先安装 Docker Compose"
exit 1
fi
log_success "系统要求检查通过"
}
# 创建必要的目录
create_directories() {
log_info "创建必要的目录结构..."
# 数据目录
mkdir -p data/{mysql,logs,configs}
mkdir -p data/{dev,staging,prod}/{mysql,logs,configs}
# 日志目录
mkdir -p logs/{dev,staging,prod}
log_success "目录结构创建完成"
}
# 设置环境配置
setup_environment() {
local env=${1:-development}
log_info "设置 ${env} 环境配置..."
# 检查环境配置文件是否存在
if [[ ! -f "environments/.env.${env}" ]]; then
log_error "环境配置文件 .env.${env} 不存在"
exit 1
fi
# 复制环境配置文件
cp "environments/.env.${env}" .env
# 复制Docker Compose配置
cp docker-compose.yml.template docker-compose.yml
# 复制配置文件模板
cp configs/nginx.conf.template configs/nginx.conf
cp configs/application-docker.yml.template configs/application-docker.yml
cp configs/my.cnf.template configs/my.cnf
log_success "${env} 环境配置设置完成"
}
# 设置文件权限
set_permissions() {
log_info "设置文件权限..."
# 设置脚本执行权限
chmod +x scripts/*.sh
# 设置数据目录权限
chmod -R 755 data/
chmod -R 755 logs/
log_success "文件权限设置完成"
}
# 验证配置
validate_config() {
log_info "验证配置文件..."
# 检查 .env 文件
if [[ ! -f ".env" ]]; then
log_error ".env 文件不存在,请先运行环境设置"
exit 1
fi
# 检查 docker-compose.yml 文件
if [[ ! -f "docker-compose.yml" ]]; then
log_error "docker-compose.yml 文件不存在"
exit 1
fi
# 验证 Docker Compose 配置语法
if ! docker-compose config > /dev/null 2>&1; then
log_error "Docker Compose 配置文件语法错误"
exit 1
fi
log_success "配置文件验证通过"
}
# 显示帮助信息
show_help() {
echo "用法: $0 [选项] [环境]"
echo ""
echo "选项:"
echo " -h, --help 显示此帮助信息"
echo " -c, --check 仅检查系统要求"
echo " -v, --validate 仅验证配置"
echo ""
echo "环境:"
echo " development 开发环境 (默认)"
echo " staging 测试环境"
echo " production 生产环境"
echo ""
echo "示例:"
echo " $0 # 设置开发环境"
echo " $0 production # 设置生产环境"
echo " $0 --check # 仅检查系统要求"
}
# 主函数
main() {
local environment="development"
local check_only=false
local validate_only=false
# 解析命令行参数
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
exit 0
;;
-c|--check)
check_only=true
shift
;;
-v|--validate)
validate_only=true
shift
;;
development|staging|production)
environment=$1
shift
;;
*)
log_error "未知参数: $1"
show_help
exit 1
;;
esac
done
# 切换到docker目录
cd "$(dirname "$0")/.."
log_info "开始设置Docker部署环境..."
# 检查系统要求
check_requirements
if [[ "$check_only" == true ]]; then
log_success "系统要求检查完成"
exit 0
fi
if [[ "$validate_only" == true ]]; then
validate_config
log_success "配置验证完成"
exit 0
fi
# 创建目录结构
create_directories
# 设置环境配置
setup_environment "$environment"
# 设置文件权限
set_permissions
# 验证配置
validate_config
log_success "Docker部署环境设置完成"
log_info "下一步:"
log_info "1. 检查并修改 .env 文件中的配置"
log_info "2. 运行 'scripts/build.sh' 构建镜像"
log_info "3. 运行 'scripts/deploy.sh start' 启动服务"
}
# 执行主函数
main "$@"

View File

@ -0,0 +1,338 @@
package com.ruoyi.credit.domain.dto;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 通过验证的贷款数据传输对象
*
* @author ruoyi
* @date 2025-01-04
*/
public class ValidatedLoanDTO
{
/** 贷款ID */
private Long loanId;
/** 债权凭证ID */
private Long creditId;
/** 债权编号 */
private String creditNumber;
/** 合同编号 */
private String contractNumber;
/** 安保公司 */
private String securityCompany;
/** 债权金额 */
private BigDecimal creditAmount;
/** 贷款编号 */
private String loanNumber;
/** 贷款金额 */
private BigDecimal loanAmount;
/** 利率 */
private Double interestRate;
/** 贷款期限(月) */
private Integer loanTermMonths;
/** 月还款额 */
private BigDecimal monthlyPayment;
/** 贷款用途 */
private String loanPurpose;
/** 贷款状态 */
private String loanStatus;
/** 贷款开始日期 */
@JsonFormat(pattern = "yyyy-MM-dd")
private Date loanStartDate;
/** 贷款结束日期 */
@JsonFormat(pattern = "yyyy-MM-dd")
private Date loanEndDate;
/** 银行机构ID */
private Long bankInstitutionId;
/** 银行机构名称 */
private String bankInstitutionName;
/** 审批状态 */
private String approvalStatus;
/** 审批时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date approvalTime;
/** 审批人 */
private String approvedBy;
/** 申请时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date applicationDate;
/** 验证状态 */
private String validationStatus;
/** 验证时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date validationTime;
/** 验证结果 */
private String validationResult;
/** 失败原因 */
private String failureReason;
/** 验证得分 */
private Integer validationScore;
/** 规则版本 */
private String ruleVersion;
/** 债权状态 */
private String creditStatus;
/** 服务周期ID */
private Long servicePeriodId;
public Long getLoanId() {
return loanId;
}
public void setLoanId(Long loanId) {
this.loanId = loanId;
}
public Long getCreditId() {
return creditId;
}
public void setCreditId(Long creditId) {
this.creditId = creditId;
}
public String getCreditNumber() {
return creditNumber;
}
public void setCreditNumber(String creditNumber) {
this.creditNumber = creditNumber;
}
public String getContractNumber() {
return contractNumber;
}
public void setContractNumber(String contractNumber) {
this.contractNumber = contractNumber;
}
public String getSecurityCompany() {
return securityCompany;
}
public void setSecurityCompany(String securityCompany) {
this.securityCompany = securityCompany;
}
public BigDecimal getCreditAmount() {
return creditAmount;
}
public void setCreditAmount(BigDecimal creditAmount) {
this.creditAmount = creditAmount;
}
public String getLoanNumber() {
return loanNumber;
}
public void setLoanNumber(String loanNumber) {
this.loanNumber = loanNumber;
}
public BigDecimal getLoanAmount() {
return loanAmount;
}
public void setLoanAmount(BigDecimal loanAmount) {
this.loanAmount = loanAmount;
}
public Double getInterestRate() {
return interestRate;
}
public void setInterestRate(Double interestRate) {
this.interestRate = interestRate;
}
public Integer getLoanTermMonths() {
return loanTermMonths;
}
public void setLoanTermMonths(Integer loanTermMonths) {
this.loanTermMonths = loanTermMonths;
}
public BigDecimal getMonthlyPayment() {
return monthlyPayment;
}
public void setMonthlyPayment(BigDecimal monthlyPayment) {
this.monthlyPayment = monthlyPayment;
}
public String getLoanPurpose() {
return loanPurpose;
}
public void setLoanPurpose(String loanPurpose) {
this.loanPurpose = loanPurpose;
}
public String getLoanStatus() {
return loanStatus;
}
public void setLoanStatus(String loanStatus) {
this.loanStatus = loanStatus;
}
public Date getLoanStartDate() {
return loanStartDate;
}
public void setLoanStartDate(Date loanStartDate) {
this.loanStartDate = loanStartDate;
}
public Date getLoanEndDate() {
return loanEndDate;
}
public void setLoanEndDate(Date loanEndDate) {
this.loanEndDate = loanEndDate;
}
public Long getBankInstitutionId() {
return bankInstitutionId;
}
public void setBankInstitutionId(Long bankInstitutionId) {
this.bankInstitutionId = bankInstitutionId;
}
public String getBankInstitutionName() {
return bankInstitutionName;
}
public void setBankInstitutionName(String bankInstitutionName) {
this.bankInstitutionName = bankInstitutionName;
}
public String getApprovalStatus() {
return approvalStatus;
}
public void setApprovalStatus(String approvalStatus) {
this.approvalStatus = approvalStatus;
}
public Date getApprovalTime() {
return approvalTime;
}
public void setApprovalTime(Date approvalTime) {
this.approvalTime = approvalTime;
}
public String getApprovedBy() {
return approvedBy;
}
public void setApprovedBy(String approvedBy) {
this.approvedBy = approvedBy;
}
public Date getApplicationDate() {
return applicationDate;
}
public void setApplicationDate(Date applicationDate) {
this.applicationDate = applicationDate;
}
public String getValidationStatus() {
return validationStatus;
}
public void setValidationStatus(String validationStatus) {
this.validationStatus = validationStatus;
}
public Date getValidationTime() {
return validationTime;
}
public void setValidationTime(Date validationTime) {
this.validationTime = validationTime;
}
public String getValidationResult() {
return validationResult;
}
public void setValidationResult(String validationResult) {
this.validationResult = validationResult;
}
public String getFailureReason() {
return failureReason;
}
public void setFailureReason(String failureReason) {
this.failureReason = failureReason;
}
public Integer getValidationScore() {
return validationScore;
}
public void setValidationScore(Integer validationScore) {
this.validationScore = validationScore;
}
public String getRuleVersion() {
return ruleVersion;
}
public void setRuleVersion(String ruleVersion) {
this.ruleVersion = ruleVersion;
}
public String getCreditStatus() {
return creditStatus;
}
public void setCreditStatus(String creditStatus) {
this.creditStatus = creditStatus;
}
public Long getServicePeriodId() {
return servicePeriodId;
}
public void setServicePeriodId(Long servicePeriodId) {
this.servicePeriodId = servicePeriodId;
}
}