Some checks failed
Deploy / deploy (push) Has been cancelled
Full-stack web application for Telegram management - Frontend: Vue 3 + Vben Admin - Backend: NestJS - Features: User management, group broadcast, statistics 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2805 lines
56 KiB
Markdown
2805 lines
56 KiB
Markdown
# Telegram 管理系统部署指南
|
||
|
||
> **版本**: v2.0.0
|
||
> **更新时间**: 2024-01-20
|
||
> **维护者**: 开发团队
|
||
|
||
## 📋 文档目录
|
||
|
||
- [部署概述](#部署概述)
|
||
- [环境要求](#环境要求)
|
||
- [快速部署](#快速部署)
|
||
- [开发环境部署](#开发环境部署)
|
||
- [生产环境部署](#生产环境部署)
|
||
- [Docker部署](#docker部署)
|
||
- [Kubernetes部署](#kubernetes部署)
|
||
- [数据库配置](#数据库配置)
|
||
- [环境变量配置](#环境变量配置)
|
||
- [SSL证书配置](#ssl证书配置)
|
||
- [监控与日志](#监控与日志)
|
||
- [备份与恢复](#备份与恢复)
|
||
- [故障排除](#故障排除)
|
||
|
||
---
|
||
|
||
## 🏗️ 部署概述
|
||
|
||
### 系统架构
|
||
|
||
Telegram管理系统采用前后端分离架构,包含以下组件:
|
||
|
||
- **前端应用**: Vue 3 + Vben Admin
|
||
- **后端API**: Node.js + Express
|
||
- **数据库**: MySQL + Redis + MongoDB
|
||
- **反向代理**: Nginx
|
||
- **实时通信**: WebSocket
|
||
|
||
### 部署方式
|
||
|
||
支持多种部署方式:
|
||
|
||
1. **Docker Compose**: 快速本地部署和开发
|
||
2. **Kubernetes**: 生产环境容器编排
|
||
3. **传统部署**: 直接在服务器上安装
|
||
4. **云原生部署**: 支持AWS、阿里云等云平台
|
||
|
||
---
|
||
|
||
## 💻 环境要求
|
||
|
||
### 硬件要求
|
||
|
||
| 环境 | CPU | 内存 | 存储 | 网络 |
|
||
| ---------- | ---- | ---- | ----- | ------- |
|
||
| 开发环境 | 2核 | 4GB | 20GB | 10Mbps |
|
||
| 测试环境 | 4核 | 8GB | 100GB | 50Mbps |
|
||
| 生产环境 | 8核 | 16GB | 500GB | 100Mbps |
|
||
| 高可用环境 | 16核 | 32GB | 1TB | 1Gbps |
|
||
|
||
### 软件要求
|
||
|
||
#### 基础软件
|
||
|
||
| 软件 | 版本要求 | 说明 |
|
||
| -------------- | -------- | ---------- |
|
||
| Node.js | ≥18.0.0 | 运行时环境 |
|
||
| npm/pnpm | ≥8.0.0 | 包管理器 |
|
||
| Git | ≥2.30.0 | 版本控制 |
|
||
| Docker | ≥20.10.0 | 容器运行时 |
|
||
| Docker Compose | ≥2.0.0 | 容器编排 |
|
||
|
||
#### 数据库
|
||
|
||
| 数据库 | 版本要求 | 用途 |
|
||
| ------- | -------- | ---------- |
|
||
| MySQL | ≥8.0.0 | 主数据存储 |
|
||
| Redis | ≥7.0.0 | 缓存和会话 |
|
||
| MongoDB | ≥6.0.0 | 日志存储 |
|
||
|
||
#### Web服务器
|
||
|
||
| 服务器 | 版本要求 | 用途 |
|
||
| ------ | -------- | ------------- |
|
||
| Nginx | ≥1.20.0 | 反向代理 |
|
||
| Apache | ≥2.4.0 | 备选web服务器 |
|
||
|
||
### 网络要求
|
||
|
||
- **入站端口**: 80 (HTTP), 443 (HTTPS), 3000 (API)
|
||
- **出站访问**: 访问Telegram API、邮件服务、短信服务
|
||
- **内部通信**: 各服务间网络连通性
|
||
|
||
---
|
||
|
||
## ⚡ 快速部署
|
||
|
||
### 使用Docker Compose(推荐)
|
||
|
||
1. **克隆项目**
|
||
|
||
```bash
|
||
git clone https://github.com/your-org/telegram-management-system.git
|
||
cd telegram-management-system
|
||
```
|
||
|
||
2. **配置环境变量**
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
# 编辑 .env 文件,配置必要的环境变量
|
||
```
|
||
|
||
3. **启动所有服务**
|
||
|
||
```bash
|
||
docker-compose up -d
|
||
```
|
||
|
||
4. **初始化数据库**
|
||
|
||
```bash
|
||
docker-compose exec backend npm run db:migrate
|
||
docker-compose exec backend npm run db:seed
|
||
```
|
||
|
||
5. **访问系统**
|
||
|
||
- 前端地址: http://localhost
|
||
- API地址: http://localhost:3000
|
||
- 默认账号: admin / 111111
|
||
|
||
### 一键安装脚本
|
||
|
||
提供快速安装脚本:
|
||
|
||
```bash
|
||
# 下载并执行安装脚本
|
||
curl -fsSL https://raw.githubusercontent.com/your-org/telegram-management-system/main/scripts/install.sh | bash
|
||
|
||
# 或者下载后执行
|
||
wget https://raw.githubusercontent.com/your-org/telegram-management-system/main/scripts/install.sh
|
||
chmod +x install.sh
|
||
./install.sh
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 开发环境部署
|
||
|
||
### 前端开发环境
|
||
|
||
1. **安装依赖**
|
||
|
||
```bash
|
||
cd frontend-vben/apps/web-antd
|
||
pnpm install
|
||
```
|
||
|
||
2. **配置开发环境**
|
||
|
||
```bash
|
||
# 复制环境配置文件
|
||
cp .env.development.example .env.development
|
||
|
||
# 编辑配置文件
|
||
nano .env.development
|
||
```
|
||
|
||
```env
|
||
# .env.development
|
||
VITE_API_URL=http://localhost:3001/api/v1
|
||
VITE_WS_URL=ws://localhost:3001/ws
|
||
VITE_APP_TITLE=Telegram管理系统(开发)
|
||
```
|
||
|
||
3. **启动开发服务器**
|
||
|
||
```bash
|
||
pnpm dev
|
||
```
|
||
|
||
### 后端开发环境
|
||
|
||
1. **安装依赖**
|
||
|
||
```bash
|
||
cd backend
|
||
npm install
|
||
```
|
||
|
||
2. **配置数据库**
|
||
|
||
```bash
|
||
# 启动MySQL (使用Docker)
|
||
docker run -d --name mysql-dev \
|
||
-e MYSQL_ROOT_PASSWORD=root123 \
|
||
-e MYSQL_DATABASE=telegram_system \
|
||
-e MYSQL_USER=app_user \
|
||
-e MYSQL_PASSWORD=app_password \
|
||
-p 3306:3306 \
|
||
mysql:8.0
|
||
|
||
# 启动Redis
|
||
docker run -d --name redis-dev \
|
||
-p 6379:6379 \
|
||
redis:7-alpine
|
||
|
||
# 启动MongoDB
|
||
docker run -d --name mongodb-dev \
|
||
-p 27017:27017 \
|
||
mongo:6.0
|
||
```
|
||
|
||
3. **配置环境变量**
|
||
|
||
```bash
|
||
cp .env.example .env.development
|
||
```
|
||
|
||
```env
|
||
# .env.development
|
||
NODE_ENV=development
|
||
PORT=3001
|
||
|
||
# 数据库配置
|
||
DB_HOST=localhost
|
||
DB_PORT=3306
|
||
DB_NAME=telegram_system
|
||
DB_USER=app_user
|
||
DB_PASSWORD=app_password
|
||
|
||
# Redis配置
|
||
REDIS_HOST=localhost
|
||
REDIS_PORT=6379
|
||
REDIS_PASSWORD=
|
||
|
||
# MongoDB配置
|
||
MONGODB_URI=mongodb://localhost:27017/telegram_system_logs
|
||
|
||
# JWT配置
|
||
JWT_SECRET=your-jwt-secret-key
|
||
JWT_EXPIRE=7d
|
||
REFRESH_TOKEN_EXPIRE=30d
|
||
|
||
# Telegram配置
|
||
TELEGRAM_BOT_TOKEN=your-telegram-bot-token
|
||
TELEGRAM_WEBHOOK_URL=https://your-domain.com/webhook/telegram
|
||
```
|
||
|
||
4. **初始化数据库**
|
||
|
||
```bash
|
||
# 运行数据库迁移
|
||
npm run db:migrate
|
||
|
||
# 填充初始数据
|
||
npm run db:seed
|
||
```
|
||
|
||
5. **启动开发服务器**
|
||
|
||
```bash
|
||
npm run dev
|
||
```
|
||
|
||
### 开发环境验证
|
||
|
||
验证开发环境是否正常:
|
||
|
||
```bash
|
||
# 检查前端
|
||
curl http://localhost:5173
|
||
|
||
# 检查后端API
|
||
curl http://localhost:3001/api/v1/health
|
||
|
||
# 检查数据库连接
|
||
npm run db:check
|
||
```
|
||
|
||
---
|
||
|
||
## 🏭 生产环境部署
|
||
|
||
### 服务器准备
|
||
|
||
1. **系统要求**
|
||
|
||
```bash
|
||
# Ubuntu 20.04 LTS 或更高版本
|
||
lsb_release -a
|
||
|
||
# 安装基础软件
|
||
sudo apt update
|
||
sudo apt install -y curl wget git nginx certbot
|
||
```
|
||
|
||
2. **安装Node.js**
|
||
|
||
```bash
|
||
# 安装Node.js 18.x
|
||
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
|
||
sudo apt-get install -y nodejs
|
||
|
||
# 验证安装
|
||
node --version
|
||
npm --version
|
||
```
|
||
|
||
3. **安装Docker**
|
||
|
||
```bash
|
||
# 安装Docker
|
||
curl -fsSL https://get.docker.com -o get-docker.sh
|
||
sudo sh get-docker.sh
|
||
|
||
# 安装Docker Compose
|
||
sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||
sudo chmod +x /usr/local/bin/docker-compose
|
||
|
||
# 验证安装
|
||
docker --version
|
||
docker-compose --version
|
||
```
|
||
|
||
### 应用部署
|
||
|
||
1. **克隆代码**
|
||
|
||
```bash
|
||
sudo mkdir -p /opt/telegram-system
|
||
sudo chown $USER:$USER /opt/telegram-system
|
||
cd /opt/telegram-system
|
||
|
||
git clone https://github.com/your-org/telegram-management-system.git .
|
||
```
|
||
|
||
2. **构建前端**
|
||
|
||
```bash
|
||
cd frontend-vben/apps/web-antd
|
||
|
||
# 安装pnpm
|
||
npm install -g pnpm
|
||
|
||
# 安装依赖
|
||
pnpm install
|
||
|
||
# 构建生产版本
|
||
pnpm build
|
||
```
|
||
|
||
3. **配置生产环境变量**
|
||
|
||
```bash
|
||
cp .env.example .env.production
|
||
```
|
||
|
||
```env
|
||
# .env.production
|
||
NODE_ENV=production
|
||
PORT=3001
|
||
|
||
# 数据库配置
|
||
DB_HOST=mysql
|
||
DB_PORT=3306
|
||
DB_NAME=telegram_system
|
||
DB_USER=app_user
|
||
DB_PASSWORD=your-secure-password
|
||
|
||
# Redis配置
|
||
REDIS_HOST=redis
|
||
REDIS_PORT=6379
|
||
REDIS_PASSWORD=your-redis-password
|
||
|
||
# MongoDB配置
|
||
MONGODB_URI=mongodb://mongodb:27017/telegram_system_logs
|
||
|
||
# JWT配置
|
||
JWT_SECRET=your-very-secure-jwt-secret-key
|
||
JWT_EXPIRE=7d
|
||
REFRESH_TOKEN_EXPIRE=30d
|
||
|
||
# Telegram配置
|
||
TELEGRAM_BOT_TOKEN=your-telegram-bot-token
|
||
TELEGRAM_WEBHOOK_URL=https://yourdomain.com/webhook/telegram
|
||
|
||
# 安全配置
|
||
CORS_ORIGINS=https://yourdomain.com
|
||
RATE_LIMIT_MAX=100
|
||
RATE_LIMIT_WINDOW=60000
|
||
|
||
# 邮件配置
|
||
SMTP_HOST=smtp.gmail.com
|
||
SMTP_PORT=587
|
||
SMTP_USER=your-email@gmail.com
|
||
SMTP_PASS=your-app-password
|
||
|
||
# 文件存储
|
||
FILE_STORAGE_TYPE=local
|
||
FILE_STORAGE_PATH=/app/uploads
|
||
MAX_FILE_SIZE=10485760
|
||
|
||
# 日志配置
|
||
LOG_LEVEL=info
|
||
LOG_FILE_PATH=/app/logs/app.log
|
||
```
|
||
|
||
4. **配置Docker Compose**
|
||
|
||
```yaml
|
||
# docker-compose.prod.yml
|
||
version: '3.8'
|
||
|
||
services:
|
||
frontend:
|
||
build:
|
||
context: ./frontend-vben/apps/web-antd
|
||
dockerfile: Dockerfile.prod
|
||
container_name: telegram-frontend
|
||
restart: unless-stopped
|
||
volumes:
|
||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||
- ./ssl:/etc/nginx/ssl:ro
|
||
ports:
|
||
- '80:80'
|
||
- '443:443'
|
||
depends_on:
|
||
- backend
|
||
networks:
|
||
- telegram-network
|
||
|
||
backend:
|
||
build:
|
||
context: ./backend
|
||
dockerfile: Dockerfile.prod
|
||
container_name: telegram-backend
|
||
restart: unless-stopped
|
||
env_file:
|
||
- .env.production
|
||
volumes:
|
||
- ./uploads:/app/uploads
|
||
- ./logs:/app/logs
|
||
ports:
|
||
- '3001:3001'
|
||
depends_on:
|
||
- mysql
|
||
- redis
|
||
- mongodb
|
||
networks:
|
||
- telegram-network
|
||
healthcheck:
|
||
test: ['CMD', 'curl', '-f', 'http://localhost:3001/health']
|
||
interval: 30s
|
||
timeout: 10s
|
||
retries: 3
|
||
|
||
mysql:
|
||
image: mysql:8.0
|
||
container_name: telegram-mysql
|
||
restart: unless-stopped
|
||
environment:
|
||
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
|
||
MYSQL_DATABASE: ${DB_NAME}
|
||
MYSQL_USER: ${DB_USER}
|
||
MYSQL_PASSWORD: ${DB_PASSWORD}
|
||
volumes:
|
||
- mysql_data:/var/lib/mysql
|
||
- ./sql/init:/docker-entrypoint-initdb.d
|
||
ports:
|
||
- '3306:3306'
|
||
networks:
|
||
- telegram-network
|
||
command: --default-authentication-plugin=mysql_native_password
|
||
|
||
redis:
|
||
image: redis:7-alpine
|
||
container_name: telegram-redis
|
||
restart: unless-stopped
|
||
command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes
|
||
volumes:
|
||
- redis_data:/data
|
||
ports:
|
||
- '6379:6379'
|
||
networks:
|
||
- telegram-network
|
||
|
||
mongodb:
|
||
image: mongo:6.0
|
||
container_name: telegram-mongodb
|
||
restart: unless-stopped
|
||
environment:
|
||
MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USER}
|
||
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD}
|
||
volumes:
|
||
- mongodb_data:/data/db
|
||
ports:
|
||
- '27017:27017'
|
||
networks:
|
||
- telegram-network
|
||
|
||
volumes:
|
||
mysql_data:
|
||
driver: local
|
||
redis_data:
|
||
driver: local
|
||
mongodb_data:
|
||
driver: local
|
||
|
||
networks:
|
||
telegram-network:
|
||
driver: bridge
|
||
```
|
||
|
||
5. **启动生产服务**
|
||
|
||
```bash
|
||
# 构建并启动所有服务
|
||
docker-compose -f docker-compose.prod.yml up -d
|
||
|
||
# 检查服务状态
|
||
docker-compose -f docker-compose.prod.yml ps
|
||
|
||
# 查看日志
|
||
docker-compose -f docker-compose.prod.yml logs -f
|
||
```
|
||
|
||
---
|
||
|
||
## 🐳 Docker部署
|
||
|
||
### Dockerfile配置
|
||
|
||
#### 前端Dockerfile
|
||
|
||
```dockerfile
|
||
# frontend-vben/apps/web-antd/Dockerfile.prod
|
||
FROM node:18-alpine AS builder
|
||
|
||
WORKDIR /app
|
||
|
||
# 复制package文件
|
||
COPY package*.json ./
|
||
COPY pnpm-lock.yaml ./
|
||
|
||
# 安装pnpm和依赖
|
||
RUN npm install -g pnpm
|
||
RUN pnpm install --frozen-lockfile
|
||
|
||
# 复制源码
|
||
COPY . .
|
||
|
||
# 构建应用
|
||
RUN pnpm build
|
||
|
||
# 生产阶段
|
||
FROM nginx:alpine
|
||
|
||
# 复制构建产物
|
||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||
|
||
# 复制nginx配置
|
||
COPY nginx.conf /etc/nginx/nginx.conf
|
||
|
||
# 创建必要目录
|
||
RUN mkdir -p /var/log/nginx
|
||
|
||
# 暴露端口
|
||
EXPOSE 80 443
|
||
|
||
# 健康检查
|
||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||
CMD curl -f http://localhost/ || exit 1
|
||
|
||
CMD ["nginx", "-g", "daemon off;"]
|
||
```
|
||
|
||
#### 后端Dockerfile
|
||
|
||
```dockerfile
|
||
# backend/Dockerfile.prod
|
||
FROM node:18-alpine
|
||
|
||
# 设置工作目录
|
||
WORKDIR /app
|
||
|
||
# 创建非root用户
|
||
RUN addgroup -g 1001 -S nodejs
|
||
RUN adduser -S nodejs -u 1001
|
||
|
||
# 复制package文件
|
||
COPY package*.json ./
|
||
|
||
# 安装生产依赖
|
||
RUN npm install --only=production && npm cache clean --force
|
||
|
||
# 复制源码
|
||
COPY . .
|
||
|
||
# 创建必要目录
|
||
RUN mkdir -p uploads logs
|
||
RUN chown -R nodejs:nodejs /app
|
||
|
||
# 切换到非root用户
|
||
USER nodejs
|
||
|
||
# 暴露端口
|
||
EXPOSE 3001
|
||
|
||
# 健康检查
|
||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||
CMD curl -f http://localhost:3001/health || exit 1
|
||
|
||
# 启动应用
|
||
CMD ["node", "server.js"]
|
||
```
|
||
|
||
### Docker构建优化
|
||
|
||
1. **多阶段构建**
|
||
|
||
```dockerfile
|
||
# 使用多阶段构建减少镜像大小
|
||
FROM node:18-alpine AS dependencies
|
||
WORKDIR /app
|
||
COPY package*.json ./
|
||
RUN npm ci --only=production
|
||
|
||
FROM node:18-alpine AS build
|
||
WORKDIR /app
|
||
COPY package*.json ./
|
||
RUN npm ci
|
||
COPY . .
|
||
RUN npm run build
|
||
|
||
FROM node:18-alpine AS runtime
|
||
WORKDIR /app
|
||
COPY --from=dependencies /app/node_modules ./node_modules
|
||
COPY --from=build /app/dist ./dist
|
||
COPY package*.json ./
|
||
EXPOSE 3001
|
||
CMD ["node", "dist/server.js"]
|
||
```
|
||
|
||
2. **.dockerignore文件**
|
||
|
||
```dockerignore
|
||
# .dockerignore
|
||
node_modules
|
||
npm-debug.log
|
||
.git
|
||
.gitignore
|
||
README.md
|
||
.env.development
|
||
.env.local
|
||
coverage
|
||
.coverage
|
||
.nyc_output
|
||
.DS_Store
|
||
*.log
|
||
logs
|
||
```
|
||
|
||
### Docker网络配置
|
||
|
||
```bash
|
||
# 创建自定义网络
|
||
docker network create telegram-network
|
||
|
||
# 运行数据库服务
|
||
docker run -d --name mysql \
|
||
--network telegram-network \
|
||
-e MYSQL_ROOT_PASSWORD=root123 \
|
||
-e MYSQL_DATABASE=telegram_system \
|
||
-v mysql_data:/var/lib/mysql \
|
||
mysql:8.0
|
||
|
||
# 运行Redis
|
||
docker run -d --name redis \
|
||
--network telegram-network \
|
||
-v redis_data:/data \
|
||
redis:7-alpine
|
||
|
||
# 运行应用
|
||
docker run -d --name telegram-backend \
|
||
--network telegram-network \
|
||
-p 3001:3001 \
|
||
-e DB_HOST=mysql \
|
||
-e REDIS_HOST=redis \
|
||
telegram-system/backend:latest
|
||
```
|
||
|
||
---
|
||
|
||
## ☸️ Kubernetes部署
|
||
|
||
### 命名空间配置
|
||
|
||
```yaml
|
||
# k8s/namespace.yaml
|
||
apiVersion: v1
|
||
kind: Namespace
|
||
metadata:
|
||
name: telegram-system
|
||
labels:
|
||
name: telegram-system
|
||
```
|
||
|
||
### ConfigMap配置
|
||
|
||
```yaml
|
||
# k8s/configmap.yaml
|
||
apiVersion: v1
|
||
kind: ConfigMap
|
||
metadata:
|
||
name: telegram-config
|
||
namespace: telegram-system
|
||
data:
|
||
NODE_ENV: 'production'
|
||
DB_HOST: 'mysql-service'
|
||
DB_PORT: '3306'
|
||
DB_NAME: 'telegram_system'
|
||
REDIS_HOST: 'redis-service'
|
||
REDIS_PORT: '6379'
|
||
MONGODB_URI: 'mongodb://mongodb-service:27017/telegram_system_logs'
|
||
LOG_LEVEL: 'info'
|
||
```
|
||
|
||
### Secret配置
|
||
|
||
```yaml
|
||
# k8s/secret.yaml
|
||
apiVersion: v1
|
||
kind: Secret
|
||
metadata:
|
||
name: telegram-secret
|
||
namespace: telegram-system
|
||
type: Opaque
|
||
data:
|
||
DB_PASSWORD: <base64-encoded-password>
|
||
REDIS_PASSWORD: <base64-encoded-password>
|
||
JWT_SECRET: <base64-encoded-jwt-secret>
|
||
TELEGRAM_BOT_TOKEN: <base64-encoded-bot-token>
|
||
```
|
||
|
||
### MySQL部署
|
||
|
||
```yaml
|
||
# k8s/mysql-deployment.yaml
|
||
apiVersion: apps/v1
|
||
kind: Deployment
|
||
metadata:
|
||
name: mysql
|
||
namespace: telegram-system
|
||
spec:
|
||
replicas: 1
|
||
selector:
|
||
matchLabels:
|
||
app: mysql
|
||
template:
|
||
metadata:
|
||
labels:
|
||
app: mysql
|
||
spec:
|
||
containers:
|
||
- name: mysql
|
||
image: mysql:8.0
|
||
ports:
|
||
- containerPort: 3306
|
||
env:
|
||
- name: MYSQL_ROOT_PASSWORD
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: telegram-secret
|
||
key: DB_PASSWORD
|
||
- name: MYSQL_DATABASE
|
||
valueFrom:
|
||
configMapKeyRef:
|
||
name: telegram-config
|
||
key: DB_NAME
|
||
volumeMounts:
|
||
- name: mysql-storage
|
||
mountPath: /var/lib/mysql
|
||
resources:
|
||
requests:
|
||
memory: '1Gi'
|
||
cpu: '500m'
|
||
limits:
|
||
memory: '2Gi'
|
||
cpu: '1000m'
|
||
volumes:
|
||
- name: mysql-storage
|
||
persistentVolumeClaim:
|
||
claimName: mysql-pvc
|
||
|
||
---
|
||
apiVersion: v1
|
||
kind: Service
|
||
metadata:
|
||
name: mysql-service
|
||
namespace: telegram-system
|
||
spec:
|
||
selector:
|
||
app: mysql
|
||
ports:
|
||
- port: 3306
|
||
targetPort: 3306
|
||
type: ClusterIP
|
||
|
||
---
|
||
apiVersion: v1
|
||
kind: PersistentVolumeClaim
|
||
metadata:
|
||
name: mysql-pvc
|
||
namespace: telegram-system
|
||
spec:
|
||
accessModes:
|
||
- ReadWriteOnce
|
||
resources:
|
||
requests:
|
||
storage: 10Gi
|
||
```
|
||
|
||
### Redis部署
|
||
|
||
```yaml
|
||
# k8s/redis-deployment.yaml
|
||
apiVersion: apps/v1
|
||
kind: Deployment
|
||
metadata:
|
||
name: redis
|
||
namespace: telegram-system
|
||
spec:
|
||
replicas: 1
|
||
selector:
|
||
matchLabels:
|
||
app: redis
|
||
template:
|
||
metadata:
|
||
labels:
|
||
app: redis
|
||
spec:
|
||
containers:
|
||
- name: redis
|
||
image: redis:7-alpine
|
||
ports:
|
||
- containerPort: 6379
|
||
command:
|
||
- redis-server
|
||
- --requirepass
|
||
- $(REDIS_PASSWORD)
|
||
- --appendonly
|
||
- 'yes'
|
||
env:
|
||
- name: REDIS_PASSWORD
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: telegram-secret
|
||
key: REDIS_PASSWORD
|
||
volumeMounts:
|
||
- name: redis-storage
|
||
mountPath: /data
|
||
resources:
|
||
requests:
|
||
memory: '256Mi'
|
||
cpu: '250m'
|
||
limits:
|
||
memory: '512Mi'
|
||
cpu: '500m'
|
||
volumes:
|
||
- name: redis-storage
|
||
persistentVolumeClaim:
|
||
claimName: redis-pvc
|
||
|
||
---
|
||
apiVersion: v1
|
||
kind: Service
|
||
metadata:
|
||
name: redis-service
|
||
namespace: telegram-system
|
||
spec:
|
||
selector:
|
||
app: redis
|
||
ports:
|
||
- port: 6379
|
||
targetPort: 6379
|
||
type: ClusterIP
|
||
|
||
---
|
||
apiVersion: v1
|
||
kind: PersistentVolumeClaim
|
||
metadata:
|
||
name: redis-pvc
|
||
namespace: telegram-system
|
||
spec:
|
||
accessModes:
|
||
- ReadWriteOnce
|
||
resources:
|
||
requests:
|
||
storage: 1Gi
|
||
```
|
||
|
||
### 后端应用部署
|
||
|
||
```yaml
|
||
# k8s/backend-deployment.yaml
|
||
apiVersion: apps/v1
|
||
kind: Deployment
|
||
metadata:
|
||
name: backend
|
||
namespace: telegram-system
|
||
spec:
|
||
replicas: 3
|
||
selector:
|
||
matchLabels:
|
||
app: backend
|
||
template:
|
||
metadata:
|
||
labels:
|
||
app: backend
|
||
spec:
|
||
containers:
|
||
- name: backend
|
||
image: telegram-system/backend:latest
|
||
ports:
|
||
- containerPort: 3001
|
||
envFrom:
|
||
- configMapRef:
|
||
name: telegram-config
|
||
- secretRef:
|
||
name: telegram-secret
|
||
volumeMounts:
|
||
- name: uploads-storage
|
||
mountPath: /app/uploads
|
||
- name: logs-storage
|
||
mountPath: /app/logs
|
||
livenessProbe:
|
||
httpGet:
|
||
path: /health
|
||
port: 3001
|
||
initialDelaySeconds: 30
|
||
periodSeconds: 10
|
||
readinessProbe:
|
||
httpGet:
|
||
path: /ready
|
||
port: 3001
|
||
initialDelaySeconds: 5
|
||
periodSeconds: 5
|
||
resources:
|
||
requests:
|
||
memory: '512Mi'
|
||
cpu: '250m'
|
||
limits:
|
||
memory: '1Gi'
|
||
cpu: '500m'
|
||
volumes:
|
||
- name: uploads-storage
|
||
persistentVolumeClaim:
|
||
claimName: uploads-pvc
|
||
- name: logs-storage
|
||
persistentVolumeClaim:
|
||
claimName: logs-pvc
|
||
|
||
---
|
||
apiVersion: v1
|
||
kind: Service
|
||
metadata:
|
||
name: backend-service
|
||
namespace: telegram-system
|
||
spec:
|
||
selector:
|
||
app: backend
|
||
ports:
|
||
- port: 3001
|
||
targetPort: 3001
|
||
type: ClusterIP
|
||
|
||
---
|
||
apiVersion: v1
|
||
kind: PersistentVolumeClaim
|
||
metadata:
|
||
name: uploads-pvc
|
||
namespace: telegram-system
|
||
spec:
|
||
accessModes:
|
||
- ReadWriteMany
|
||
resources:
|
||
requests:
|
||
storage: 5Gi
|
||
|
||
---
|
||
apiVersion: v1
|
||
kind: PersistentVolumeClaim
|
||
metadata:
|
||
name: logs-pvc
|
||
namespace: telegram-system
|
||
spec:
|
||
accessModes:
|
||
- ReadWriteMany
|
||
resources:
|
||
requests:
|
||
storage: 2Gi
|
||
```
|
||
|
||
### 前端应用部署
|
||
|
||
```yaml
|
||
# k8s/frontend-deployment.yaml
|
||
apiVersion: apps/v1
|
||
kind: Deployment
|
||
metadata:
|
||
name: frontend
|
||
namespace: telegram-system
|
||
spec:
|
||
replicas: 3
|
||
selector:
|
||
matchLabels:
|
||
app: frontend
|
||
template:
|
||
metadata:
|
||
labels:
|
||
app: frontend
|
||
spec:
|
||
containers:
|
||
- name: frontend
|
||
image: telegram-system/frontend:latest
|
||
ports:
|
||
- containerPort: 80
|
||
resources:
|
||
requests:
|
||
memory: '128Mi'
|
||
cpu: '100m'
|
||
limits:
|
||
memory: '256Mi'
|
||
cpu: '200m'
|
||
|
||
---
|
||
apiVersion: v1
|
||
kind: Service
|
||
metadata:
|
||
name: frontend-service
|
||
namespace: telegram-system
|
||
spec:
|
||
selector:
|
||
app: frontend
|
||
ports:
|
||
- port: 80
|
||
targetPort: 80
|
||
type: LoadBalancer
|
||
```
|
||
|
||
### Ingress配置
|
||
|
||
```yaml
|
||
# k8s/ingress.yaml
|
||
apiVersion: networking.k8s.io/v1
|
||
kind: Ingress
|
||
metadata:
|
||
name: telegram-ingress
|
||
namespace: telegram-system
|
||
annotations:
|
||
kubernetes.io/ingress.class: nginx
|
||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||
nginx.ingress.kubernetes.io/ssl-redirect: 'true'
|
||
nginx.ingress.kubernetes.io/proxy-body-size: '50m'
|
||
spec:
|
||
tls:
|
||
- hosts:
|
||
- yourdomain.com
|
||
- api.yourdomain.com
|
||
secretName: telegram-tls
|
||
rules:
|
||
- host: yourdomain.com
|
||
http:
|
||
paths:
|
||
- path: /
|
||
pathType: Prefix
|
||
backend:
|
||
service:
|
||
name: frontend-service
|
||
port:
|
||
number: 80
|
||
- host: api.yourdomain.com
|
||
http:
|
||
paths:
|
||
- path: /
|
||
pathType: Prefix
|
||
backend:
|
||
service:
|
||
name: backend-service
|
||
port:
|
||
number: 3001
|
||
```
|
||
|
||
### 部署命令
|
||
|
||
```bash
|
||
# 创建命名空间
|
||
kubectl apply -f k8s/namespace.yaml
|
||
|
||
# 创建配置
|
||
kubectl apply -f k8s/configmap.yaml
|
||
kubectl apply -f k8s/secret.yaml
|
||
|
||
# 部署数据库
|
||
kubectl apply -f k8s/mysql-deployment.yaml
|
||
kubectl apply -f k8s/redis-deployment.yaml
|
||
|
||
# 等待数据库就绪
|
||
kubectl wait --for=condition=ready pod -l app=mysql -n telegram-system --timeout=300s
|
||
kubectl wait --for=condition=ready pod -l app=redis -n telegram-system --timeout=300s
|
||
|
||
# 部署应用
|
||
kubectl apply -f k8s/backend-deployment.yaml
|
||
kubectl apply -f k8s/frontend-deployment.yaml
|
||
|
||
# 配置Ingress
|
||
kubectl apply -f k8s/ingress.yaml
|
||
|
||
# 检查部署状态
|
||
kubectl get pods -n telegram-system
|
||
kubectl get services -n telegram-system
|
||
kubectl get ingress -n telegram-system
|
||
```
|
||
|
||
---
|
||
|
||
## 🗄️ 数据库配置
|
||
|
||
### MySQL配置
|
||
|
||
1. **创建数据库和用户**
|
||
|
||
```sql
|
||
-- 连接到MySQL
|
||
mysql -u root -p
|
||
|
||
-- 创建数据库
|
||
CREATE DATABASE telegram_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||
|
||
-- 创建用户
|
||
CREATE USER 'app_user'@'%' IDENTIFIED BY 'your_secure_password';
|
||
|
||
-- 授权
|
||
GRANT ALL PRIVILEGES ON telegram_system.* TO 'app_user'@'%';
|
||
FLUSH PRIVILEGES;
|
||
|
||
-- 验证
|
||
SHOW DATABASES;
|
||
SELECT User, Host FROM mysql.user WHERE User = 'app_user';
|
||
```
|
||
|
||
2. **MySQL配置优化**
|
||
|
||
```ini
|
||
# /etc/mysql/mysql.conf.d/mysqld.cnf
|
||
[mysqld]
|
||
# 基础配置
|
||
port = 3306
|
||
bind-address = 0.0.0.0
|
||
socket = /var/run/mysqld/mysqld.sock
|
||
|
||
# 字符集配置
|
||
character-set-server = utf8mb4
|
||
collation-server = utf8mb4_unicode_ci
|
||
|
||
# 内存配置
|
||
innodb_buffer_pool_size = 1G
|
||
innodb_log_file_size = 256M
|
||
key_buffer_size = 128M
|
||
max_connections = 500
|
||
|
||
# 性能配置
|
||
innodb_flush_log_at_trx_commit = 2
|
||
sync_binlog = 0
|
||
query_cache_size = 0
|
||
query_cache_type = 0
|
||
|
||
# 日志配置
|
||
slow_query_log = 1
|
||
slow_query_log_file = /var/log/mysql/slow.log
|
||
long_query_time = 2
|
||
|
||
# 二进制日志
|
||
log-bin = mysql-bin
|
||
binlog_format = ROW
|
||
expire_logs_days = 7
|
||
```
|
||
|
||
3. **数据库初始化脚本**
|
||
|
||
```sql
|
||
-- sql/init/01-schema.sql
|
||
-- 用户表
|
||
CREATE TABLE users (
|
||
id VARCHAR(36) PRIMARY KEY,
|
||
username VARCHAR(50) UNIQUE NOT NULL,
|
||
email VARCHAR(100) UNIQUE NOT NULL,
|
||
password_hash VARCHAR(255) NOT NULL,
|
||
profile JSON,
|
||
status ENUM('active', 'inactive', 'suspended') DEFAULT 'active',
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
|
||
INDEX idx_username (username),
|
||
INDEX idx_email (email),
|
||
INDEX idx_status (status)
|
||
);
|
||
|
||
-- Telegram账号表
|
||
CREATE TABLE telegram_accounts (
|
||
id VARCHAR(36) PRIMARY KEY,
|
||
telegram_id VARCHAR(20) UNIQUE NOT NULL,
|
||
username VARCHAR(50),
|
||
first_name VARCHAR(50),
|
||
last_name VARCHAR(50),
|
||
phone VARCHAR(20),
|
||
status ENUM('active', 'inactive', 'blocked') DEFAULT 'active',
|
||
metadata JSON,
|
||
managed_by VARCHAR(36),
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
|
||
INDEX idx_telegram_id (telegram_id),
|
||
INDEX idx_username (username),
|
||
INDEX idx_managed_by (managed_by),
|
||
FOREIGN KEY (managed_by) REFERENCES users(id)
|
||
);
|
||
|
||
-- 更多表定义...
|
||
```
|
||
|
||
### Redis配置
|
||
|
||
1. **Redis配置文件**
|
||
|
||
```conf
|
||
# redis.conf
|
||
port 6379
|
||
bind 0.0.0.0
|
||
requirepass your_redis_password
|
||
|
||
# 持久化配置
|
||
save 900 1
|
||
save 300 10
|
||
save 60 10000
|
||
|
||
appendonly yes
|
||
appendfsync everysec
|
||
|
||
# 内存配置
|
||
maxmemory 512mb
|
||
maxmemory-policy allkeys-lru
|
||
|
||
# 网络配置
|
||
timeout 300
|
||
keepalive 60
|
||
|
||
# 日志配置
|
||
loglevel notice
|
||
logfile /var/log/redis/redis-server.log
|
||
|
||
# 安全配置
|
||
protected-mode yes
|
||
```
|
||
|
||
2. **Redis集群配置(可选)**
|
||
|
||
```conf
|
||
# redis-cluster.conf
|
||
port 7000
|
||
cluster-enabled yes
|
||
cluster-config-file nodes.conf
|
||
cluster-node-timeout 5000
|
||
appendonly yes
|
||
```
|
||
|
||
### MongoDB配置
|
||
|
||
1. **MongoDB初始化**
|
||
|
||
```javascript
|
||
// mongo-init.js
|
||
db = db.getSiblingDB('telegram_system_logs');
|
||
|
||
// 创建用户
|
||
db.createUser({
|
||
user: 'app_user',
|
||
pwd: 'your_mongodb_password',
|
||
roles: [
|
||
{
|
||
role: 'readWrite',
|
||
db: 'telegram_system_logs',
|
||
},
|
||
],
|
||
});
|
||
|
||
// 创建索引
|
||
db.logs.createIndex({ timestamp: 1 });
|
||
db.logs.createIndex({ level: 1 });
|
||
db.logs.createIndex({ source: 1 });
|
||
db.logs.createIndex({ userId: 1 });
|
||
|
||
// 创建TTL索引(日志保留30天)
|
||
db.logs.createIndex({ timestamp: 1 }, { expireAfterSeconds: 2592000 });
|
||
```
|
||
|
||
2. **MongoDB配置文件**
|
||
|
||
```yaml
|
||
# mongod.conf
|
||
systemLog:
|
||
destination: file
|
||
logAppend: true
|
||
path: /var/log/mongodb/mongod.log
|
||
|
||
storage:
|
||
dbPath: /var/lib/mongodb
|
||
journal:
|
||
enabled: true
|
||
|
||
processManagement:
|
||
fork: true
|
||
pidFilePath: /var/run/mongodb/mongod.pid
|
||
|
||
net:
|
||
port: 27017
|
||
bindIpAll: true
|
||
|
||
security:
|
||
authorization: enabled
|
||
|
||
replication:
|
||
replSetName: 'rs0'
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 环境变量配置
|
||
|
||
### 完整环境变量列表
|
||
|
||
```env
|
||
# .env.production
|
||
# ======================
|
||
# 应用基础配置
|
||
# ======================
|
||
NODE_ENV=production
|
||
PORT=3001
|
||
APP_NAME=Telegram管理系统
|
||
APP_VERSION=2.0.0
|
||
|
||
# ======================
|
||
# 数据库配置
|
||
# ======================
|
||
# MySQL配置
|
||
DB_HOST=mysql
|
||
DB_PORT=3306
|
||
DB_NAME=telegram_system
|
||
DB_USER=app_user
|
||
DB_PASSWORD=your_secure_mysql_password
|
||
DB_POOL_MIN=5
|
||
DB_POOL_MAX=50
|
||
DB_TIMEOUT=60000
|
||
|
||
# Redis配置
|
||
REDIS_HOST=redis
|
||
REDIS_PORT=6379
|
||
REDIS_PASSWORD=your_secure_redis_password
|
||
REDIS_DB=0
|
||
REDIS_KEY_PREFIX=telegram:
|
||
REDIS_CONNECT_TIMEOUT=10000
|
||
|
||
# MongoDB配置
|
||
MONGODB_URI=mongodb://app_user:your_mongodb_password@mongodb:27017/telegram_system_logs
|
||
MONGODB_OPTIONS={"authSource":"telegram_system_logs","useNewUrlParser":true}
|
||
|
||
# ======================
|
||
# 安全配置
|
||
# ======================
|
||
# JWT配置
|
||
JWT_SECRET=your_very_secure_jwt_secret_key_at_least_32_characters
|
||
JWT_EXPIRE=7d
|
||
REFRESH_TOKEN_SECRET=your_refresh_token_secret_key
|
||
REFRESH_TOKEN_EXPIRE=30d
|
||
|
||
# 加密配置
|
||
ENCRYPTION_KEY=your_32_character_encryption_key
|
||
HASH_ROUNDS=12
|
||
|
||
# CORS配置
|
||
CORS_ORIGINS=https://yourdomain.com,https://api.yourdomain.com
|
||
CORS_CREDENTIALS=true
|
||
|
||
# 安全头配置
|
||
HELMET_ENABLED=true
|
||
CSP_ENABLED=true
|
||
|
||
# ======================
|
||
# 第三方服务配置
|
||
# ======================
|
||
# Telegram配置
|
||
TELEGRAM_BOT_TOKEN=your_telegram_bot_token
|
||
TELEGRAM_WEBHOOK_URL=https://api.yourdomain.com/webhook/telegram
|
||
TELEGRAM_API_URL=https://api.telegram.org/bot
|
||
TELEGRAM_RATE_LIMIT=30
|
||
|
||
# 邮件配置
|
||
SMTP_HOST=smtp.gmail.com
|
||
SMTP_PORT=587
|
||
SMTP_SECURE=false
|
||
SMTP_USER=your_email@gmail.com
|
||
SMTP_PASS=your_app_password
|
||
SMTP_FROM_NAME=Telegram管理系统
|
||
SMTP_FROM_EMAIL=noreply@yourdomain.com
|
||
|
||
# 短信配置
|
||
SMS_PROVIDER=aliyun
|
||
SMS_ACCESS_KEY=your_sms_access_key
|
||
SMS_SECRET_KEY=your_sms_secret_key
|
||
SMS_SIGN_NAME=你的签名
|
||
SMS_TEMPLATE_CODE=SMS_123456789
|
||
|
||
# ======================
|
||
# 文件存储配置
|
||
# ======================
|
||
# 本地存储
|
||
FILE_STORAGE_TYPE=local
|
||
FILE_STORAGE_PATH=/app/uploads
|
||
FILE_STORAGE_URL=https://yourdomain.com/uploads
|
||
|
||
# 云存储(阿里云OSS)
|
||
# FILE_STORAGE_TYPE=oss
|
||
# OSS_REGION=oss-cn-beijing
|
||
# OSS_ACCESS_KEY_ID=your_oss_access_key
|
||
# OSS_ACCESS_KEY_SECRET=your_oss_secret_key
|
||
# OSS_BUCKET=your_bucket_name
|
||
# OSS_ENDPOINT=https://oss-cn-beijing.aliyuncs.com
|
||
|
||
# 文件限制
|
||
MAX_FILE_SIZE=10485760
|
||
ALLOWED_FILE_TYPES=jpg,jpeg,png,gif,pdf,doc,docx,xls,xlsx
|
||
|
||
# ======================
|
||
# 性能配置
|
||
# ======================
|
||
# 缓存配置
|
||
CACHE_TTL=3600
|
||
CACHE_MAX_SIZE=100
|
||
ENABLE_CACHE=true
|
||
|
||
# 限流配置
|
||
RATE_LIMIT_ENABLED=true
|
||
RATE_LIMIT_MAX=100
|
||
RATE_LIMIT_WINDOW=60000
|
||
RATE_LIMIT_SKIP_SUCCESSFUL=false
|
||
|
||
# 会话配置
|
||
SESSION_SECRET=your_session_secret_key
|
||
SESSION_TTL=86400
|
||
SESSION_STORE=redis
|
||
|
||
# ======================
|
||
# 日志配置
|
||
# ======================
|
||
LOG_LEVEL=info
|
||
LOG_FORMAT=json
|
||
LOG_FILE_ENABLED=true
|
||
LOG_FILE_PATH=/app/logs/app.log
|
||
LOG_FILE_MAX_SIZE=100m
|
||
LOG_FILE_MAX_FILES=10
|
||
|
||
# 访问日志
|
||
ACCESS_LOG_ENABLED=true
|
||
ACCESS_LOG_PATH=/app/logs/access.log
|
||
|
||
# 错误日志
|
||
ERROR_LOG_ENABLED=true
|
||
ERROR_LOG_PATH=/app/logs/error.log
|
||
|
||
# ======================
|
||
# 监控配置
|
||
# ======================
|
||
# 健康检查
|
||
HEALTH_CHECK_ENABLED=true
|
||
HEALTH_CHECK_TIMEOUT=5000
|
||
|
||
# 性能监控
|
||
PERFORMANCE_MONITORING=true
|
||
METRICS_ENDPOINT=/metrics
|
||
|
||
# APM配置
|
||
APM_ENABLED=false
|
||
APM_SERVICE_NAME=telegram-system-api
|
||
APM_SERVER_URL=http://apm-server:8200
|
||
|
||
# ======================
|
||
# WebSocket配置
|
||
# ======================
|
||
WS_ENABLED=true
|
||
WS_PORT=3001
|
||
WS_PATH=/ws
|
||
WS_HEARTBEAT_INTERVAL=30000
|
||
WS_TIMEOUT=60000
|
||
|
||
# ======================
|
||
# 队列配置
|
||
# ======================
|
||
QUEUE_ENABLED=true
|
||
QUEUE_REDIS_HOST=redis
|
||
QUEUE_REDIS_PORT=6379
|
||
QUEUE_REDIS_DB=1
|
||
QUEUE_CONCURRENCY=5
|
||
|
||
# 消息队列
|
||
MESSAGE_QUEUE_NAME=message_tasks
|
||
MESSAGE_QUEUE_ATTEMPTS=3
|
||
MESSAGE_QUEUE_DELAY=5000
|
||
|
||
# ======================
|
||
# 开发配置(仅开发环境)
|
||
# ======================
|
||
# DEBUG模式
|
||
DEBUG=false
|
||
DEVELOPMENT_FEATURES=false
|
||
|
||
# 热重载
|
||
HOT_RELOAD=false
|
||
|
||
# 测试配置
|
||
ENABLE_TEST_ROUTES=false
|
||
TEST_DATA_ENABLED=false
|
||
```
|
||
|
||
### 环境变量验证
|
||
|
||
创建环境变量验证脚本:
|
||
|
||
```javascript
|
||
// scripts/validate-env.js
|
||
const requiredVars = [
|
||
'NODE_ENV',
|
||
'PORT',
|
||
'DB_HOST',
|
||
'DB_NAME',
|
||
'DB_USER',
|
||
'DB_PASSWORD',
|
||
'REDIS_HOST',
|
||
'JWT_SECRET',
|
||
'TELEGRAM_BOT_TOKEN',
|
||
];
|
||
|
||
const optionalVars = [
|
||
'MONGODB_URI',
|
||
'SMTP_HOST',
|
||
'SMS_PROVIDER',
|
||
'FILE_STORAGE_TYPE',
|
||
];
|
||
|
||
function validateEnvironment() {
|
||
const missing = [];
|
||
const warnings = [];
|
||
|
||
// 检查必需变量
|
||
requiredVars.forEach((varName) => {
|
||
if (!process.env[varName]) {
|
||
missing.push(varName);
|
||
}
|
||
});
|
||
|
||
// 检查可选变量
|
||
optionalVars.forEach((varName) => {
|
||
if (!process.env[varName]) {
|
||
warnings.push(varName);
|
||
}
|
||
});
|
||
|
||
// 检查JWT密钥长度
|
||
if (process.env.JWT_SECRET && process.env.JWT_SECRET.length < 32) {
|
||
missing.push('JWT_SECRET (must be at least 32 characters)');
|
||
}
|
||
|
||
// 输出结果
|
||
if (missing.length > 0) {
|
||
console.error('❌ Missing required environment variables:');
|
||
missing.forEach((varName) => {
|
||
console.error(` - ${varName}`);
|
||
});
|
||
process.exit(1);
|
||
}
|
||
|
||
if (warnings.length > 0) {
|
||
console.warn('⚠️ Optional environment variables not set:');
|
||
warnings.forEach((varName) => {
|
||
console.warn(` - ${varName}`);
|
||
});
|
||
}
|
||
|
||
console.log('✅ Environment validation passed');
|
||
}
|
||
|
||
if (require.main === module) {
|
||
validateEnvironment();
|
||
}
|
||
|
||
module.exports = { validateEnvironment };
|
||
```
|
||
|
||
运行验证:
|
||
|
||
```bash
|
||
node scripts/validate-env.js
|
||
```
|
||
|
||
---
|
||
|
||
## 🔒 SSL证书配置
|
||
|
||
### 使用Let's Encrypt免费证书
|
||
|
||
1. **安装Certbot**
|
||
|
||
```bash
|
||
# Ubuntu/Debian
|
||
sudo apt update
|
||
sudo apt install certbot python3-certbot-nginx
|
||
|
||
# CentOS/Rocky Linux
|
||
sudo dnf install certbot python3-certbot-nginx
|
||
```
|
||
|
||
2. **获取SSL证书**
|
||
|
||
```bash
|
||
# 为域名申请证书
|
||
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com -d api.yourdomain.com
|
||
|
||
# 或者使用DNS验证(推荐)
|
||
sudo certbot certonly --dns-cloudflare \
|
||
--dns-cloudflare-credentials ~/.secrets/cloudflare.ini \
|
||
-d yourdomain.com \
|
||
-d "*.yourdomain.com"
|
||
```
|
||
|
||
3. **自动续期配置**
|
||
|
||
```bash
|
||
# 添加到crontab
|
||
sudo crontab -e
|
||
|
||
# 添加以下行(每天检查一次)
|
||
0 2 * * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload nginx"
|
||
```
|
||
|
||
### Nginx SSL配置
|
||
|
||
```nginx
|
||
# /etc/nginx/sites-available/telegram-system
|
||
server {
|
||
listen 80;
|
||
server_name yourdomain.com www.yourdomain.com;
|
||
return 301 https://$server_name$request_uri;
|
||
}
|
||
|
||
server {
|
||
listen 443 ssl http2;
|
||
server_name yourdomain.com www.yourdomain.com;
|
||
|
||
# SSL配置
|
||
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
|
||
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
|
||
|
||
# SSL安全配置
|
||
ssl_protocols TLSv1.2 TLSv1.3;
|
||
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
|
||
ssl_prefer_server_ciphers off;
|
||
ssl_session_cache shared:SSL:10m;
|
||
ssl_session_timeout 10m;
|
||
|
||
# HSTS
|
||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||
|
||
# 其他安全头
|
||
add_header X-Frame-Options DENY always;
|
||
add_header X-Content-Type-Options nosniff always;
|
||
add_header X-XSS-Protection "1; mode=block" always;
|
||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||
|
||
# 前端静态文件
|
||
root /var/www/telegram-system/dist;
|
||
index index.html;
|
||
|
||
# Gzip压缩
|
||
gzip on;
|
||
gzip_vary on;
|
||
gzip_min_length 1024;
|
||
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
|
||
|
||
# 静态文件缓存
|
||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||
expires 1y;
|
||
add_header Cache-Control "public, immutable";
|
||
}
|
||
|
||
# API代理
|
||
location /api/ {
|
||
proxy_pass http://backend-service:3001;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Upgrade $http_upgrade;
|
||
proxy_set_header Connection 'upgrade';
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
proxy_cache_bypass $http_upgrade;
|
||
|
||
# 超时配置
|
||
proxy_connect_timeout 60s;
|
||
proxy_send_timeout 60s;
|
||
proxy_read_timeout 60s;
|
||
|
||
# 缓冲配置
|
||
proxy_buffering on;
|
||
proxy_buffer_size 128k;
|
||
proxy_buffers 4 256k;
|
||
proxy_busy_buffers_size 256k;
|
||
}
|
||
|
||
# WebSocket代理
|
||
location /ws {
|
||
proxy_pass http://backend-service:3001;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Upgrade $http_upgrade;
|
||
proxy_set_header Connection "upgrade";
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
|
||
# WebSocket特定配置
|
||
proxy_read_timeout 86400;
|
||
proxy_send_timeout 86400;
|
||
}
|
||
|
||
# SPA路由支持
|
||
location / {
|
||
try_files $uri $uri/ /index.html;
|
||
}
|
||
|
||
# 健康检查
|
||
location /health {
|
||
access_log off;
|
||
return 200 "healthy\n";
|
||
add_header Content-Type text/plain;
|
||
}
|
||
}
|
||
|
||
# API子域名
|
||
server {
|
||
listen 443 ssl http2;
|
||
server_name api.yourdomain.com;
|
||
|
||
# SSL配置(复用主域名证书)
|
||
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
|
||
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
|
||
|
||
# 直接代理到后端
|
||
location / {
|
||
proxy_pass http://backend-service:3001;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Upgrade $http_upgrade;
|
||
proxy_set_header Connection 'upgrade';
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
proxy_cache_bypass $http_upgrade;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 安全最佳实践
|
||
|
||
1. **SSL配置测试**
|
||
|
||
```bash
|
||
# 使用SSL Labs测试
|
||
curl -s "https://api.ssllabs.com/api/v3/analyze?host=yourdomain.com" | jq .
|
||
|
||
# 使用testssl.sh
|
||
git clone https://github.com/drwetter/testssl.sh.git
|
||
cd testssl.sh
|
||
./testssl.sh yourdomain.com
|
||
```
|
||
|
||
2. **HTTP安全头检查**
|
||
|
||
```bash
|
||
# 检查安全头
|
||
curl -I https://yourdomain.com
|
||
|
||
# 使用securityheaders.com
|
||
curl -s "https://securityheaders.com/?q=yourdomain.com&hide=on&followRedirects=on" | grep grade
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 监控与日志
|
||
|
||
### 系统监控
|
||
|
||
1. **Prometheus + Grafana部署**
|
||
|
||
```yaml
|
||
# docker-compose.monitoring.yml
|
||
version: '3.8'
|
||
|
||
services:
|
||
prometheus:
|
||
image: prom/prometheus:latest
|
||
container_name: prometheus
|
||
ports:
|
||
- '9090:9090'
|
||
volumes:
|
||
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
|
||
- prometheus_data:/prometheus
|
||
command:
|
||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||
- '--storage.tsdb.path=/prometheus'
|
||
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
|
||
- '--web.console.templates=/usr/share/prometheus/consoles'
|
||
- '--web.enable-lifecycle'
|
||
|
||
grafana:
|
||
image: grafana/grafana:latest
|
||
container_name: grafana
|
||
ports:
|
||
- '3000:3000'
|
||
environment:
|
||
- GF_SECURITY_ADMIN_PASSWORD=admin123
|
||
volumes:
|
||
- grafana_data:/var/lib/grafana
|
||
- ./monitoring/grafana/dashboards:/etc/grafana/provisioning/dashboards
|
||
- ./monitoring/grafana/datasources:/etc/grafana/provisioning/datasources
|
||
|
||
node-exporter:
|
||
image: prom/node-exporter:latest
|
||
container_name: node-exporter
|
||
ports:
|
||
- '9100:9100'
|
||
volumes:
|
||
- /proc:/host/proc:ro
|
||
- /sys:/host/sys:ro
|
||
- /:/rootfs:ro
|
||
- /run/systemd/private:/run/systemd/private:ro
|
||
command:
|
||
- '--path.procfs=/host/proc'
|
||
- '--path.sysfs=/host/sys'
|
||
- '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'
|
||
|
||
alertmanager:
|
||
image: prom/alertmanager:latest
|
||
container_name: alertmanager
|
||
ports:
|
||
- '9093:9093'
|
||
volumes:
|
||
- ./monitoring/alertmanager.yml:/etc/alertmanager/alertmanager.yml
|
||
|
||
volumes:
|
||
prometheus_data:
|
||
grafana_data:
|
||
```
|
||
|
||
2. **Prometheus配置**
|
||
|
||
```yaml
|
||
# monitoring/prometheus.yml
|
||
global:
|
||
scrape_interval: 15s
|
||
evaluation_interval: 15s
|
||
|
||
rule_files:
|
||
- 'rules/*.yml'
|
||
|
||
alerting:
|
||
alertmanagers:
|
||
- static_configs:
|
||
- targets:
|
||
- alertmanager:9093
|
||
|
||
scrape_configs:
|
||
- job_name: 'prometheus'
|
||
static_configs:
|
||
- targets: ['localhost:9090']
|
||
|
||
- job_name: 'node-exporter'
|
||
static_configs:
|
||
- targets: ['node-exporter:9100']
|
||
|
||
- job_name: 'telegram-backend'
|
||
static_configs:
|
||
- targets: ['backend:3001']
|
||
metrics_path: '/metrics'
|
||
scrape_interval: 30s
|
||
|
||
- job_name: 'mysql'
|
||
static_configs:
|
||
- targets: ['mysql-exporter:9104']
|
||
|
||
- job_name: 'redis'
|
||
static_configs:
|
||
- targets: ['redis-exporter:9121']
|
||
```
|
||
|
||
3. **告警规则**
|
||
|
||
```yaml
|
||
# monitoring/rules/alerts.yml
|
||
groups:
|
||
- name: telegram-system-alerts
|
||
rules:
|
||
- alert: HighCPUUsage
|
||
expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
|
||
for: 5m
|
||
labels:
|
||
severity: warning
|
||
annotations:
|
||
summary: 'High CPU usage detected'
|
||
description: 'CPU usage is above 80% for more than 5 minutes'
|
||
|
||
- alert: HighMemoryUsage
|
||
expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100 > 90
|
||
for: 5m
|
||
labels:
|
||
severity: critical
|
||
annotations:
|
||
summary: 'High memory usage detected'
|
||
description: 'Memory usage is above 90% for more than 5 minutes'
|
||
|
||
- alert: ApplicationDown
|
||
expr: up{job="telegram-backend"} == 0
|
||
for: 1m
|
||
labels:
|
||
severity: critical
|
||
annotations:
|
||
summary: 'Application is down'
|
||
description: 'Telegram system backend is not responding'
|
||
|
||
- alert: DatabaseConnectionFailure
|
||
expr: mysql_up == 0
|
||
for: 2m
|
||
labels:
|
||
severity: critical
|
||
annotations:
|
||
summary: 'Database connection failure'
|
||
description: 'Cannot connect to MySQL database'
|
||
|
||
- alert: HighErrorRate
|
||
expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) * 100 > 5
|
||
for: 2m
|
||
labels:
|
||
severity: warning
|
||
annotations:
|
||
summary: 'High error rate detected'
|
||
description: 'Error rate is above 5% for more than 2 minutes'
|
||
```
|
||
|
||
### 日志管理
|
||
|
||
1. **ELK Stack部署**
|
||
|
||
```yaml
|
||
# docker-compose.elk.yml
|
||
version: '3.8'
|
||
|
||
services:
|
||
elasticsearch:
|
||
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.0
|
||
container_name: elasticsearch
|
||
environment:
|
||
- discovery.type=single-node
|
||
- 'ES_JAVA_OPTS=-Xms1g -Xmx1g'
|
||
ports:
|
||
- '9200:9200'
|
||
volumes:
|
||
- elasticsearch_data:/usr/share/elasticsearch/data
|
||
|
||
logstash:
|
||
image: docker.elastic.co/logstash/logstash:7.17.0
|
||
container_name: logstash
|
||
volumes:
|
||
- ./elk/logstash/config:/usr/share/logstash/pipeline
|
||
- ./elk/logstash/logstash.yml:/usr/share/logstash/config/logstash.yml
|
||
ports:
|
||
- '5044:5044'
|
||
depends_on:
|
||
- elasticsearch
|
||
|
||
kibana:
|
||
image: docker.elastic.co/kibana/kibana:7.17.0
|
||
container_name: kibana
|
||
ports:
|
||
- '5601:5601'
|
||
environment:
|
||
ELASTICSEARCH_HOSTS: http://elasticsearch:9200
|
||
depends_on:
|
||
- elasticsearch
|
||
|
||
volumes:
|
||
elasticsearch_data:
|
||
```
|
||
|
||
2. **Logstash配置**
|
||
|
||
```ruby
|
||
# elk/logstash/config/pipeline.conf
|
||
input {
|
||
beats {
|
||
port => 5044
|
||
}
|
||
|
||
tcp {
|
||
port => 5000
|
||
codec => json_lines
|
||
}
|
||
}
|
||
|
||
filter {
|
||
if [fields][service] == "telegram-system" {
|
||
json {
|
||
source => "message"
|
||
}
|
||
|
||
date {
|
||
match => [ "timestamp", "ISO8601" ]
|
||
}
|
||
|
||
if [level] == "error" {
|
||
mutate {
|
||
add_tag => [ "error" ]
|
||
}
|
||
}
|
||
|
||
# 解析用户代理
|
||
if [userAgent] {
|
||
useragent {
|
||
source => "userAgent"
|
||
target => "ua"
|
||
}
|
||
}
|
||
|
||
# IP地理位置
|
||
if [clientIP] {
|
||
geoip {
|
||
source => "clientIP"
|
||
target => "geoip"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
output {
|
||
elasticsearch {
|
||
hosts => ["elasticsearch:9200"]
|
||
index => "telegram-system-%{+YYYY.MM.dd}"
|
||
}
|
||
|
||
if "error" in [tags] {
|
||
email {
|
||
to => "admin@yourdomain.com"
|
||
subject => "Telegram System Error Alert"
|
||
body => "Error: %{message}\nTimestamp: %{timestamp}\nLevel: %{level}"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
3. **应用日志配置**
|
||
|
||
```javascript
|
||
// backend/utils/logger.js
|
||
const winston = require('winston');
|
||
require('winston-daily-rotate-file');
|
||
|
||
const logFormat = winston.format.combine(
|
||
winston.format.timestamp(),
|
||
winston.format.errors({ stack: true }),
|
||
winston.format.json(),
|
||
);
|
||
|
||
const logger = winston.createLogger({
|
||
level: process.env.LOG_LEVEL || 'info',
|
||
format: logFormat,
|
||
defaultMeta: {
|
||
service: 'telegram-system',
|
||
version: process.env.APP_VERSION,
|
||
},
|
||
transports: [
|
||
// 控制台输出
|
||
new winston.transports.Console({
|
||
format: winston.format.combine(
|
||
winston.format.colorize(),
|
||
winston.format.simple(),
|
||
),
|
||
}),
|
||
|
||
// 文件输出
|
||
new winston.transports.DailyRotateFile({
|
||
filename: 'logs/app-%DATE%.log',
|
||
datePattern: 'YYYY-MM-DD',
|
||
maxSize: '20m',
|
||
maxFiles: '14d',
|
||
level: 'info',
|
||
}),
|
||
|
||
// 错误日志
|
||
new winston.transports.DailyRotateFile({
|
||
filename: 'logs/error-%DATE%.log',
|
||
datePattern: 'YYYY-MM-DD',
|
||
maxSize: '20m',
|
||
maxFiles: '30d',
|
||
level: 'error',
|
||
}),
|
||
|
||
// 发送到Logstash
|
||
new winston.transports.Http({
|
||
host: 'logstash',
|
||
port: 5000,
|
||
level: 'warn',
|
||
}),
|
||
],
|
||
});
|
||
|
||
module.exports = logger;
|
||
```
|
||
|
||
---
|
||
|
||
## 💾 备份与恢复
|
||
|
||
### 数据库备份
|
||
|
||
1. **MySQL备份脚本**
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# scripts/backup-mysql.sh
|
||
|
||
# 配置
|
||
BACKUP_DIR="/opt/backups/mysql"
|
||
DB_NAME="telegram_system"
|
||
DB_USER="backup_user"
|
||
DB_PASSWORD="backup_password"
|
||
DB_HOST="localhost"
|
||
RETENTION_DAYS=30
|
||
|
||
# 创建备份目录
|
||
mkdir -p $BACKUP_DIR
|
||
|
||
# 生成备份文件名
|
||
BACKUP_FILE="$BACKUP_DIR/telegram_system_$(date +%Y%m%d_%H%M%S).sql"
|
||
|
||
# 执行备份
|
||
mysqldump -h $DB_HOST -u $DB_USER -p$DB_PASSWORD \
|
||
--single-transaction \
|
||
--routines \
|
||
--triggers \
|
||
--events \
|
||
--hex-blob \
|
||
--complete-insert \
|
||
$DB_NAME > $BACKUP_FILE
|
||
|
||
# 压缩备份文件
|
||
gzip $BACKUP_FILE
|
||
|
||
# 删除旧备份
|
||
find $BACKUP_DIR -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete
|
||
|
||
# 验证备份
|
||
if [ -f "$BACKUP_FILE.gz" ]; then
|
||
echo "Backup completed successfully: $BACKUP_FILE.gz"
|
||
|
||
# 上传到云存储(可选)
|
||
# aws s3 cp "$BACKUP_FILE.gz" s3://your-backup-bucket/mysql/
|
||
else
|
||
echo "Backup failed!"
|
||
exit 1
|
||
fi
|
||
```
|
||
|
||
2. **Redis备份脚本**
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# scripts/backup-redis.sh
|
||
|
||
BACKUP_DIR="/opt/backups/redis"
|
||
REDIS_HOST="localhost"
|
||
REDIS_PORT="6379"
|
||
REDIS_PASSWORD="your_redis_password"
|
||
RETENTION_DAYS=7
|
||
|
||
mkdir -p $BACKUP_DIR
|
||
|
||
# 触发Redis保存
|
||
redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD BGSAVE
|
||
|
||
# 等待保存完成
|
||
while [ $(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD LASTSAVE) -eq $(redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD LASTSAVE) ]; do
|
||
sleep 1
|
||
done
|
||
|
||
# 复制RDB文件
|
||
BACKUP_FILE="$BACKUP_DIR/redis_$(date +%Y%m%d_%H%M%S).rdb"
|
||
cp /var/lib/redis/dump.rdb $BACKUP_FILE
|
||
|
||
# 压缩
|
||
gzip $BACKUP_FILE
|
||
|
||
# 清理旧备份
|
||
find $BACKUP_DIR -name "*.rdb.gz" -mtime +$RETENTION_DAYS -delete
|
||
|
||
echo "Redis backup completed: $BACKUP_FILE.gz"
|
||
```
|
||
|
||
3. **MongoDB备份脚本**
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# scripts/backup-mongodb.sh
|
||
|
||
BACKUP_DIR="/opt/backups/mongodb"
|
||
DB_NAME="telegram_system_logs"
|
||
MONGO_HOST="localhost"
|
||
MONGO_PORT="27017"
|
||
MONGO_USER="backup_user"
|
||
MONGO_PASSWORD="backup_password"
|
||
RETENTION_DAYS=14
|
||
|
||
mkdir -p $BACKUP_DIR
|
||
|
||
BACKUP_FILE="$BACKUP_DIR/mongodb_$(date +%Y%m%d_%H%M%S)"
|
||
|
||
# 执行备份
|
||
mongodump \
|
||
--host $MONGO_HOST:$MONGO_PORT \
|
||
--username $MONGO_USER \
|
||
--password $MONGO_PASSWORD \
|
||
--db $DB_NAME \
|
||
--out $BACKUP_FILE
|
||
|
||
# 压缩备份
|
||
tar -czf "$BACKUP_FILE.tar.gz" -C $BACKUP_DIR $(basename $BACKUP_FILE)
|
||
rm -rf $BACKUP_FILE
|
||
|
||
# 清理旧备份
|
||
find $BACKUP_DIR -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete
|
||
|
||
echo "MongoDB backup completed: $BACKUP_FILE.tar.gz"
|
||
```
|
||
|
||
### 自动化备份
|
||
|
||
1. **Crontab配置**
|
||
|
||
```bash
|
||
# 编辑crontab
|
||
sudo crontab -e
|
||
|
||
# 添加备份任务
|
||
# MySQL备份 - 每天凌晨2点
|
||
0 2 * * * /opt/telegram-system/scripts/backup-mysql.sh >> /var/log/backup-mysql.log 2>&1
|
||
|
||
# Redis备份 - 每6小时
|
||
0 */6 * * * /opt/telegram-system/scripts/backup-redis.sh >> /var/log/backup-redis.log 2>&1
|
||
|
||
# MongoDB备份 - 每天凌晨3点
|
||
0 3 * * * /opt/telegram-system/scripts/backup-mongodb.sh >> /var/log/backup-mongodb.log 2>&1
|
||
|
||
# 文件备份 - 每周日凌晨1点
|
||
0 1 * * 0 /opt/telegram-system/scripts/backup-files.sh >> /var/log/backup-files.log 2>&1
|
||
```
|
||
|
||
2. **文件备份脚本**
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# scripts/backup-files.sh
|
||
|
||
BACKUP_DIR="/opt/backups/files"
|
||
SOURCE_DIR="/opt/telegram-system/uploads"
|
||
RETENTION_DAYS=90
|
||
|
||
mkdir -p $BACKUP_DIR
|
||
|
||
BACKUP_FILE="$BACKUP_DIR/files_$(date +%Y%m%d_%H%M%S).tar.gz"
|
||
|
||
# 备份上传文件
|
||
tar -czf $BACKUP_FILE -C $(dirname $SOURCE_DIR) $(basename $SOURCE_DIR)
|
||
|
||
# 清理旧备份
|
||
find $BACKUP_DIR -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete
|
||
|
||
echo "Files backup completed: $BACKUP_FILE"
|
||
```
|
||
|
||
### 恢复流程
|
||
|
||
1. **MySQL恢复**
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# scripts/restore-mysql.sh
|
||
|
||
BACKUP_FILE=$1
|
||
DB_NAME="telegram_system"
|
||
DB_USER="root"
|
||
DB_PASSWORD="root_password"
|
||
DB_HOST="localhost"
|
||
|
||
if [ -z "$BACKUP_FILE" ]; then
|
||
echo "Usage: $0 <backup_file>"
|
||
exit 1
|
||
fi
|
||
|
||
# 解压备份文件
|
||
if [[ $BACKUP_FILE == *.gz ]]; then
|
||
gunzip -c $BACKUP_FILE > /tmp/restore.sql
|
||
RESTORE_FILE="/tmp/restore.sql"
|
||
else
|
||
RESTORE_FILE=$BACKUP_FILE
|
||
fi
|
||
|
||
# 停止应用服务
|
||
docker-compose stop backend
|
||
|
||
# 删除现有数据库
|
||
mysql -h $DB_HOST -u $DB_USER -p$DB_PASSWORD -e "DROP DATABASE IF EXISTS $DB_NAME;"
|
||
mysql -h $DB_HOST -u $DB_USER -p$DB_PASSWORD -e "CREATE DATABASE $DB_NAME CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
||
|
||
# 恢复数据
|
||
mysql -h $DB_HOST -u $DB_USER -p$DB_PASSWORD $DB_NAME < $RESTORE_FILE
|
||
|
||
# 清理临时文件
|
||
if [ "$RESTORE_FILE" = "/tmp/restore.sql" ]; then
|
||
rm /tmp/restore.sql
|
||
fi
|
||
|
||
# 重启应用服务
|
||
docker-compose start backend
|
||
|
||
echo "MySQL restore completed from: $BACKUP_FILE"
|
||
```
|
||
|
||
2. **灾难恢复计划**
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# scripts/disaster-recovery.sh
|
||
|
||
echo "Starting disaster recovery process..."
|
||
|
||
# 1. 停止所有服务
|
||
echo "Stopping all services..."
|
||
docker-compose down
|
||
|
||
# 2. 恢复数据库
|
||
echo "Restoring databases..."
|
||
./scripts/restore-mysql.sh /opt/backups/mysql/latest.sql.gz
|
||
./scripts/restore-redis.sh /opt/backups/redis/latest.rdb.gz
|
||
./scripts/restore-mongodb.sh /opt/backups/mongodb/latest.tar.gz
|
||
|
||
# 3. 恢复文件
|
||
echo "Restoring files..."
|
||
tar -xzf /opt/backups/files/latest.tar.gz -C /opt/telegram-system/
|
||
|
||
# 4. 重新启动服务
|
||
echo "Starting services..."
|
||
docker-compose up -d
|
||
|
||
# 5. 验证服务
|
||
echo "Verifying services..."
|
||
sleep 30
|
||
|
||
# 检查服务状态
|
||
if curl -f http://localhost:3001/health; then
|
||
echo "✅ Disaster recovery completed successfully"
|
||
else
|
||
echo "❌ Disaster recovery failed - manual intervention required"
|
||
exit 1
|
||
fi
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 故障排除
|
||
|
||
### 常见问题
|
||
|
||
#### 1. 应用无法启动
|
||
|
||
**问题症状**:
|
||
|
||
- 容器启动失败
|
||
- 应用日志显示连接错误
|
||
- 健康检查失败
|
||
|
||
**解决步骤**:
|
||
|
||
```bash
|
||
# 检查容器状态
|
||
docker-compose ps
|
||
|
||
# 查看详细日志
|
||
docker-compose logs backend
|
||
|
||
# 检查环境变量
|
||
docker-compose exec backend printenv
|
||
|
||
# 检查网络连接
|
||
docker-compose exec backend ping mysql
|
||
docker-compose exec backend ping redis
|
||
|
||
# 验证数据库连接
|
||
docker-compose exec backend npm run db:check
|
||
```
|
||
|
||
**常见原因**:
|
||
|
||
- 数据库未就绪
|
||
- 环境变量配置错误
|
||
- 网络连接问题
|
||
- 端口冲突
|
||
|
||
#### 2. 数据库连接失败
|
||
|
||
**问题症状**:
|
||
|
||
- `ECONNREFUSED` 错误
|
||
- 数据库超时
|
||
- 认证失败
|
||
|
||
**解决步骤**:
|
||
|
||
```bash
|
||
# 检查MySQL状态
|
||
docker-compose exec mysql mysql -u root -p -e "SHOW DATABASES;"
|
||
|
||
# 检查用户权限
|
||
docker-compose exec mysql mysql -u root -p -e "SELECT User, Host FROM mysql.user;"
|
||
|
||
# 测试连接
|
||
docker-compose exec backend mysql -h mysql -u app_user -p
|
||
|
||
# 检查网络
|
||
docker network ls
|
||
docker network inspect telegram-system_default
|
||
```
|
||
|
||
#### 3. Redis连接问题
|
||
|
||
**问题症状**:
|
||
|
||
- 缓存功能异常
|
||
- 会话丢失
|
||
- WebSocket连接问题
|
||
|
||
**解决步骤**:
|
||
|
||
```bash
|
||
# 检查Redis状态
|
||
docker-compose exec redis redis-cli ping
|
||
|
||
# 测试认证
|
||
docker-compose exec redis redis-cli -a your_password ping
|
||
|
||
# 检查配置
|
||
docker-compose exec redis redis-cli config get "*"
|
||
|
||
# 查看连接信息
|
||
docker-compose exec redis redis-cli info clients
|
||
```
|
||
|
||
#### 4. 前端无法访问后端
|
||
|
||
**问题症状**:
|
||
|
||
- API请求失败
|
||
- CORS错误
|
||
- 502/504错误
|
||
|
||
**解决步骤**:
|
||
|
||
```bash
|
||
# 检查Nginx配置
|
||
nginx -t
|
||
|
||
# 重新加载Nginx
|
||
nginx -s reload
|
||
|
||
# 检查代理配置
|
||
curl -I http://localhost/api/health
|
||
|
||
# 检查网络连接
|
||
telnet backend 3001
|
||
```
|
||
|
||
#### 5. SSL证书问题
|
||
|
||
**问题症状**:
|
||
|
||
- 证书过期警告
|
||
- SSL握手失败
|
||
- 混合内容错误
|
||
|
||
**解决步骤**:
|
||
|
||
```bash
|
||
# 检查证书状态
|
||
openssl x509 -in /etc/letsencrypt/live/yourdomain.com/cert.pem -text -noout
|
||
|
||
# 验证证书链
|
||
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt /etc/letsencrypt/live/yourdomain.com/cert.pem
|
||
|
||
# 续期证书
|
||
certbot renew --dry-run
|
||
|
||
# 检查证书有效期
|
||
certbot certificates
|
||
```
|
||
|
||
### 性能问题排查
|
||
|
||
#### 1. 响应时间过长
|
||
|
||
**排查步骤**:
|
||
|
||
```bash
|
||
# 检查系统资源
|
||
top
|
||
htop
|
||
iostat -x 1
|
||
|
||
# 检查数据库性能
|
||
docker-compose exec mysql mysql -u root -p -e "SHOW PROCESSLIST;"
|
||
docker-compose exec mysql mysql -u root -p -e "SHOW STATUS LIKE 'Slow_queries';"
|
||
|
||
# 检查Redis性能
|
||
docker-compose exec redis redis-cli --latency
|
||
docker-compose exec redis redis-cli info stats
|
||
|
||
# 分析应用日志
|
||
tail -f logs/app.log | grep -E "(slow|timeout|error)"
|
||
```
|
||
|
||
#### 2. 内存使用过高
|
||
|
||
**排查步骤**:
|
||
|
||
```bash
|
||
# 检查容器内存使用
|
||
docker stats
|
||
|
||
# 检查Node.js内存泄漏
|
||
docker-compose exec backend node --expose-gc --inspect=0.0.0.0:9229 server.js
|
||
|
||
# 分析heap dump
|
||
npm install -g heapdump
|
||
```
|
||
|
||
#### 3. 数据库锁等待
|
||
|
||
**排查步骤**:
|
||
|
||
```bash
|
||
# 检查锁等待
|
||
docker-compose exec mysql mysql -u root -p -e "SHOW ENGINE INNODB STATUS\G" | grep -A 10 "TRANSACTIONS"
|
||
|
||
# 查看当前事务
|
||
docker-compose exec mysql mysql -u root -p -e "SELECT * FROM information_schema.innodb_trx;"
|
||
|
||
# 查看锁等待
|
||
docker-compose exec mysql mysql -u root -p -e "SELECT * FROM information_schema.innodb_locks;"
|
||
```
|
||
|
||
### 日志分析
|
||
|
||
#### 应用日志分析
|
||
|
||
```bash
|
||
# 错误日志分析
|
||
grep -E "ERROR|FATAL" logs/app.log | tail -n 50
|
||
|
||
# 慢查询分析
|
||
grep "slow query" logs/app.log | awk '{print $NF}' | sort | uniq -c | sort -nr
|
||
|
||
# API错误统计
|
||
grep "api_error" logs/access.log | cut -d' ' -f7 | sort | uniq -c | sort -nr
|
||
|
||
# 用户活动分析
|
||
grep "user_action" logs/app.log | cut -d' ' -f4 | sort | uniq -c | sort -nr
|
||
```
|
||
|
||
#### 系统日志分析
|
||
|
||
```bash
|
||
# 系统错误
|
||
journalctl -u docker -f
|
||
|
||
# 内核日志
|
||
dmesg | tail -n 50
|
||
|
||
# 磁盘空间检查
|
||
df -h
|
||
du -sh /opt/telegram-system/* | sort -h
|
||
```
|
||
|
||
### 监控告警处理
|
||
|
||
#### 告警响应流程
|
||
|
||
1. **收到告警**
|
||
- 查看告警详情
|
||
- 确认告警级别
|
||
- 开始故障处理
|
||
|
||
2. **问题排查**
|
||
- 检查监控面板
|
||
- 分析相关日志
|
||
- 确定问题范围
|
||
|
||
3. **问题修复**
|
||
- 实施修复措施
|
||
- 验证修复效果
|
||
- 更新告警状态
|
||
|
||
4. **后续跟进**
|
||
- 编写事故报告
|
||
- 优化监控规则
|
||
- 预防类似问题
|
||
|
||
### 应急处理脚本
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# scripts/emergency-response.sh
|
||
|
||
ISSUE_TYPE=$1
|
||
|
||
case $ISSUE_TYPE in
|
||
"high-cpu")
|
||
echo "处理高CPU使用率问题..."
|
||
# 重启应用服务
|
||
docker-compose restart backend
|
||
# 清理临时文件
|
||
docker system prune -f
|
||
;;
|
||
|
||
"high-memory")
|
||
echo "处理高内存使用问题..."
|
||
# 清理缓存
|
||
docker-compose exec redis redis-cli FLUSHDB
|
||
# 重启服务
|
||
docker-compose restart backend
|
||
;;
|
||
|
||
"database-down")
|
||
echo "处理数据库故障..."
|
||
# 尝试重启数据库
|
||
docker-compose restart mysql
|
||
# 检查数据完整性
|
||
docker-compose exec mysql mysqlcheck --all-databases
|
||
;;
|
||
|
||
"disk-full")
|
||
echo "处理磁盘空间不足..."
|
||
# 清理日志文件
|
||
find /var/log -name "*.log" -mtime +7 -delete
|
||
# 清理Docker缓存
|
||
docker system prune -a -f
|
||
# 清理备份文件
|
||
find /opt/backups -mtime +30 -delete
|
||
;;
|
||
|
||
*)
|
||
echo "用法: $0 {high-cpu|high-memory|database-down|disk-full}"
|
||
exit 1
|
||
;;
|
||
esac
|
||
|
||
echo "应急处理完成,请检查系统状态"
|
||
```
|
||
|
||
---
|
||
|
||
## 📚 附录
|
||
|
||
### 部署检查清单
|
||
|
||
#### 部署前检查
|
||
|
||
- [ ] 服务器资源满足要求
|
||
- [ ] 域名DNS配置正确
|
||
- [ ] SSL证书已申请
|
||
- [ ] 环境变量已配置
|
||
- [ ] 数据库已创建
|
||
- [ ] 备份策略已制定
|
||
|
||
#### 部署过程检查
|
||
|
||
- [ ] 代码版本正确
|
||
- [ ] 构建过程无错误
|
||
- [ ] 数据库迁移成功
|
||
- [ ] 服务启动正常
|
||
- [ ] 健康检查通过
|
||
- [ ] SSL证书生效
|
||
|
||
#### 部署后验证
|
||
|
||
- [ ] 前端页面可访问
|
||
- [ ] API接口正常
|
||
- [ ] 用户登录功能
|
||
- [ ] 数据库连接正常
|
||
- [ ] 缓存功能正常
|
||
- [ ] WebSocket连接正常
|
||
- [ ] 邮件发送功能
|
||
- [ ] 文件上传功能
|
||
- [ ] 监控告警配置
|
||
|
||
### 常用命令
|
||
|
||
#### Docker相关
|
||
|
||
```bash
|
||
# 查看服务状态
|
||
docker-compose ps
|
||
|
||
# 查看日志
|
||
docker-compose logs -f backend
|
||
|
||
# 重启服务
|
||
docker-compose restart backend
|
||
|
||
# 进入容器
|
||
docker-compose exec backend bash
|
||
|
||
# 更新服务
|
||
docker-compose pull
|
||
docker-compose up -d
|
||
|
||
# 清理资源
|
||
docker system prune -f
|
||
```
|
||
|
||
#### 数据库相关
|
||
|
||
```bash
|
||
# 连接MySQL
|
||
docker-compose exec mysql mysql -u root -p
|
||
|
||
# 导出数据库
|
||
docker-compose exec mysql mysqldump -u root -p telegram_system > backup.sql
|
||
|
||
# 导入数据库
|
||
docker-compose exec -T mysql mysql -u root -p telegram_system < backup.sql
|
||
|
||
# 检查Redis
|
||
docker-compose exec redis redis-cli ping
|
||
|
||
# MongoDB操作
|
||
docker-compose exec mongodb mongo telegram_system_logs
|
||
```
|
||
|
||
#### 系统维护
|
||
|
||
```bash
|
||
# 检查磁盘空间
|
||
df -h
|
||
|
||
# 检查内存使用
|
||
free -h
|
||
|
||
# 检查系统负载
|
||
uptime
|
||
|
||
# 查看网络连接
|
||
netstat -tlnp
|
||
|
||
# 检查端口占用
|
||
lsof -i :3001
|
||
```
|
||
|
||
### 联系方式
|
||
|
||
- **技术支持**: support@yourdomain.com
|
||
- **紧急联系**: +86-138-0000-0000
|
||
- **文档地址**: https://docs.yourdomain.com
|
||
- **监控地址**: https://monitor.yourdomain.com
|
||
|
||
---
|
||
|
||
**最后更新**: 2024-01-20
|
||
**文档版本**: v2.0.0
|
||
|
||
> 本部署指南涵盖了从开发环境到生产环境的完整部署流程。如有疑问或需要支持,请联系技术团队。
|