生产环境部署指南

生产环境部署指南

本指南提供 PowerWiki 的企业级生产环境部署方案,包括高可用、性能优化、安全加固等。

架构设计

推荐架构

┌─────────────────────────────────────────────────────┐
│                    用户访问                          │
└────────────────────┬────────────────────────────────┘
                     │
┌────────────────────▼────────────────────────────────┐
│              CDN / 负载均衡器                        │
│         (Cloudflare / Nginx / HAProxy)              │
└────────────────────┬────────────────────────────────┘
                     │
        ┌────────────┼────────────┐
        │            │            │
┌───────▼──┐  ┌──────▼──┐  ┌─────▼────┐
│ PowerWiki│  │PowerWiki│  │PowerWiki │
│ 实例 1   │  │ 实例 2  │  │ 实例 3   │
└───────┬──┘  └──────┬──┘  └─────┬────┘
        │            │            │
        └────────────┼────────────┘
                     │
        ┌────────────▼────────────┐
        │   共享存储 / 数据卷      │
        │  (NFS / Docker Volume)  │
        └────────────┬────────────┘
                     │
        ┌────────────▼────────────┐
        │   Git 仓库 / 缓存       │
        │  (GitHub / GitLab)      │
        └─────────────────────────┘

部署方案对比

方案 可用性 性能 成本 复杂度 适用场景
单机 Docker 小型团队
Docker Swarm 中型企业
Kubernetes 大型企业

单机生产部署

使用 Docker Compose

创建 docker-compose.prod.yml

version: '3.8'

services:
  powerwiki:
    image: sayunchuan/powerwiki:latest
    container_name: powerwiki
    restart: always
    ports:
      - "3150:3150"
    environment:
      - NODE_ENV=production
      - DATA_DIR=/app/data
      - GIT_CACHE_DIR=/app/cache
      - LANG=zh-CN
    volumes:
      - ./config.json:/app/config.json:ro
      - powerwiki_data:/app/data
      - powerwiki_cache:/app/cache
    networks:
      - powerwiki-net
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3150"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

  nginx:
    image: nginx:alpine
    container_name: powerwiki-nginx
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
      - ./logs/nginx:/var/log/nginx
    depends_on:
      - powerwiki
    networks:
      - powerwiki-net
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

volumes:
  powerwiki_data:
    driver: local
  powerwiki_cache:
    driver: local

networks:
  powerwiki-net:
    driver: bridge

Nginx 配置

创建 nginx.conf

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
    use epoll;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    client_max_body_size 20M;

    # Gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml text/javascript 
               application/json application/javascript application/xml+rss 
               application/rss+xml font/truetype font/opentype 
               application/vnd.ms-fontobject image/svg+xml;

    # 缓存设置
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=powerwiki_cache:10m 
                     max_size=1g inactive=60m use_temp_path=off;

    upstream powerwiki {
        server powerwiki:3150;
    }

    server {
        listen 80;
        server_name _;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name wiki.example.com;

        ssl_certificate /etc/nginx/ssl/cert.pem;
        ssl_certificate_key /etc/nginx/ssl/key.pem;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;

        # 安全头
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header Referrer-Policy "strict-origin-when-cross-origin" always;

        location / {
            proxy_pass http://powerwiki;
            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_set_header X-Forwarded-Host $server_name;
            
            # 缓存设置
            proxy_cache powerwiki_cache;
            proxy_cache_valid 200 1h;
            proxy_cache_use_stale error timeout invalid_header updating;
            add_header X-Cache-Status $upstream_cache_status;
        }

        # 静态文件缓存
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
            proxy_pass http://powerwiki;
            proxy_cache powerwiki_cache;
            proxy_cache_valid 200 30d;
            expires 30d;
            add_header Cache-Control "public, immutable";
        }

        # 健康检查
        location /health {
            access_log off;
            proxy_pass http://powerwiki;
        }
    }
}

启动生产环境

# 启动服务
docker-compose -f docker-compose.prod.yml up -d

# 查看日志
docker-compose -f docker-compose.prod.yml logs -f

# 停止服务
docker-compose -f docker-compose.prod.yml down

高可用部署

使用 Docker Swarm

初始化 Swarm:

docker swarm init

创建 docker-compose.swarm.yml

version: '3.8'

services:
  powerwiki:
    image: sayunchuan/powerwiki:latest
    deploy:
      replicas: 3
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
      update_config:
        parallelism: 1
        delay: 10s
    environment:
      - NODE_ENV=production
      - DATA_DIR=/app/data
      - GIT_CACHE_DIR=/app/cache
    volumes:
      - ./config.json:/app/config.json:ro
      - powerwiki_data:/app/data
      - powerwiki_cache:/app/cache
    networks:
      - powerwiki-net

  nginx:
    image: nginx:alpine
    deploy:
      replicas: 2
      restart_policy:
        condition: on-failure
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    networks:
      - powerwiki-net

