feat: 添加生产环境 Docker 配置和配置验证脚本

- 创建 docker-compose.prod.yml 生产环境配置
  - 添加资源限制(CPU、内存)
  - 添加健康检查配置
  - 优化日志配置
  - 添加网络隔离
- 创建 validate-config.ps1 和 validate-config.sh 配置验证脚本
  - 验证环境变量配置
  - 验证端口可用性
  - 验证依赖服务连接
  - 验证开发环境和 Docker
This commit is contained in:
WuYongJie 2025-12-22 18:00:55 +08:00
parent 6860ba010f
commit 9d58c6f707
3 changed files with 506 additions and 106 deletions

View File

@ -1,148 +1,140 @@
# ============================================
# 生产环境 Docker Compose 配置
# ============================================
# 使用方法:
# docker-compose -f docker-compose.prod.yml up -d
# ============================================
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
container_name: furniture3d-app
restart: unless-stopped
env_file:
- .env
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
minio:
condition: service_healthy
ports:
- "${WEB_PORT:-3001}:3000"
environment:
NODE_ENV: production
PORT: 3000
DATABASE_URL: postgresql://furniture:furniture123@postgres:5432/furniture_db?schema=public
S3_ENDPOINT: http://minio:9000
S3_PUBLIC_ENDPOINT: http://192.168.42.252:9002
S3_REGION: us-east-1
S3_ACCESS_KEY: minioadmin
S3_SECRET_KEY: minioadmin123
S3_BUCKET: furniture-3d-models
NEXT_TELEMETRY_DISABLED: "1"
JWT_SECRET: change-me-in-test
mem_limit: 2g
cpus: 2.0
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health?mode=simple"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
command: >
sh -c "
if [ -x ./node_modules/.bin/prisma ]; then ./node_modules/.bin/prisma db push || true; fi;
if [ -x ./node_modules/prisma/build/index.js ]; then node ./node_modules/prisma/build/index.js db push || true; fi;
node server.js
"
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# PostgreSQL 数据库
postgres:
image: postgres:15-alpine
container_name: furniture3d-postgres
restart: unless-stopped
restart: always
environment:
POSTGRES_USER: furniture
POSTGRES_PASSWORD: furniture123
POSTGRES_DB: furniture_db
POSTGRES_USER: ${DB_USER:-postgres}
POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres}
POSTGRES_DB: ${DB_NAME:-furniture3d}
# 性能优化参数
POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C"
ports:
- "5433:5432"
- "${DB_PORT:-5432}:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
mem_limit: 1g
cpus: 1.0
- ./backups/database:/backups
healthcheck:
test: ["CMD-SHELL", "pg_isready -U furniture -d furniture_db"]
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres} -d ${DB_NAME:-furniture3d}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
redis:
image: redis:7-alpine
container_name: furniture3d-redis
restart: unless-stopped
command: >
redis-server
--maxmemory 256mb
--maxmemory-policy allkeys-lru
ports:
- "6379:6379"
volumes:
- redis_data:/data
mem_limit: 512m
cpus: 0.5
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
max-size: "50m"
max-file: "5"
networks:
- furniture3d-network
# MinIO 对象存储
minio:
image: minio/minio:latest
container_name: furniture3d-minio
restart: unless-stopped
restart: always
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin123
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minioadmin}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-minioadmin}
# 生产环境建议启用 TLS
# MINIO_SERVER_URL: https://minio.yourdomain.com
ports:
- "9002:9000"
- "9003:9001"
- "${MINIO_API_PORT:-9000}:9000"
- "${MINIO_CONSOLE_PORT:-9001}:9001"
volumes:
- minio_data:/data
mem_limit: 512m
cpus: 0.5
- ./backups/files:/backups
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
start_period: 30s
deploy:
resources:
limits:
cpus: '1'
memory: 1G
reservations:
cpus: '0.25'
memory: 256M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
max-size: "50m"
max-file: "5"
networks:
- furniture3d-network
minio-setup:
image: minio/mc:latest
container_name: furniture3d-minio-setup
# Next.js 应用(可选,也可以单独部署)
app:
build:
context: .
dockerfile: Dockerfile
container_name: furniture3d-app
restart: always
environment:
NODE_ENV: production
DATABASE_URL: postgresql://${DB_USER:-postgres}:${DB_PASSWORD:-postgres}@postgres:5432/${DB_NAME:-furniture3d}
S3_ENDPOINT: http://minio:9000
S3_ACCESS_KEY: ${MINIO_ROOT_USER:-minioadmin}
S3_SECRET_KEY: ${MINIO_ROOT_PASSWORD:-minioadmin}
S3_BUCKET: ${S3_BUCKET:-furniture-3d-models}
JWT_SECRET: ${JWT_SECRET:-your-super-secret-jwt-key-change-in-production}
ports:
- "${APP_PORT:-3000}:3000"
depends_on:
postgres:
condition: service_healthy
minio:
condition: service_healthy
environment:
MC_HOST_minio: http://minioadmin:minioadmin123@minio:9000
entrypoint: ["sh", "-c"]
command: >
"mc alias set myminio http://minio:9000 minioadmin minioadmin123 && \
mc mb -p myminio/furniture-3d-models || true && \
mc anonymous set download myminio/furniture-3d-models || true && \
echo 'MinIO bucket ready' && sleep 1"
restart: "no"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health?mode=simple"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
resources:
limits:
cpus: '2'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "10"
networks:
- furniture3d-network
volumes:
postgres_data:
redis_data:
driver: local
minio_data:
driver: local
networks:
furniture3d-network:
driver: bridge

