Docker 部署

本指南介绍使用 Docker 部署 MCPHub,包括开发和生产配置。

Docker 快速开始

使用预构建镜像

# 拉取最新镜像
docker pull mcphub/mcphub:latest

# 使用默认配置运行
docker run -d \
  --name mcphub \
  -p 3000:3000 \
  -v $(pwd)/mcp_settings.json:/app/mcp_settings.json \
  mcphub/mcphub:latest

从源码构建

# 克隆仓库
git clone https://github.com/your-username/mcphub.git
cd mcphub

# 构建 Docker 镜像
docker build -t mcphub:local .

# 运行容器
docker run -d \
  --name mcphub \
  -p 3000:3000 \
  -v $(pwd)/mcp_settings.json:/app/mcp_settings.json \
  mcphub:local

Docker Compose 设置

基本配置

创建 docker-compose.yml 文件:
version: '3.8'

services:
  mcphub:
    image: mcphub/mcphub:latest
    # 本地开发时使用:
    # build: .
    container_name: mcphub
    ports:
      - '3000:3000'
    environment:
      - NODE_ENV=production
      - PORT=3000
      - JWT_SECRET=${JWT_SECRET:-your-jwt-secret}
      - DATABASE_URL=postgresql://mcphub:password@postgres:5432/mcphub
    volumes:
      - ./mcp_settings.json:/app/mcp_settings.json:ro
      - ./servers.json:/app/servers.json:ro
      - mcphub_data:/app/data
    depends_on:
      postgres:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - mcphub-network

  postgres:
    image: postgres:15-alpine
    container_name: mcphub-postgres
    environment:
      - POSTGRES_DB=mcphub
      - POSTGRES_USER=mcphub
      - POSTGRES_PASSWORD=password
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro
    ports:
      - '5432:5432'
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U mcphub -d mcphub']
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    networks:
      - mcphub-network

volumes:
  postgres_data:
  mcphub_data:

networks:
  mcphub-network:
    driver: bridge

生产配置(包含 Nginx)

version: '3.8'

services:
  nginx:
    image: nginx:alpine
    container_name: mcphub-nginx
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
      - nginx_logs:/var/log/nginx
    depends_on:
      - mcphub
    restart: unless-stopped
    networks:
      - mcphub-network

  mcphub:
    image: mcphub/mcphub:latest
    container_name: mcphub-app
    expose:
      - '3000'
    environment:
      - NODE_ENV=production
      - PORT=3000
      - JWT_SECRET=${JWT_SECRET}
      - JWT_EXPIRES_IN=${JWT_EXPIRES_IN:-24h}
      - DATABASE_URL=postgresql://mcphub:${POSTGRES_PASSWORD}@postgres:5432/mcphub
      - OPENAI_API_KEY=${OPENAI_API_KEY}
      - REDIS_URL=redis://redis:6379
    volumes:
      - ./mcp_settings.json:/app/mcp_settings.json:ro
      - ./servers.json:/app/servers.json:ro
      - mcphub_data:/app/data
      - mcphub_logs:/app/logs
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - mcphub-network
    healthcheck:
      test: ['CMD', 'wget', '--quiet', '--tries=1', '--spider', 'http://localhost:3000/health']
      interval: 30s
      timeout: 10s
      retries: 3

  postgres:
    image: postgres:15-alpine
    container_name: mcphub-postgres
    environment:
      - POSTGRES_DB=mcphub
      - POSTGRES_USER=mcphub
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./backups:/backups
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U mcphub -d mcphub']
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    networks:
      - mcphub-network

  redis:
    image: redis:7-alpine
    container_name: mcphub-redis
    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data
    healthcheck:
      test: ['CMD', 'redis-cli', 'ping']
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    networks:
      - mcphub-network

volumes:
  postgres_data:
  redis_data:
  mcphub_data:
  mcphub_logs:
  nginx_logs:

networks:
  mcphub-network:
    driver: bridge

环境变量

为 Docker Compose 创建 .env 文件:
# 应用程序
NODE_ENV=production
JWT_SECRET=your-super-secret-jwt-key-change-this
JWT_EXPIRES_IN=24h

# 数据库
POSTGRES_PASSWORD=your-secure-database-password

# Redis
REDIS_PASSWORD=your-secure-redis-password

# 外部 API
OPENAI_API_KEY=your-openai-api-key

# 可选:自定义端口
# PORT=3000

开发设置

开发 Docker Compose

创建 docker-compose.dev.yml
version: '3.8'

services:
  mcphub-dev:
    build:
      context: .
      dockerfile: Dockerfile.dev
    container_name: mcphub-dev
    ports:
      - '3000:3000'
      - '5173:5173' # 前端开发服务器
      - '9229:9229' # 调试端口
    environment:
      - NODE_ENV=development
      - PORT=3000
      - DATABASE_URL=postgresql://mcphub:password@postgres:5432/mcphub
    volumes:
      - .:/app
      - /app/node_modules
      - /app/frontend/node_modules
    depends_on:
      - postgres
    command: pnpm dev
    networks:
      - mcphub-dev

  postgres:
    image: postgres:15-alpine
    container_name: mcphub-postgres-dev
    environment:
      - POSTGRES_DB=mcphub
      - POSTGRES_USER=mcphub
      - POSTGRES_PASSWORD=password
    ports:
      - '5432:5432'
    volumes:
      - postgres_dev_data:/var/lib/postgresql/data
    networks:
      - mcphub-dev