volumes:
  powerwiki_data:
    driver: local
  powerwiki_cache:
    driver: local

networks:
  powerwiki-net:
    driver: overlay

部署:

docker stack deploy -c docker-compose.swarm.yml powerwiki

Kubernetes 部署

创建 Namespace

kubectl create namespace powerwiki

创建 ConfigMap

kubectl create configmap powerwiki-config \
  --from-file=config.json \
  -n powerwiki

创建 Deployment

创建 k8s-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: powerwiki
  namespace: powerwiki
spec:
  replicas: 3
  selector:
    matchLabels:
      app: powerwiki
  template:
    metadata:
      labels:
        app: powerwiki
    spec:
      containers:
      - name: powerwiki
        image: sayunchuan/powerwiki:latest
        ports:
        - containerPort: 3150
        env:
        - name: NODE_ENV
          value: "production"
        - name: DATA_DIR
          value: "/app/data"
        - name: GIT_CACHE_DIR
          value: "/app/cache"
        volumeMounts:
        - name: config
          mountPath: /app/config.json
          subPath: config.json
        - name: data
          mountPath: /app/data
        - name: cache
          mountPath: /app/cache
        livenessProbe:
          httpGet:
            path: /
            port: 3150
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /
            port: 3150
          initialDelaySeconds: 5
          periodSeconds: 5
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
      volumes:
      - name: config
        configMap:
          name: powerwiki-config
      - name: data
        persistentVolumeClaim:
          claimName: powerwiki-data
      - name: cache
        persistentVolumeClaim:
          claimName: powerwiki-cache

创建 Service

apiVersion: v1
kind: Service
metadata:
  name: powerwiki
  namespace: powerwiki
spec:
  selector:
    app: powerwiki
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3150
  type: LoadBalancer

创建 Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: powerwiki
  namespace: powerwiki
spec:
  ingressClassName: nginx
  rules:
  - host: wiki.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: powerwiki
            port:
              number: 80
  tls:
  - hosts:
    - wiki.example.com
    secretName: powerwiki-tls

部署:

kubectl apply -f k8s-deployment.yaml
kubectl apply -f k8s-service.yaml
kubectl apply -f k8s-ingress.yaml

监控和告警

使用 Prometheus 监控

创建 prometheus.yml

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'powerwiki'
    static_configs:
      - targets: ['localhost:3150']

使用 Grafana 可视化

docker run -d -p 3000:3000 grafana/grafana

备份和恢复

自动备份脚本

创建 backup.sh

#!/bin/bash

BACKUP_DIR="/backups"
DATE=$(date +%Y%m%d_%H%M%S)

# 备份数据卷
docker run --rm \
  -v powerwiki_data:/data \
  -v $BACKUP_DIR:/backup \
  alpine tar czf /backup/data_$DATE.tar.gz -C /data .

# 备份缓存
docker run --rm \
  -v powerwiki_cache:/cache \
  -v $BACKUP_DIR:/backup \
  alpine tar czf /backup/cache_$DATE.tar.gz -C /cache .

# 备份配置
cp config.json $BACKUP_DIR/config_$DATE.json

# 清理旧备份(保留 7 天)
find $BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete

设置定时任务:

# 每天凌晨 2 点执行备份
0 2 * * * /path/to/backup.sh

安全加固

SSL/TLS 证书

使用 Let's Encrypt:

# 安装 Certbot
sudo apt-get install certbot python3-certbot-nginx

# 获取证书
sudo certbot certonly --standalone -d wiki.example.com

# 自动续期
sudo systemctl enable certbot.timer

防火墙配置

# 允许 HTTP 和 HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# 限制 SSH 访问
sudo ufw allow from 192.168.1.0/24 to any port 22

定期更新

# 更新 Docker 镜像
docker pull sayunchuan/powerwiki:latest

# 重启容器
docker-compose -f docker-compose.prod.yml up -d

性能优化

资源限制

resources:
  requests:
    memory: "256Mi"
    cpu: "250m"
  limits:
    memory: "512Mi"
    cpu: "500m"

自动扩展

# Docker Swarm 自动扩展
docker service update --limit-memory 512m powerwiki_powerwiki

故障恢复

健康检查

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:3150"]
  interval: 30s
  timeout: 10s
  retries: 3

自动重启

restart_policy:
  condition: on-failure
  delay: 5s
  max_attempts: 3

提示: 生产环境部署需要考虑高可用、性能、安全等多个方面。建议根据实际需求选择合适的部署方案。

更新时间:2026年2月24日