217
scripts/validate-config.ps1 Normal file
View File

@ -0,0 +1,217 @@
# ============================================
# 配置验证脚本 (PowerShell)
# ============================================
# 功能:
# - 验证环境变量配置
# - 验证端口可用性
# - 验证依赖服务连接
# 使用:
# .\scripts\validate-config.ps1
# ============================================
param(
[switch]$Verbose
)
$ErrorActionPreference = "Continue"
$script:HasErrors = $false
$script:HasWarnings = $false
function Write-Check {
param([string]$Name, [string]$Status, [string]$Message)
$icon = switch ($Status) {
"OK" { "✅" }
"WARN" { "⚠️" }
"ERROR" { "❌" }
default { "ℹ️" }
}
Write-Host " $icon $Name : $Message"
if ($Status -eq "ERROR") { $script:HasErrors = $true }
if ($Status -eq "WARN") { $script:HasWarnings = $true }
}
Write-Host ""
Write-Host "========================================"
Write-Host " 配置验证脚本"
Write-Host "========================================"
Write-Host ""
# 1. 检查环境变量文件
Write-Host "📋 检查环境变量..."
if (Test-Path ".env") {
Write-Check "环境变量文件" "OK" ".env 文件存在"
# 读取 .env 文件
$envContent = Get-Content ".env" -Raw
# 检查必需的环境变量
$requiredVars = @(
@{ Name = "DATABASE_URL"; Pattern = "DATABASE_URL=" }
)
# JWT_SECRET 或 NEXTAUTH_SECRET 至少需要一个
if ($envContent -match "JWT_SECRET=" -or $envContent -match "NEXTAUTH_SECRET=") {
Write-Check "JWT/Auth Secret" "OK" "已配置"
} else {
Write-Check "JWT/Auth Secret" "ERROR" "未配置 (需要 JWT_SECRET 或 NEXTAUTH_SECRET)"
}
foreach ($var in $requiredVars) {
if ($envContent -match $var.Pattern) {
Write-Check $var.Name "OK" "已配置"
} else {
Write-Check $var.Name "ERROR" "未配置"
}
}
# 检查可选但推荐的环境变量
$optionalVars = @(
@{ Name = "S3_ENDPOINT"; Pattern = "S3_ENDPOINT=" },
@{ Name = "S3_ACCESS_KEY"; Pattern = "S3_ACCESS_KEY=" },
@{ Name = "S3_SECRET_KEY"; Pattern = "S3_SECRET_KEY=" }
)
foreach ($var in $optionalVars) {
if ($envContent -match $var.Pattern) {
Write-Check $var.Name "OK" "已配置"
} else {
Write-Check $var.Name "WARN" "未配置(可选)"
}
}
} else {
Write-Check "环境变量文件" "ERROR" ".env 文件不存在"
}
Write-Host ""
# 2. 检查端口可用性
Write-Host "🔌 检查端口可用性..."
$ports = @(
@{ Port = 3000; Name = "Next.js 应用" },
@{ Port = 5432; Name = "PostgreSQL" },
@{ Port = 9000; Name = "MinIO API" },
@{ Port = 9001; Name = "MinIO Console" }
)
foreach ($p in $ports) {
$connection = Get-NetTCPConnection -LocalPort $p.Port -ErrorAction SilentlyContinue
if ($connection) {
$process = Get-Process -Id $connection.OwningProcess -ErrorAction SilentlyContinue
$processName = if ($process) { $process.ProcessName } else { "未知进程" }
Write-Check "$($p.Name) (端口 $($p.Port))" "OK" "已被 $processName 使用"
} else {
Write-Check "$($p.Name) (端口 $($p.Port))" "OK" "端口可用"
}
}
Write-Host ""
# 3. 检查依赖服务
Write-Host "🔗 检查依赖服务..."
# 检查 PostgreSQL
try {
$pgConnection = Test-NetConnection -ComputerName localhost -Port 5432 -WarningAction SilentlyContinue
if ($pgConnection.TcpTestSucceeded) {
Write-Check "PostgreSQL" "OK" "服务运行中"
} else {
Write-Check "PostgreSQL" "WARN" "服务未运行或无法连接"
}
} catch {
Write-Check "PostgreSQL" "WARN" "无法检测服务状态"
}
# 检查 MinIO
try {
$minioConnection = Test-NetConnection -ComputerName localhost -Port 9000 -WarningAction SilentlyContinue
if ($minioConnection.TcpTestSucceeded) {
Write-Check "MinIO" "OK" "服务运行中"
} else {
Write-Check "MinIO" "WARN" "服务未运行或无法连接"
}
} catch {
Write-Check "MinIO" "WARN" "无法检测服务状态"
}
Write-Host ""
# 4. 检查 Node.js 和 npm
Write-Host "📦 检查开发环境..."
try {
$nodeVersion = node --version 2>$null
if ($nodeVersion) {
Write-Check "Node.js" "OK" "版本 $nodeVersion"
} else {
Write-Check "Node.js" "ERROR" "未安装"
}
} catch {
Write-Check "Node.js" "ERROR" "未安装"
}
try {
$npmVersion = npm --version 2>$null
if ($npmVersion) {
Write-Check "npm" "OK" "版本 $npmVersion"
} else {
Write-Check "npm" "ERROR" "未安装"
}
} catch {
Write-Check "npm" "ERROR" "未安装"
}
# 检查 node_modules
if (Test-Path "node_modules") {
Write-Check "依赖包" "OK" "node_modules 存在"
} else {
Write-Check "依赖包" "WARN" "node_modules 不存在,请运行 npm install"
}
Write-Host ""
# 5. 检查 Docker(可选)
Write-Host "🐳 检查 Docker..."
try {
$dockerVersion = docker --version 2>$null
if ($dockerVersion) {
Write-Check "Docker" "OK" $dockerVersion
} else {
Write-Check "Docker" "WARN" "未安装(可选)"
}
} catch {
Write-Check "Docker" "WARN" "未安装(可选)"
}
try {
$composeVersion = docker-compose --version 2>$null
if ($composeVersion) {
Write-Check "Docker Compose" "OK" $composeVersion
} else {
Write-Check "Docker Compose" "WARN" "未安装(可选)"
}
} catch {
Write-Check "Docker Compose" "WARN" "未安装(可选)"
}
Write-Host ""
Write-Host "========================================"
if ($script:HasErrors) {
Write-Host " ❌ 配置验证失败,请修复上述错误"
Write-Host "========================================"
exit 1
} elseif ($script:HasWarnings) {
Write-Host " ⚠️ 配置验证通过,但有警告"
Write-Host "========================================"
exit 0
} else {
Write-Host " ✅ 配置验证通过"
Write-Host "========================================"
exit 0
}

