1427 lines
36 KiB
Markdown
1427 lines
36 KiB
Markdown
# DataTools Pro 部署指南
|
||
|
||
## 1. 部署概述
|
||
|
||
### 1.1 部署架构
|
||
DataTools Pro支持多种部署方式,从简单的单机部署到企业级的容器化集群部署。
|
||
|
||
```
|
||
部署架构选择:
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ 部署方案对比 │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ 开发环境部署 │
|
||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||
│ │ • 本地开发服务器 (Flask dev server) │ │
|
||
│ │ • SQLite数据库 │ │
|
||
│ │ • 适用于: 开发测试、功能验证 │ │
|
||
│ └─────────────────────────────────────────────────────────┘ │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ 生产环境部署 │
|
||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||
│ │ • WSGI服务器 (Gunicorn/uWSGI) │ │
|
||
│ │ • 反向代理 (Nginx/Apache) │ │
|
||
│ │ • 进程管理 (systemd/supervisor) │ │
|
||
│ │ • 适用于: 小型生产环境 │ │
|
||
│ └─────────────────────────────────────────────────────────┘ │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ 容器化部署 │
|
||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||
│ │ • Docker容器化 │ │
|
||
│ │ • Docker Compose编排 │ │
|
||
│ │ • 负载均衡和高可用 │ │
|
||
│ │ • 适用于: 中大型生产环境 │ │
|
||
│ └─────────────────────────────────────────────────────────┘ │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ Kubernetes部署 │
|
||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||
│ │ • K8s Deployment和Service │ │
|
||
│ │ • 自动扩缩容和故障恢复 │ │
|
||
│ │ • ConfigMap和Secret管理 │ │
|
||
│ │ • 适用于: 企业级云原生环境 │ │
|
||
│ └─────────────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 1.2 环境要求
|
||
|
||
#### 1.2.1 基础环境
|
||
- **操作系统**: Linux (推荐Ubuntu 20.04+, CentOS 8+)
|
||
- **Python版本**: Python 3.7+
|
||
- **内存**: 最低2GB,推荐4GB+
|
||
- **磁盘**: 最低10GB,推荐50GB+
|
||
- **网络**: 能够访问Cassandra和Redis集群
|
||
|
||
#### 1.2.2 软件依赖
|
||
```bash
|
||
# 系统包依赖
|
||
sudo apt-get update
|
||
sudo apt-get install -y \
|
||
python3 \
|
||
python3-pip \
|
||
python3-venv \
|
||
git \
|
||
nginx \
|
||
supervisor \
|
||
curl \
|
||
wget
|
||
```
|
||
|
||
#### 1.2.3 Python依赖
|
||
```txt
|
||
# requirements.txt
|
||
Flask==2.3.3
|
||
cassandra-driver==3.29.1
|
||
redis==4.5.4
|
||
redis-py-cluster==2.1.3
|
||
gunicorn==21.2.0
|
||
gevent==23.7.0
|
||
python-dotenv==1.0.0
|
||
PyYAML==6.0.1
|
||
cryptography==41.0.3
|
||
```
|
||
|
||
## 2. 开发环境部署
|
||
|
||
### 2.1 快速启动
|
||
```bash
|
||
# 1. 克隆项目
|
||
git clone <repository-url>
|
||
cd BigDataTool
|
||
|
||
# 2. 创建虚拟环境
|
||
python3 -m venv venv
|
||
source venv/bin/activate # Linux/Mac
|
||
# venv\Scripts\activate # Windows
|
||
|
||
# 3. 安装依赖
|
||
pip install -r requirements.txt
|
||
|
||
# 4. 初始化配置
|
||
cp config.example.py config.py
|
||
|
||
# 5. 启动应用
|
||
python app.py
|
||
```
|
||
|
||
### 2.2 开发环境配置
|
||
```python
|
||
# config.py - 开发环境配置
|
||
DEBUG = True
|
||
TESTING = False
|
||
|
||
# 数据库配置
|
||
DATABASE_URL = 'sqlite:///config_groups.db'
|
||
|
||
# 日志配置
|
||
LOG_LEVEL = 'DEBUG'
|
||
LOG_FILE = 'logs/datatools.log'
|
||
|
||
# 安全配置
|
||
SECRET_KEY = 'dev-secret-key-change-in-production'
|
||
|
||
# Cassandra默认配置
|
||
DEFAULT_CASSANDRA_CONFIG = {
|
||
'hosts': ['127.0.0.1'],
|
||
'port': 9042,
|
||
'keyspace': 'test_ks'
|
||
}
|
||
|
||
# Redis默认配置
|
||
DEFAULT_REDIS_CONFIG = {
|
||
'host': '127.0.0.1',
|
||
'port': 6379,
|
||
'db': 0
|
||
}
|
||
```
|
||
|
||
### 2.3 开发服务脚本
|
||
```bash
|
||
#!/bin/bash
|
||
# dev-server.sh - 开发服务器启动脚本
|
||
|
||
set -e
|
||
|
||
# 检查虚拟环境
|
||
if [[ "$VIRTUAL_ENV" == "" ]]; then
|
||
echo "请先激活虚拟环境: source venv/bin/activate"
|
||
exit 1
|
||
fi
|
||
|
||
# 创建必要目录
|
||
mkdir -p logs
|
||
mkdir -p data
|
||
|
||
# 检查配置文件
|
||
if [ ! -f "config.py" ]; then
|
||
echo "复制配置文件: cp config.example.py config.py"
|
||
cp config.example.py config.py
|
||
fi
|
||
|
||
# 初始化数据库
|
||
python -c "
|
||
from app import init_database
|
||
init_database()
|
||
print('数据库初始化完成')
|
||
"
|
||
|
||
# 启动开发服务器
|
||
echo "启动DataTools Pro开发服务器..."
|
||
echo "访问地址: http://localhost:5000"
|
||
python app.py
|
||
```
|
||
|
||
## 3. 生产环境部署
|
||
|
||
### 3.1 系统用户创建
|
||
```bash
|
||
# 创建专用用户
|
||
sudo useradd -r -s /bin/false datatools
|
||
sudo mkdir -p /opt/datatools
|
||
sudo chown datatools:datatools /opt/datatools
|
||
```
|
||
|
||
### 3.2 应用部署
|
||
```bash
|
||
#!/bin/bash
|
||
# deploy-production.sh - 生产环境部署脚本
|
||
|
||
set -e
|
||
|
||
APP_USER="datatools"
|
||
APP_DIR="/opt/datatools"
|
||
APP_NAME="datatools-pro"
|
||
PYTHON_VERSION="3.9"
|
||
|
||
echo "开始部署DataTools Pro到生产环境..."
|
||
|
||
# 1. 创建应用目录
|
||
sudo mkdir -p $APP_DIR/{app,logs,data,backup}
|
||
sudo chown -R $APP_USER:$APP_USER $APP_DIR
|
||
|
||
# 2. 部署应用代码
|
||
sudo -u $APP_USER git clone <repository-url> $APP_DIR/app
|
||
cd $APP_DIR/app
|
||
|
||
# 3. 创建虚拟环境
|
||
sudo -u $APP_USER python$PYTHON_VERSION -m venv $APP_DIR/venv
|
||
sudo -u $APP_USER $APP_DIR/venv/bin/pip install --upgrade pip
|
||
|
||
# 4. 安装依赖
|
||
sudo -u $APP_USER $APP_DIR/venv/bin/pip install -r requirements.txt
|
||
|
||
# 5. 创建生产配置
|
||
sudo -u $APP_USER cp config.example.py config.py
|
||
sudo -u $APP_USER cat > config.py << 'EOF'
|
||
import os
|
||
from dotenv import load_dotenv
|
||
|
||
# 加载环境变量
|
||
load_dotenv()
|
||
|
||
# 基础配置
|
||
DEBUG = False
|
||
TESTING = False
|
||
SECRET_KEY = os.getenv('SECRET_KEY', 'change-this-in-production')
|
||
|
||
# 数据库配置
|
||
DATABASE_URL = os.getenv('DATABASE_URL', '/opt/datatools/data/config_groups.db')
|
||
|
||
# 日志配置
|
||
LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO')
|
||
LOG_FILE = '/opt/datatools/logs/datatools.log'
|
||
|
||
# 服务器配置
|
||
HOST = os.getenv('HOST', '127.0.0.1')
|
||
PORT = int(os.getenv('PORT', 5000))
|
||
WORKERS = int(os.getenv('WORKERS', 4))
|
||
|
||
# 外部服务配置
|
||
CASSANDRA_HOSTS = os.getenv('CASSANDRA_HOSTS', '127.0.0.1').split(',')
|
||
REDIS_HOSTS = os.getenv('REDIS_HOSTS', '127.0.0.1').split(',')
|
||
EOF
|
||
|
||
# 6. 创建环境变量文件
|
||
sudo -u $APP_USER cat > $APP_DIR/.env << 'EOF'
|
||
# 生产环境配置
|
||
SECRET_KEY=your-production-secret-key-here
|
||
DATABASE_URL=/opt/datatools/data/config_groups.db
|
||
LOG_LEVEL=INFO
|
||
HOST=127.0.0.1
|
||
PORT=5000
|
||
WORKERS=4
|
||
|
||
# 外部服务
|
||
CASSANDRA_HOSTS=10.0.1.100,10.0.1.101
|
||
REDIS_HOSTS=10.0.2.100,10.0.2.101
|
||
EOF
|
||
|
||
# 7. 初始化数据库
|
||
sudo -u $APP_USER $APP_DIR/venv/bin/python -c "
|
||
import sys
|
||
sys.path.insert(0, '$APP_DIR/app')
|
||
from app import init_database
|
||
init_database()
|
||
print('数据库初始化完成')
|
||
"
|
||
|
||
# 8. 设置权限
|
||
sudo chown -R $APP_USER:$APP_USER $APP_DIR
|
||
sudo chmod 600 $APP_DIR/.env
|
||
sudo chmod 755 $APP_DIR/app/app.py
|
||
|
||
echo "应用部署完成: $APP_DIR"
|
||
```
|
||
|
||
### 3.3 Gunicorn配置
|
||
```python
|
||
# gunicorn.conf.py
|
||
import os
|
||
import multiprocessing
|
||
|
||
# 服务器socket
|
||
bind = f"{os.getenv('HOST', '127.0.0.1')}:{os.getenv('PORT', 5000)}"
|
||
backlog = 2048
|
||
|
||
# Worker进程
|
||
workers = int(os.getenv('WORKERS', multiprocessing.cpu_count() * 2 + 1))
|
||
worker_class = 'gevent'
|
||
worker_connections = 1000
|
||
max_requests = 1000
|
||
max_requests_jitter = 100
|
||
preload_app = True
|
||
|
||
# 超时设置
|
||
timeout = 120
|
||
keepalive = 2
|
||
graceful_timeout = 30
|
||
|
||
# 日志配置
|
||
accesslog = '/opt/datatools/logs/access.log'
|
||
errorlog = '/opt/datatools/logs/error.log'
|
||
loglevel = 'info'
|
||
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
|
||
|
||
# 进程命名
|
||
proc_name = 'datatools-pro'
|
||
|
||
# 用户和组
|
||
user = 'datatools'
|
||
group = 'datatools'
|
||
|
||
# 临时目录
|
||
tmp_upload_dir = '/opt/datatools/tmp'
|
||
|
||
# 启动时钩子
|
||
def on_starting(server):
|
||
server.log.info("DataTools Pro 正在启动...")
|
||
|
||
def when_ready(server):
|
||
server.log.info("DataTools Pro 启动完成")
|
||
|
||
def on_exit(server):
|
||
server.log.info("DataTools Pro 正在关闭...")
|
||
```
|
||
|
||
### 3.4 Systemd服务配置
|
||
```ini
|
||
# /etc/systemd/system/datatools-pro.service
|
||
[Unit]
|
||
Description=DataTools Pro - Enterprise Data Processing Platform
|
||
After=network.target
|
||
Wants=network.target
|
||
|
||
[Service]
|
||
Type=notify
|
||
User=datatools
|
||
Group=datatools
|
||
RuntimeDirectory=datatools-pro
|
||
WorkingDirectory=/opt/datatools/app
|
||
Environment=PATH=/opt/datatools/venv/bin
|
||
EnvironmentFile=/opt/datatools/.env
|
||
ExecStart=/opt/datatools/venv/bin/gunicorn --config gunicorn.conf.py app:app
|
||
ExecReload=/bin/kill -s HUP $MAINPID
|
||
KillMode=mixed
|
||
TimeoutStopSec=30
|
||
PrivateTmp=true
|
||
ProtectSystem=strict
|
||
ReadWritePaths=/opt/datatools
|
||
NoNewPrivileges=yes
|
||
|
||
# 重启策略
|
||
Restart=always
|
||
RestartSec=10
|
||
StartLimitBurst=3
|
||
StartLimitInterval=60
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
```
|
||
|
||
```bash
|
||
# 启用和启动服务
|
||
sudo systemctl daemon-reload
|
||
sudo systemctl enable datatools-pro
|
||
sudo systemctl start datatools-pro
|
||
sudo systemctl status datatools-pro
|
||
```
|
||
|
||
### 3.5 Nginx反向代理配置
|
||
```nginx
|
||
# /etc/nginx/sites-available/datatools-pro
|
||
upstream datatools_backend {
|
||
server 127.0.0.1:5000 fail_timeout=0;
|
||
# 如果有多个worker,可以添加多个server
|
||
# server 127.0.0.1:5001 fail_timeout=0;
|
||
# server 127.0.0.1:5002 fail_timeout=0;
|
||
}
|
||
|
||
server {
|
||
listen 80;
|
||
listen [::]:80;
|
||
server_name datatools.yourdomain.com;
|
||
|
||
# 重定向到HTTPS
|
||
return 301 https://$server_name$request_uri;
|
||
}
|
||
|
||
server {
|
||
listen 443 ssl http2;
|
||
listen [::]:443 ssl http2;
|
||
server_name datatools.yourdomain.com;
|
||
|
||
# SSL配置
|
||
ssl_certificate /etc/ssl/certs/datatools.crt;
|
||
ssl_certificate_key /etc/ssl/private/datatools.key;
|
||
ssl_protocols TLSv1.2 TLSv1.3;
|
||
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384;
|
||
ssl_prefer_server_ciphers off;
|
||
ssl_session_cache shared:SSL:10m;
|
||
ssl_session_timeout 10m;
|
||
|
||
# 安全头
|
||
add_header X-Frame-Options DENY;
|
||
add_header X-Content-Type-Options nosniff;
|
||
add_header X-XSS-Protection "1; mode=block";
|
||
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
|
||
|
||
# 基础配置
|
||
client_max_body_size 100M;
|
||
keepalive_timeout 65;
|
||
gzip on;
|
||
gzip_vary on;
|
||
gzip_types
|
||
text/plain
|
||
text/css
|
||
text/xml
|
||
text/javascript
|
||
application/javascript
|
||
application/xml+rss
|
||
application/json;
|
||
|
||
# 静态文件缓存
|
||
location /static/ {
|
||
alias /opt/datatools/app/static/;
|
||
expires 1y;
|
||
add_header Cache-Control "public, immutable";
|
||
access_log off;
|
||
}
|
||
|
||
# API接口
|
||
location /api/ {
|
||
proxy_pass http://datatools_backend;
|
||
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 120s;
|
||
proxy_buffering off;
|
||
}
|
||
|
||
# 应用主体
|
||
location / {
|
||
proxy_pass http://datatools_backend;
|
||
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;
|
||
}
|
||
|
||
# 日志配置
|
||
access_log /var/log/nginx/datatools-access.log;
|
||
error_log /var/log/nginx/datatools-error.log;
|
||
}
|
||
```
|
||
|
||
```bash
|
||
# 启用站点
|
||
sudo ln -s /etc/nginx/sites-available/datatools-pro /etc/nginx/sites-enabled/
|
||
sudo nginx -t
|
||
sudo systemctl reload nginx
|
||
```
|
||
|
||
## 4. 容器化部署
|
||
|
||
### 4.1 Dockerfile
|
||
```dockerfile
|
||
# Dockerfile
|
||
FROM python:3.9-slim
|
||
|
||
# 设置工作目录
|
||
WORKDIR /app
|
||
|
||
# 安装系统依赖
|
||
RUN apt-get update && apt-get install -y \
|
||
gcc \
|
||
g++ \
|
||
&& rm -rf /var/lib/apt/lists/*
|
||
|
||
# 复制依赖文件
|
||
COPY requirements.txt .
|
||
|
||
# 安装Python依赖
|
||
RUN pip install --no-cache-dir -r requirements.txt
|
||
|
||
# 复制应用代码
|
||
COPY . .
|
||
|
||
# 创建非root用户
|
||
RUN useradd -r -s /bin/false appuser && \
|
||
chown -R appuser:appuser /app
|
||
|
||
# 切换到非root用户
|
||
USER appuser
|
||
|
||
# 暴露端口
|
||
EXPOSE 5000
|
||
|
||
# 健康检查
|
||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||
CMD curl -f http://localhost:5000/api/health || exit 1
|
||
|
||
# 启动命令
|
||
CMD ["gunicorn", "--config", "gunicorn.conf.py", "app:app"]
|
||
```
|
||
|
||
### 4.2 Docker Compose配置
|
||
```yaml
|
||
# docker-compose.yml
|
||
version: '3.8'
|
||
|
||
services:
|
||
datatools-pro:
|
||
build:
|
||
context: .
|
||
dockerfile: Dockerfile
|
||
image: datatools-pro:latest
|
||
container_name: datatools-pro
|
||
restart: unless-stopped
|
||
ports:
|
||
- "5000:5000"
|
||
environment:
|
||
- DEBUG=False
|
||
- SECRET_KEY=${SECRET_KEY}
|
||
- DATABASE_URL=/app/data/config_groups.db
|
||
- LOG_LEVEL=INFO
|
||
- CASSANDRA_HOSTS=${CASSANDRA_HOSTS}
|
||
- REDIS_HOSTS=${REDIS_HOSTS}
|
||
volumes:
|
||
- ./data:/app/data
|
||
- ./logs:/app/logs
|
||
- ./backup:/app/backup
|
||
networks:
|
||
- datatools-network
|
||
healthcheck:
|
||
test: ["CMD", "curl", "-f", "http://localhost:5000/api/health"]
|
||
interval: 30s
|
||
timeout: 10s
|
||
retries: 3
|
||
start_period: 40s
|
||
|
||
nginx:
|
||
image: nginx:alpine
|
||
container_name: datatools-nginx
|
||
restart: unless-stopped
|
||
ports:
|
||
- "80:80"
|
||
- "443:443"
|
||
volumes:
|
||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||
- ./nginx/conf.d:/etc/nginx/conf.d:ro
|
||
- ./ssl:/etc/ssl:ro
|
||
- ./logs/nginx:/var/log/nginx
|
||
depends_on:
|
||
- datatools-pro
|
||
networks:
|
||
- datatools-network
|
||
|
||
redis:
|
||
image: redis:7-alpine
|
||
container_name: datatools-redis
|
||
restart: unless-stopped
|
||
ports:
|
||
- "6379:6379"
|
||
volumes:
|
||
- redis-data:/data
|
||
command: redis-server --appendonly yes
|
||
networks:
|
||
- datatools-network
|
||
|
||
volumes:
|
||
redis-data:
|
||
driver: local
|
||
|
||
networks:
|
||
datatools-network:
|
||
driver: bridge
|
||
```
|
||
|
||
### 4.3 环境变量配置
|
||
```bash
|
||
# .env - Docker Compose环境变量
|
||
COMPOSE_PROJECT_NAME=datatools-pro
|
||
|
||
# 应用配置
|
||
SECRET_KEY=your-super-secret-key-for-production
|
||
DEBUG=False
|
||
LOG_LEVEL=INFO
|
||
|
||
# 外部服务
|
||
CASSANDRA_HOSTS=cassandra-node1,cassandra-node2,cassandra-node3
|
||
REDIS_HOSTS=redis-node1,redis-node2,redis-node3
|
||
|
||
# 数据库
|
||
DATABASE_URL=/app/data/config_groups.db
|
||
|
||
# 监控
|
||
ENABLE_MONITORING=true
|
||
METRICS_PORT=9090
|
||
```
|
||
|
||
### 4.4 容器化部署脚本
|
||
```bash
|
||
#!/bin/bash
|
||
# deploy-docker.sh - Docker容器化部署脚本
|
||
|
||
set -e
|
||
|
||
PROJECT_NAME="datatools-pro"
|
||
DOCKER_COMPOSE_FILE="docker-compose.yml"
|
||
ENV_FILE=".env"
|
||
|
||
echo "开始Docker容器化部署..."
|
||
|
||
# 1. 检查Docker环境
|
||
if ! command -v docker &> /dev/null; then
|
||
echo "错误: Docker未安装"
|
||
exit 1
|
||
fi
|
||
|
||
if ! command -v docker-compose &> /dev/null; then
|
||
echo "错误: Docker Compose未安装"
|
||
exit 1
|
||
fi
|
||
|
||
# 2. 检查环境变量文件
|
||
if [ ! -f "$ENV_FILE" ]; then
|
||
echo "创建环境变量文件: $ENV_FILE"
|
||
cp .env.example $ENV_FILE
|
||
echo "请编辑 $ENV_FILE 文件并重新运行部署脚本"
|
||
exit 1
|
||
fi
|
||
|
||
# 3. 创建必要目录
|
||
mkdir -p {data,logs,backup,ssl,nginx/conf.d}
|
||
|
||
# 4. 构建镜像
|
||
echo "构建Docker镜像..."
|
||
docker-compose -f $DOCKER_COMPOSE_FILE build
|
||
|
||
# 5. 停止旧容器
|
||
echo "停止旧容器..."
|
||
docker-compose -f $DOCKER_COMPOSE_FILE down
|
||
|
||
# 6. 启动新容器
|
||
echo "启动新容器..."
|
||
docker-compose -f $DOCKER_COMPOSE_FILE up -d
|
||
|
||
# 7. 等待容器启动
|
||
echo "等待服务启动..."
|
||
sleep 30
|
||
|
||
# 8. 检查服务状态
|
||
echo "检查服务状态..."
|
||
docker-compose -f $DOCKER_COMPOSE_FILE ps
|
||
|
||
# 9. 健康检查
|
||
echo "执行健康检查..."
|
||
if curl -f http://localhost/api/health > /dev/null 2>&1; then
|
||
echo "✅ 部署成功! 服务已启动"
|
||
echo "访问地址: http://localhost"
|
||
else
|
||
echo "❌ 部署失败! 服务未正常启动"
|
||
echo "查看日志: docker-compose logs"
|
||
exit 1
|
||
fi
|
||
|
||
# 10. 显示有用信息
|
||
echo ""
|
||
echo "🚀 DataTools Pro 容器化部署完成!"
|
||
echo ""
|
||
echo "常用命令:"
|
||
echo " 查看日志: docker-compose logs -f"
|
||
echo " 重启服务: docker-compose restart"
|
||
echo " 停止服务: docker-compose down"
|
||
echo " 更新代码: git pull && docker-compose up -d --build"
|
||
echo ""
|
||
```
|
||
|
||
## 5. Kubernetes部署
|
||
|
||
### 5.1 Kubernetes资源清单
|
||
|
||
#### 5.1.1 ConfigMap配置
|
||
```yaml
|
||
# k8s/configmap.yaml
|
||
apiVersion: v1
|
||
kind: ConfigMap
|
||
metadata:
|
||
name: datatools-pro-config
|
||
namespace: datatools
|
||
data:
|
||
DEBUG: "False"
|
||
LOG_LEVEL: "INFO"
|
||
DATABASE_URL: "/app/data/config_groups.db"
|
||
CASSANDRA_HOSTS: "cassandra-service.database.svc.cluster.local"
|
||
REDIS_HOSTS: "redis-service.cache.svc.cluster.local"
|
||
WORKERS: "4"
|
||
HOST: "0.0.0.0"
|
||
PORT: "5000"
|
||
```
|
||
|
||
#### 5.1.2 Secret配置
|
||
```yaml
|
||
# k8s/secret.yaml
|
||
apiVersion: v1
|
||
kind: Secret
|
||
metadata:
|
||
name: datatools-pro-secret
|
||
namespace: datatools
|
||
type: Opaque
|
||
data:
|
||
SECRET_KEY: eW91ci1zdXBlci1zZWNyZXQta2V5LWZvci1wcm9kdWN0aW9u # base64 encoded
|
||
```
|
||
|
||
#### 5.1.3 PersistentVolume配置
|
||
```yaml
|
||
# k8s/pvc.yaml
|
||
apiVersion: v1
|
||
kind: PersistentVolumeClaim
|
||
metadata:
|
||
name: datatools-pro-data
|
||
namespace: datatools
|
||
spec:
|
||
accessModes:
|
||
- ReadWriteOnce
|
||
resources:
|
||
requests:
|
||
storage: 20Gi
|
||
storageClassName: fast-ssd
|
||
```
|
||
|
||
#### 5.1.4 Deployment配置
|
||
```yaml
|
||
# k8s/deployment.yaml
|
||
apiVersion: apps/v1
|
||
kind: Deployment
|
||
metadata:
|
||
name: datatools-pro
|
||
namespace: datatools
|
||
labels:
|
||
app: datatools-pro
|
||
version: v2.0.0
|
||
spec:
|
||
replicas: 3
|
||
selector:
|
||
matchLabels:
|
||
app: datatools-pro
|
||
template:
|
||
metadata:
|
||
labels:
|
||
app: datatools-pro
|
||
version: v2.0.0
|
||
spec:
|
||
containers:
|
||
- name: datatools-pro
|
||
image: datatools-pro:2.0.0
|
||
ports:
|
||
- containerPort: 5000
|
||
name: http
|
||
env:
|
||
- name: SECRET_KEY
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: datatools-pro-secret
|
||
key: SECRET_KEY
|
||
envFrom:
|
||
- configMapRef:
|
||
name: datatools-pro-config
|
||
volumeMounts:
|
||
- name: data-volume
|
||
mountPath: /app/data
|
||
- name: logs-volume
|
||
mountPath: /app/logs
|
||
resources:
|
||
requests:
|
||
memory: "512Mi"
|
||
cpu: "250m"
|
||
limits:
|
||
memory: "2Gi"
|
||
cpu: "1000m"
|
||
livenessProbe:
|
||
httpGet:
|
||
path: /api/health
|
||
port: 5000
|
||
initialDelaySeconds: 30
|
||
periodSeconds: 30
|
||
readinessProbe:
|
||
httpGet:
|
||
path: /api/health
|
||
port: 5000
|
||
initialDelaySeconds: 5
|
||
periodSeconds: 5
|
||
securityContext:
|
||
runAsNonRoot: true
|
||
runAsUser: 1000
|
||
readOnlyRootFilesystem: true
|
||
volumes:
|
||
- name: data-volume
|
||
persistentVolumeClaim:
|
||
claimName: datatools-pro-data
|
||
- name: logs-volume
|
||
emptyDir: {}
|
||
securityContext:
|
||
fsGroup: 1000
|
||
```
|
||
|
||
#### 5.1.5 Service配置
|
||
```yaml
|
||
# k8s/service.yaml
|
||
apiVersion: v1
|
||
kind: Service
|
||
metadata:
|
||
name: datatools-pro-service
|
||
namespace: datatools
|
||
labels:
|
||
app: datatools-pro
|
||
spec:
|
||
selector:
|
||
app: datatools-pro
|
||
ports:
|
||
- port: 80
|
||
targetPort: 5000
|
||
protocol: TCP
|
||
name: http
|
||
type: ClusterIP
|
||
```
|
||
|
||
#### 5.1.6 Ingress配置
|
||
```yaml
|
||
# k8s/ingress.yaml
|
||
apiVersion: networking.k8s.io/v1
|
||
kind: Ingress
|
||
metadata:
|
||
name: datatools-pro-ingress
|
||
namespace: datatools
|
||
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: "100m"
|
||
nginx.ingress.kubernetes.io/proxy-read-timeout: "120"
|
||
spec:
|
||
tls:
|
||
- hosts:
|
||
- datatools.yourdomain.com
|
||
secretName: datatools-pro-tls
|
||
rules:
|
||
- host: datatools.yourdomain.com
|
||
http:
|
||
paths:
|
||
- path: /
|
||
pathType: Prefix
|
||
backend:
|
||
service:
|
||
name: datatools-pro-service
|
||
port:
|
||
number: 80
|
||
```
|
||
|
||
### 5.2 Kubernetes部署脚本
|
||
```bash
|
||
#!/bin/bash
|
||
# deploy-k8s.sh - Kubernetes部署脚本
|
||
|
||
set -e
|
||
|
||
NAMESPACE="datatools"
|
||
KUBECTL_CMD="kubectl"
|
||
KUSTOMIZE_DIR="k8s"
|
||
|
||
echo "开始Kubernetes部署..."
|
||
|
||
# 1. 检查kubectl
|
||
if ! command -v kubectl &> /dev/null; then
|
||
echo "错误: kubectl未安装"
|
||
exit 1
|
||
fi
|
||
|
||
# 2. 检查集群连接
|
||
if ! kubectl cluster-info &> /dev/null; then
|
||
echo "错误: 无法连接到Kubernetes集群"
|
||
exit 1
|
||
fi
|
||
|
||
# 3. 创建命名空间
|
||
echo "创建命名空间: $NAMESPACE"
|
||
kubectl create namespace $NAMESPACE --dry-run=client -o yaml | kubectl apply -f -
|
||
|
||
# 4. 应用ConfigMap和Secret
|
||
echo "应用配置..."
|
||
kubectl apply -f $KUSTOMIZE_DIR/configmap.yaml
|
||
kubectl apply -f $KUSTOMIZE_DIR/secret.yaml
|
||
|
||
# 5. 应用存储
|
||
echo "应用存储配置..."
|
||
kubectl apply -f $KUSTOMIZE_DIR/pvc.yaml
|
||
|
||
# 6. 等待PVC绑定
|
||
echo "等待存储卷绑定..."
|
||
kubectl wait --for=condition=Bound pvc/datatools-pro-data -n $NAMESPACE --timeout=300s
|
||
|
||
# 7. 应用Deployment
|
||
echo "部署应用..."
|
||
kubectl apply -f $KUSTOMIZE_DIR/deployment.yaml
|
||
|
||
# 8. 等待Deployment就绪
|
||
echo "等待应用就绪..."
|
||
kubectl wait --for=condition=Available deployment/datatools-pro -n $NAMESPACE --timeout=300s
|
||
|
||
# 9. 应用Service
|
||
echo "创建服务..."
|
||
kubectl apply -f $KUSTOMIZE_DIR/service.yaml
|
||
|
||
# 10. 应用Ingress
|
||
if [ -f "$KUSTOMIZE_DIR/ingress.yaml" ]; then
|
||
echo "创建Ingress..."
|
||
kubectl apply -f $KUSTOMIZE_DIR/ingress.yaml
|
||
fi
|
||
|
||
# 11. 检查部署状态
|
||
echo "检查部署状态..."
|
||
kubectl get pods -n $NAMESPACE -l app=datatools-pro
|
||
kubectl get svc -n $NAMESPACE -l app=datatools-pro
|
||
|
||
# 12. 显示访问信息
|
||
echo ""
|
||
echo "🚀 Kubernetes部署完成!"
|
||
echo ""
|
||
echo "查看Pod状态: kubectl get pods -n $NAMESPACE"
|
||
echo "查看日志: kubectl logs -f deployment/datatools-pro -n $NAMESPACE"
|
||
echo "端口转发测试: kubectl port-forward service/datatools-pro-service 8080:80 -n $NAMESPACE"
|
||
echo ""
|
||
|
||
if [ -f "$KUSTOMIZE_DIR/ingress.yaml" ]; then
|
||
INGRESS_HOST=$(kubectl get ingress datatools-pro-ingress -n $NAMESPACE -o jsonpath='{.spec.rules[0].host}')
|
||
echo "访问地址: https://$INGRESS_HOST"
|
||
fi
|
||
```
|
||
|
||
### 5.3 HorizontalPodAutoscaler配置
|
||
```yaml
|
||
# k8s/hpa.yaml
|
||
apiVersion: autoscaling/v2
|
||
kind: HorizontalPodAutoscaler
|
||
metadata:
|
||
name: datatools-pro-hpa
|
||
namespace: datatools
|
||
spec:
|
||
scaleTargetRef:
|
||
apiVersion: apps/v1
|
||
kind: Deployment
|
||
name: datatools-pro
|
||
minReplicas: 2
|
||
maxReplicas: 10
|
||
metrics:
|
||
- type: Resource
|
||
resource:
|
||
name: cpu
|
||
target:
|
||
type: Utilization
|
||
averageUtilization: 70
|
||
- type: Resource
|
||
resource:
|
||
name: memory
|
||
target:
|
||
type: Utilization
|
||
averageUtilization: 80
|
||
behavior:
|
||
scaleDown:
|
||
stabilizationWindowSeconds: 300
|
||
policies:
|
||
- type: Percent
|
||
value: 10
|
||
periodSeconds: 60
|
||
scaleUp:
|
||
stabilizationWindowSeconds: 60
|
||
policies:
|
||
- type: Percent
|
||
value: 50
|
||
periodSeconds: 60
|
||
```
|
||
|
||
## 6. 监控和日志
|
||
|
||
### 6.1 应用监控配置
|
||
```python
|
||
# monitoring.py - 应用监控模块
|
||
from prometheus_client import Counter, Histogram, Gauge, generate_latest, CONTENT_TYPE_LATEST
|
||
from flask import Response
|
||
import time
|
||
import psutil
|
||
import sqlite3
|
||
|
||
# 定义监控指标
|
||
REQUEST_COUNT = Counter('datatools_requests_total', 'Total requests', ['method', 'endpoint', 'status'])
|
||
REQUEST_LATENCY = Histogram('datatools_request_duration_seconds', 'Request latency')
|
||
ACTIVE_CONNECTIONS = Gauge('datatools_active_connections', 'Active database connections')
|
||
QUERY_EXECUTION_TIME = Histogram('datatools_query_duration_seconds', 'Query execution time', ['query_type'])
|
||
|
||
# 系统资源指标
|
||
SYSTEM_CPU_USAGE = Gauge('datatools_system_cpu_usage_percent', 'System CPU usage')
|
||
SYSTEM_MEMORY_USAGE = Gauge('datatools_system_memory_usage_percent', 'System memory usage')
|
||
DATABASE_SIZE = Gauge('datatools_database_size_bytes', 'Database file size')
|
||
|
||
def init_monitoring(app):
|
||
"""初始化监控"""
|
||
|
||
@app.before_request
|
||
def before_request():
|
||
"""请求前处理"""
|
||
g.start_time = time.time()
|
||
|
||
@app.after_request
|
||
def after_request(response):
|
||
"""请求后处理"""
|
||
if hasattr(g, 'start_time'):
|
||
duration = time.time() - g.start_time
|
||
REQUEST_LATENCY.observe(duration)
|
||
REQUEST_COUNT.labels(
|
||
method=request.method,
|
||
endpoint=request.endpoint or 'unknown',
|
||
status=response.status_code
|
||
).inc()
|
||
|
||
return response
|
||
|
||
@app.route('/metrics')
|
||
def metrics():
|
||
"""Prometheus指标端点"""
|
||
# 更新系统指标
|
||
update_system_metrics()
|
||
|
||
return Response(generate_latest(), mimetype=CONTENT_TYPE_LATEST)
|
||
|
||
def update_system_metrics():
|
||
"""更新系统指标"""
|
||
# CPU使用率
|
||
cpu_percent = psutil.cpu_percent(interval=1)
|
||
SYSTEM_CPU_USAGE.set(cpu_percent)
|
||
|
||
# 内存使用率
|
||
memory = psutil.virtual_memory()
|
||
SYSTEM_MEMORY_USAGE.set(memory.percent)
|
||
|
||
# 数据库大小
|
||
try:
|
||
import os
|
||
db_path = 'config_groups.db'
|
||
if os.path.exists(db_path):
|
||
db_size = os.path.getsize(db_path)
|
||
DATABASE_SIZE.set(db_size)
|
||
except Exception:
|
||
pass
|
||
|
||
def record_query_time(query_type, duration):
|
||
"""记录查询执行时间"""
|
||
QUERY_EXECUTION_TIME.labels(query_type=query_type).observe(duration)
|
||
```
|
||
|
||
### 6.2 日志配置
|
||
```python
|
||
# logging_config.py - 日志配置
|
||
import logging
|
||
import logging.handlers
|
||
import os
|
||
from datetime import datetime
|
||
|
||
def setup_logging(app):
|
||
"""设置应用日志"""
|
||
|
||
# 创建日志目录
|
||
log_dir = app.config.get('LOG_DIR', 'logs')
|
||
os.makedirs(log_dir, exist_ok=True)
|
||
|
||
# 配置日志格式
|
||
formatter = logging.Formatter(
|
||
'%(asctime)s [%(levelname)s] %(name)s: %(message)s'
|
||
)
|
||
|
||
# 应用日志
|
||
app_handler = logging.handlers.RotatingFileHandler(
|
||
os.path.join(log_dir, 'datatools.log'),
|
||
maxBytes=10*1024*1024, # 10MB
|
||
backupCount=10
|
||
)
|
||
app_handler.setFormatter(formatter)
|
||
app_handler.setLevel(logging.INFO)
|
||
|
||
# 错误日志
|
||
error_handler = logging.handlers.RotatingFileHandler(
|
||
os.path.join(log_dir, 'error.log'),
|
||
maxBytes=10*1024*1024, # 10MB
|
||
backupCount=5
|
||
)
|
||
error_handler.setFormatter(formatter)
|
||
error_handler.setLevel(logging.ERROR)
|
||
|
||
# 访问日志
|
||
access_handler = logging.handlers.RotatingFileHandler(
|
||
os.path.join(log_dir, 'access.log'),
|
||
maxBytes=10*1024*1024, # 10MB
|
||
backupCount=10
|
||
)
|
||
access_formatter = logging.Formatter(
|
||
'%(asctime)s %(remote_addr)s "%(method)s %(url)s" %(status_code)s %(response_size)s "%(user_agent)s"'
|
||
)
|
||
access_handler.setFormatter(access_formatter)
|
||
|
||
# 配置Flask应用日志
|
||
app.logger.addHandler(app_handler)
|
||
app.logger.addHandler(error_handler)
|
||
app.logger.setLevel(logging.INFO)
|
||
|
||
# 配置访问日志
|
||
access_logger = logging.getLogger('werkzeug')
|
||
access_logger.addHandler(access_handler)
|
||
|
||
# 配置第三方库日志级别
|
||
logging.getLogger('cassandra').setLevel(logging.WARNING)
|
||
logging.getLogger('redis').setLevel(logging.WARNING)
|
||
logging.getLogger('urllib3').setLevel(logging.WARNING)
|
||
```
|
||
|
||
### 6.3 Prometheus配置
|
||
```yaml
|
||
# prometheus.yml
|
||
global:
|
||
scrape_interval: 15s
|
||
evaluation_interval: 15s
|
||
|
||
rule_files:
|
||
- "datatools_rules.yml"
|
||
|
||
scrape_configs:
|
||
- job_name: 'datatools-pro'
|
||
static_configs:
|
||
- targets: ['localhost:5000']
|
||
metrics_path: '/metrics'
|
||
scrape_interval: 30s
|
||
scrape_timeout: 10s
|
||
|
||
alerting:
|
||
alertmanagers:
|
||
- static_configs:
|
||
- targets:
|
||
- alertmanager:9093
|
||
```
|
||
|
||
### 6.4 Grafana仪表板配置
|
||
```json
|
||
{
|
||
"dashboard": {
|
||
"id": null,
|
||
"title": "DataTools Pro Monitoring",
|
||
"tags": ["datatools", "monitoring"],
|
||
"timezone": "browser",
|
||
"panels": [
|
||
{
|
||
"id": 1,
|
||
"title": "Request Rate",
|
||
"type": "graph",
|
||
"targets": [
|
||
{
|
||
"expr": "rate(datatools_requests_total[5m])",
|
||
"legendFormat": "{{method}} {{endpoint}}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": 2,
|
||
"title": "Request Latency",
|
||
"type": "graph",
|
||
"targets": [
|
||
{
|
||
"expr": "histogram_quantile(0.95, datatools_request_duration_seconds_bucket)",
|
||
"legendFormat": "95th percentile"
|
||
},
|
||
{
|
||
"expr": "histogram_quantile(0.50, datatools_request_duration_seconds_bucket)",
|
||
"legendFormat": "50th percentile"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": 3,
|
||
"title": "System Resources",
|
||
"type": "graph",
|
||
"targets": [
|
||
{
|
||
"expr": "datatools_system_cpu_usage_percent",
|
||
"legendFormat": "CPU Usage %"
|
||
},
|
||
{
|
||
"expr": "datatools_system_memory_usage_percent",
|
||
"legendFormat": "Memory Usage %"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": 4,
|
||
"title": "Query Performance",
|
||
"type": "graph",
|
||
"targets": [
|
||
{
|
||
"expr": "histogram_quantile(0.95, datatools_query_duration_seconds_bucket)",
|
||
"legendFormat": "{{query_type}} 95th percentile"
|
||
}
|
||
]
|
||
}
|
||
],
|
||
"time": {
|
||
"from": "now-1h",
|
||
"to": "now"
|
||
},
|
||
"refresh": "30s"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 7. 备份和恢复
|
||
|
||
### 7.1 数据备份脚本
|
||
```bash
|
||
#!/bin/bash
|
||
# backup.sh - 数据备份脚本
|
||
|
||
set -e
|
||
|
||
# 配置变量
|
||
BACKUP_DIR="/opt/datatools/backup"
|
||
DATA_DIR="/opt/datatools/data"
|
||
LOG_DIR="/opt/datatools/logs"
|
||
RETENTION_DAYS=30
|
||
DATE=$(date +%Y%m%d_%H%M%S)
|
||
BACKUP_NAME="datatools_backup_$DATE"
|
||
|
||
echo "开始数据备份: $BACKUP_NAME"
|
||
|
||
# 创建备份目录
|
||
mkdir -p $BACKUP_DIR/$BACKUP_NAME
|
||
|
||
# 1. 备份SQLite数据库
|
||
echo "备份SQLite数据库..."
|
||
if [ -f "$DATA_DIR/config_groups.db" ]; then
|
||
sqlite3 $DATA_DIR/config_groups.db ".backup $BACKUP_DIR/$BACKUP_NAME/config_groups.db"
|
||
sqlite3 $DATA_DIR/config_groups.db ".dump" > $BACKUP_DIR/$BACKUP_NAME/config_groups.sql
|
||
fi
|
||
|
||
# 2. 备份配置文件
|
||
echo "备份配置文件..."
|
||
cp -r /opt/datatools/app/config.py $BACKUP_DIR/$BACKUP_NAME/ 2>/dev/null || true
|
||
cp -r /opt/datatools/.env $BACKUP_DIR/$BACKUP_NAME/ 2>/dev/null || true
|
||
|
||
# 3. 备份日志文件(最近7天)
|
||
echo "备份日志文件..."
|
||
find $LOG_DIR -name "*.log" -mtime -7 -exec cp {} $BACKUP_DIR/$BACKUP_NAME/ \; 2>/dev/null || true
|
||
|
||
# 4. 创建备份信息文件
|
||
cat > $BACKUP_DIR/$BACKUP_NAME/backup_info.txt << EOF
|
||
备份时间: $(date)
|
||
备份版本: DataTools Pro 2.0
|
||
系统信息: $(uname -a)
|
||
Python版本: $(python3 --version)
|
||
数据库大小: $(du -h $DATA_DIR/config_groups.db 2>/dev/null | cut -f1 || echo "N/A")
|
||
备份大小: $(du -sh $BACKUP_DIR/$BACKUP_NAME | cut -f1)
|
||
EOF
|
||
|
||
# 5. 压缩备份
|
||
echo "压缩备份文件..."
|
||
cd $BACKUP_DIR
|
||
tar -czf $BACKUP_NAME.tar.gz $BACKUP_NAME
|
||
rm -rf $BACKUP_NAME
|
||
|
||
# 6. 清理旧备份
|
||
echo "清理旧备份..."
|
||
find $BACKUP_DIR -name "datatools_backup_*.tar.gz" -mtime +$RETENTION_DAYS -delete
|
||
|
||
# 7. 验证备份
|
||
if [ -f "$BACKUP_DIR/$BACKUP_NAME.tar.gz" ]; then
|
||
BACKUP_SIZE=$(du -h $BACKUP_DIR/$BACKUP_NAME.tar.gz | cut -f1)
|
||
echo "✅ 备份完成: $BACKUP_NAME.tar.gz ($BACKUP_SIZE)"
|
||
else
|
||
echo "❌ 备份失败!"
|
||
exit 1
|
||
fi
|
||
|
||
# 8. 可选: 上传到远程存储
|
||
if [ -n "$BACKUP_REMOTE_PATH" ]; then
|
||
echo "上传备份到远程存储..."
|
||
# rsync -avz $BACKUP_DIR/$BACKUP_NAME.tar.gz $BACKUP_REMOTE_PATH/
|
||
# aws s3 cp $BACKUP_DIR/$BACKUP_NAME.tar.gz s3://your-backup-bucket/
|
||
fi
|
||
|
||
echo "备份脚本执行完成"
|
||
```
|
||
|
||
### 7.2 数据恢复脚本
|
||
```bash
|
||
#!/bin/bash
|
||
# restore.sh - 数据恢复脚本
|
||
|
||
set -e
|
||
|
||
if [ $# -eq 0 ]; then
|
||
echo "用法: $0 <backup_file>"
|
||
echo "示例: $0 /opt/datatools/backup/datatools_backup_20240805_100000.tar.gz"
|
||
exit 1
|
||
fi
|
||
|
||
BACKUP_FILE="$1"
|
||
DATA_DIR="/opt/datatools/data"
|
||
RESTORE_DIR="/tmp/datatools_restore_$$"
|
||
|
||
echo "开始数据恢复: $BACKUP_FILE"
|
||
|
||
# 1. 验证备份文件
|
||
if [ ! -f "$BACKUP_FILE" ]; then
|
||
echo "错误: 备份文件不存在: $BACKUP_FILE"
|
||
exit 1
|
||
fi
|
||
|
||
# 2. 停止服务
|
||
echo "停止DataTools Pro服务..."
|
||
sudo systemctl stop datatools-pro || true
|
||
|
||
# 3. 备份当前数据
|
||
echo "备份当前数据..."
|
||
mkdir -p $DATA_DIR.bak
|
||
cp -r $DATA_DIR/* $DATA_DIR.bak/ 2>/dev/null || true
|
||
|
||
# 4. 解压备份文件
|
||
echo "解压备份文件..."
|
||
mkdir -p $RESTORE_DIR
|
||
cd $RESTORE_DIR
|
||
tar -xzf $BACKUP_FILE
|
||
|
||
# 5. 恢复数据库
|
||
echo "恢复数据库..."
|
||
BACKUP_DB=$(find $RESTORE_DIR -name "config_groups.db" | head -1)
|
||
if [ -f "$BACKUP_DB" ]; then
|
||
cp $BACKUP_DB $DATA_DIR/config_groups.db
|
||
chown datatools:datatools $DATA_DIR/config_groups.db
|
||
chmod 644 $DATA_DIR/config_groups.db
|
||
echo "✅ 数据库恢复完成"
|
||
else
|
||
echo "❌ 未找到数据库备份文件"
|
||
fi
|
||
|
||
# 6. 恢复配置文件
|
||
echo "恢复配置文件..."
|
||
BACKUP_CONFIG=$(find $RESTORE_DIR -name "config.py" | head -1)
|
||
if [ -f "$BACKUP_CONFIG" ]; then
|
||
cp $BACKUP_CONFIG /opt/datatools/app/config.py
|
||
chown datatools:datatools /opt/datatools/app/config.py
|
||
echo "✅ 配置文件恢复完成"
|
||
fi
|
||
|
||
BACKUP_ENV=$(find $RESTORE_DIR -name ".env" | head -1)
|
||
if [ -f "$BACKUP_ENV" ]; then
|
||
cp $BACKUP_ENV /opt/datatools/.env
|
||
chown datatools:datatools /opt/datatools/.env
|
||
chmod 600 /opt/datatools/.env
|
||
echo "✅ 环境变量文件恢复完成"
|
||
fi
|
||
|
||
# 7. 验证数据库完整性
|
||
echo "验证数据库完整性..."
|
||
if sqlite3 $DATA_DIR/config_groups.db "PRAGMA integrity_check;" | grep -q "ok"; then
|
||
echo "✅ 数据库完整性检查通过"
|
||
else
|
||
echo "❌ 数据库完整性检查失败"
|
||
echo "恢复原始数据..."
|
||
cp -r $DATA_DIR.bak/* $DATA_DIR/
|
||
exit 1
|
||
fi
|
||
|
||
# 8. 启动服务
|
||
echo "启动DataTools Pro服务..."
|
||
sudo systemctl start datatools-pro
|
||
|
||
# 9. 等待服务启动
|
||
echo "等待服务启动..."
|
||
sleep 10
|
||
|
||
# 10. 健康检查
|
||
if curl -f http://localhost:5000/api/health > /dev/null 2>&1; then
|
||
echo "✅ 恢复完成! 服务正常运行"
|
||
rm -rf $RESTORE_DIR
|
||
rm -rf $DATA_DIR.bak
|
||
else
|
||
echo "❌ 服务启动失败,回滚到原始数据"
|
||
sudo systemctl stop datatools-pro
|
||
rm -rf $DATA_DIR/*
|
||
cp -r $DATA_DIR.bak/* $DATA_DIR/
|
||
sudo systemctl start datatools-pro
|
||
rm -rf $RESTORE_DIR
|
||
exit 1
|
||
fi
|
||
|
||
echo "数据恢复脚本执行完成"
|
||
```
|
||
|
||
### 7.3 自动化备份Cron任务
|
||
```bash
|
||
# 添加定时备份任务
|
||
# crontab -e
|
||
|
||
# 每天凌晨2点执行备份
|
||
0 2 * * * /opt/datatools/scripts/backup.sh >> /opt/datatools/logs/backup.log 2>&1
|
||
|
||
# 每周日凌晨3点清理旧日志
|
||
0 3 * * 0 find /opt/datatools/logs -name "*.log.*" -mtime +7 -delete
|
||
|
||
# 每月1号检查数据库完整性
|
||
0 4 1 * * sqlite3 /opt/datatools/data/config_groups.db "PRAGMA integrity_check;" >> /opt/datatools/logs/db_check.log 2>&1
|
||
```
|
||
|
||
---
|
||
|
||
**版本**: v1.0
|
||
**更新日期**: 2024-08-05
|
||
**维护者**: DataTools Pro Team |