volumes:
  postgres_dev_data:

networks:
  mcphub-dev:
    driver: bridge

开发 Dockerfile

创建 Dockerfile.dev
FROM node:20-alpine

# 安装 pnpm
RUN npm install -g pnpm

# 设置工作目录
WORKDIR /app

# 复制包文件
COPY package.json pnpm-lock.yaml ./
COPY frontend/package.json ./frontend/

# 安装依赖
RUN pnpm install

# 复制源代码
COPY . .

# 暴露端口
EXPOSE 3000 5173 9229

# 启动开发服务器
CMD ["pnpm", "dev"]

运行应用程序

开发模式

# 启动开发环境
docker-compose -f docker-compose.dev.yml up -d

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

# 停止开发环境
docker-compose -f docker-compose.dev.yml down

生产模式

# 启动生产环境
docker-compose up -d

# 查看日志
docker-compose logs -f mcphub

# 停止生产环境
docker-compose down

配置管理

MCP 设置卷挂载

创建您的 mcp_settings.json
{
  "mcpServers": {
    "fetch": {
      "command": "uvx",
      "args": ["mcp-server-fetch"]
    },
    "playwright": {
      "command": "npx",
      "args": ["@playwright/mcp@latest", "--headless"]
    },
    "amap": {
      "command": "npx",
      "args": ["-y", "@amap/amap-maps-mcp-server"],
      "env": {
        "AMAP_MAPS_API_KEY": "your-api-key"
      }
    }
  }
}

密钥管理

对于生产环境,使用 Docker 密钥:
version: '3.8'

services:
  mcphub:
    image: mcphub/mcphub:latest
    environment:
      - JWT_SECRET_FILE=/run/secrets/jwt_secret
      - DATABASE_PASSWORD_FILE=/run/secrets/db_password
    secrets:
      - jwt_secret
      - db_password

secrets:
  jwt_secret:
    file: ./secrets/jwt_secret.txt
  db_password:
    file: ./secrets/db_password.txt

数据持久化

数据库备份

docker-compose.yml 中添加备份服务:
services:
  backup:
    image: postgres:15-alpine
    container_name: mcphub-backup
    environment:
      - PGPASSWORD=${POSTGRES_PASSWORD}
    volumes:
      - ./backups:/backups
      - ./scripts/backup.sh:/backup.sh:ro
    command: /bin/sh -c "chmod +x /backup.sh && /backup.sh"
    depends_on:
      - postgres
    profiles:
      - backup
    networks:
      - mcphub-network
创建 scripts/backup.sh
#!/bin/sh
BACKUP_FILE="/backups/mcphub_$(date +%Y%m%d_%H%M%S).sql"
pg_dump -h postgres -U mcphub -d mcphub > "$BACKUP_FILE"
echo "备份已创建:$BACKUP_FILE"

# 只保留最近 7 天的备份
find /backups -name "mcphub_*.sql" -mtime +7 -delete
运行备份:
docker-compose --profile backup run --rm backup

监控和健康检查

健康检查端点

在您的应用程序中添加:
// 在您的 Express 应用中
app.get('/health', (req, res) => {
  res.json({
    status: 'healthy',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    memory: process.memoryUsage(),
    version: process.env.npm_package_version,
  });
});

Docker 健康检查

services:
  mcphub:
    # ... 其他配置
    healthcheck:
      test: ['CMD', 'wget', '--quiet', '--tries=1', '--spider', 'http://localhost:3000/health']
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

使用 Watchtower 监控

添加自动更新:
services:
  watchtower:
    image: containrrr/watchtower
    container_name: mcphub-watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - WATCHTOWER_CLEANUP=true
      - WATCHTOWER_POLL_INTERVAL=3600
      - WATCHTOWER_INCLUDE_STOPPED=true
    restart: unless-stopped

故障排除

常见问题

容器启动失败:使用 docker-compose logs mcphub 检查日志 数据库连接错误:确保 PostgreSQL 健康且可访问 端口冲突:检查端口 3000/5432 是否已被占用 卷挂载问题:验证文件路径和权限

调试命令

# 检查容器状态
docker-compose ps

# 查看日志
docker-compose logs -f [service_name]

# 在容器中执行命令
docker-compose exec mcphub sh

# 检查数据库连接
docker-compose exec postgres psql -U mcphub -d mcphub

# 重启特定服务
docker-compose restart mcphub

# 重新构建并重启
docker-compose up --build -d

性能优化

services:
  mcphub:
    # ... 其他配置
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: '0.5'
        reservations:
          memory: 256M
          cpus: '0.25'
此 Docker 设置为 MCPHub 提供了完整的容器化环境,包含开发和生产配置。