191
scripts/validate-config.sh Normal file
View File

@ -0,0 +1,191 @@
#!/bin/bash
# ============================================
# 配置验证脚本 (Linux/Mac)
# ============================================
# 功能:
# - 验证环境变量配置
# - 验证端口可用性
# - 验证依赖服务连接
# 使用:
# ./scripts/validate-config.sh
# ============================================
HAS_ERRORS=false
HAS_WARNINGS=false
write_check() {
local name="$1"
local status="$2"
local message="$3"
case "$status" in
"OK") icon="✅" ;;
"WARN") icon="⚠️"; HAS_WARNINGS=true ;;
"ERROR") icon="❌"; HAS_ERRORS=true ;;
*) icon="ℹ️" ;;
esac
echo " $icon $name : $message"
}
echo ""
echo "========================================"
echo " 配置验证脚本"
echo "========================================"
echo ""
# 1. 检查环境变量文件
echo "📋 检查环境变量..."
if [ -f ".env" ]; then
write_check "环境变量文件" "OK" ".env 文件存在"
# 检查必需的环境变量
if grep -q "DATABASE_URL=" .env; then
write_check "DATABASE_URL" "OK" "已配置"
else
write_check "DATABASE_URL" "ERROR" "未配置"
fi
if grep -q "JWT_SECRET=" .env; then
write_check "JWT_SECRET" "OK" "已配置"
else
write_check "JWT_SECRET" "ERROR" "未配置"
fi
# 检查可选环境变量
if grep -q "S3_ENDPOINT=" .env; then
write_check "S3_ENDPOINT" "OK" "已配置"
else
write_check "S3_ENDPOINT" "WARN" "未配置(可选)"
fi
if grep -q "S3_ACCESS_KEY=" .env; then
write_check "S3_ACCESS_KEY" "OK" "已配置"
else
write_check "S3_ACCESS_KEY" "WARN" "未配置(可选)"
fi
else
write_check "环境变量文件" "ERROR" ".env 文件不存在"
fi
echo ""
# 2. 检查端口可用性
echo "🔌 检查端口可用性..."
check_port() {
local port="$1"
local name="$2"
if command -v lsof &> /dev/null; then
if lsof -i ":$port" &> /dev/null; then
process=$(lsof -i ":$port" | tail -1 | awk '{print $1}')
write_check "$name (端口 $port)" "OK" "已被 $process 使用"
else
write_check "$name (端口 $port)" "OK" "端口可用"
fi
elif command -v netstat &> /dev/null; then
if netstat -tuln | grep -q ":$port "; then
write_check "$name (端口 $port)" "OK" "端口已被使用"
else
write_check "$name (端口 $port)" "OK" "端口可用"
fi
else
write_check "$name (端口 $port)" "WARN" "无法检测端口状态"
fi
}
check_port 3000 "Next.js 应用"
check_port 5432 "PostgreSQL"
check_port 9000 "MinIO API"
check_port 9001 "MinIO Console"
echo ""
# 3. 检查依赖服务
echo "🔗 检查依赖服务..."
# 检查 PostgreSQL
if command -v pg_isready &> /dev/null; then
if pg_isready -h localhost -p 5432 &> /dev/null; then
write_check "PostgreSQL" "OK" "服务运行中"
else
write_check "PostgreSQL" "WARN" "服务未运行或无法连接"
fi
elif nc -z localhost 5432 2>/dev/null; then
write_check "PostgreSQL" "OK" "端口可访问"
else
write_check "PostgreSQL" "WARN" "服务未运行或无法连接"
fi
# 检查 MinIO
if curl -s http://localhost:9000/minio/health/live &> /dev/null; then
write_check "MinIO" "OK" "服务运行中"
elif nc -z localhost 9000 2>/dev/null; then
write_check "MinIO" "OK" "端口可访问"
else
write_check "MinIO" "WARN" "服务未运行或无法连接"
fi
echo ""
# 4. 检查开发环境
echo "📦 检查开发环境..."
if command -v node &> /dev/null; then
node_version=$(node --version)
write_check "Node.js" "OK" "版本 $node_version"
else
write_check "Node.js" "ERROR" "未安装"
fi
if command -v npm &> /dev/null; then
npm_version=$(npm --version)
write_check "npm" "OK" "版本 $npm_version"
else
write_check "npm" "ERROR" "未安装"
fi
if [ -d "node_modules" ]; then
write_check "依赖包" "OK" "node_modules 存在"
else
write_check "依赖包" "WARN" "node_modules 不存在,请运行 npm install"
fi
echo ""
# 5. 检查 Docker(可选)
echo "🐳 检查 Docker..."
if command -v docker &> /dev/null; then
docker_version=$(docker --version)
write_check "Docker" "OK" "$docker_version"
else
write_check "Docker" "WARN" "未安装(可选)"
fi
if command -v docker-compose &> /dev/null; then
compose_version=$(docker-compose --version)
write_check "Docker Compose" "OK" "$compose_version"
else
write_check "Docker Compose" "WARN" "未安装(可选)"
fi
echo ""
echo "========================================"
if [ "$HAS_ERRORS" = true ]; then
echo " ❌ 配置验证失败,请修复上述错误"
echo "========================================"
exit 1
elif [ "$HAS_WARNINGS" = true ]; then
echo " ⚠️ 配置验证通过,但有警告"
echo "========================================"
exit 0
else
echo " ✅ 配置验证通过"
echo "========================================"
exit 0
fi