Skip to content

Docker 部署

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

Docker 快速开始

使用预构建镜像

bash
# 拉取最新镜像
docker pull huangjunsen/xiaozhi-mcphub:latest

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

从源码构建

bash
# 克隆仓库
git clone https://github.com/huangjunsen0406/xiaozhi-mcphub.git
cd xiaozhi-mcphub

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

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

Docker Compose 设置

基本配置

创建 docker-compose.yml 文件:

yaml
version: '3.8'

services:
  xiaozhi-mcphub:
    image: huangjunsen/xiaozhi-mcphub:latest
    # 本地开发时使用:
    # build: .
    container_name: xiaozhi-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
      # 小智平台集成环境变量
      - XIAOZHI_ENABLED=${XIAOZHI_ENABLED:-true}
      - XIAOZHI_WEBSOCKET_URL=${XIAOZHI_WEBSOCKET_URL}
      - XIAOZHI_RECONNECT_MAX_ATTEMPTS=${XIAOZHI_RECONNECT_MAX_ATTEMPTS:-10}
    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)

yaml
version: '3.8'

services:
  nginx:
    image: nginx:alpine
    container_name: xiaozhi-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:
      - xiaozhi-mcphub
    restart: unless-stopped
    networks:
      - mcphub-network

  xiaozhi-mcphub:
    image: huangjunsen/xiaozhi-mcphub:latest
    container_name: xiaozhi-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
      # 小智平台配置
      - XIAOZHI_ENABLED=true
      - XIAOZHI_WEBSOCKET_URL=${XIAOZHI_WEBSOCKET_URL}
      - XIAOZHI_RECONNECT_MAX_ATTEMPTS=10
      - XIAOZHI_RECONNECT_INITIAL_DELAY=2000
      - XIAOZHI_RECONNECT_MAX_DELAY=60000
      # 高德地图API密钥(如果使用)
      - AMAP_MAPS_API_KEY=${AMAP_MAPS_API_KEY}
    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 文件:

bash
# 应用程序
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

# 小智平台集成配置
XIAOZHI_ENABLED=true
XIAOZHI_WEBSOCKET_URL=wss://api.xiaozhi.me/mcp/?token=your-jwt-token
XIAOZHI_RECONNECT_MAX_ATTEMPTS=10
XIAOZHI_RECONNECT_INITIAL_DELAY=2000
XIAOZHI_RECONNECT_MAX_DELAY=60000

# MCP服务器API密钥
AMAP_MAPS_API_KEY=your-amap-api-key
SLACK_BOT_TOKEN=your-slack-bot-token
SLACK_TEAM_ID=your-slack-team-id
GITHUB_TOKEN=your-github-token

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

开发设置

开发 Docker Compose

创建 docker-compose.dev.yml

yaml
version: '3.8'

services:
  xiaozhi-mcphub-dev:
    build:
      context: .
      dockerfile: Dockerfile.dev
    container_name: xiaozhi-mcphub-dev
    ports:
      - '3000:3000'
      - '5173:5173' # 前端开发服务器
      - '9229:9229' # 调试端口
    environment:
      - NODE_ENV=development
      - PORT=3000
      - DATABASE_URL=postgresql://mcphub:password@postgres:5432/mcphub
      - XIAOZHI_ENABLED=true
      - XIAOZHI_WEBSOCKET_URL=${XIAOZHI_WEBSOCKET_URL}
    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

dockerfile
FROM python:3.13-slim-bookworm AS base

COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

RUN apt-get update && apt-get install -y curl gnupg git \
  && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
  && apt-get install -y nodejs \
  && apt-get clean && rm -rf /var/lib/apt/lists/*

RUN npm install -g pnpm

# 安装全局MCP服务器包
ENV PNPM_HOME=/usr/local/share/pnpm
ENV PATH=$PNPM_HOME:$PATH
RUN mkdir -p $PNPM_HOME && \
  pnpm add -g @amap/amap-maps-mcp-server @playwright/mcp@latest @modelcontextprotocol/server-github @modelcontextprotocol/server-slack

RUN uv tool install mcp-server-fetch

# 设置工作目录
WORKDIR /app

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

# 安装依赖
RUN pnpm install

# 复制源代码
COPY . .

# 暴露端口
EXPOSE 3000 5173 9229

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

配置管理

小智平台MCP设置

创建您的 mcp_settings.json,包含小智平台配置:

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": "${AMAP_MAPS_API_KEY}"
      }
    },
    "slack": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-slack"],
      "env": {
        "SLACK_BOT_TOKEN": "${SLACK_BOT_TOKEN}",
        "SLACK_TEAM_ID": "${SLACK_TEAM_ID}"
      }
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  },
  "xiaozhi": {
    "enabled": true,
    "webSocketUrl": "${XIAOZHI_WEBSOCKET_URL}",
    "reconnect": {
      "maxAttempts": 10,
      "initialDelay": 2000,
      "maxDelay": 60000,
      "backoffMultiplier": 2
    }
  }
}

密钥管理

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

yaml
version: '3.8'

services:
  xiaozhi-mcphub:
    image: huangjunsen/xiaozhi-mcphub:latest
    environment:
      - JWT_SECRET_FILE=/run/secrets/jwt_secret
      - DATABASE_PASSWORD_FILE=/run/secrets/db_password
      - XIAOZHI_WEBSOCKET_URL_FILE=/run/secrets/xiaozhi_url
    secrets:
      - jwt_secret
      - db_password
      - xiaozhi_url

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

数据持久化

数据库备份

docker-compose.yml 中添加备份服务:

yaml
services:
  backup:
    image: postgres:15-alpine
    container_name: xiaozhi-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

bash
#!/bin/sh
BACKUP_FILE="/backups/xiaozhi-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 "xiaozhi-mcphub_*.sql" -mtime +7 -delete

运行备份:

bash
docker-compose --profile backup run --rm backup

监控和健康检查

健康检查端点

应用程序包含以下健康检查端点:

javascript
// 在您的 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,
    xiaozhi: {
      enabled: process.env.XIAOZHI_ENABLED === 'true',
      connected: xiaozhi.isConnected()
    }
  });
});

Docker 健康检查

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

使用 Watchtower 监控

添加自动更新:

yaml
services:
  watchtower:
    image: containrrr/watchtower
    container_name: xiaozhi-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 xiaozhi-mcphub 检查日志

小智平台连接失败:检查 WebSocket URL 和 JWT 令牌

bash
# 检查小智连接状态
curl http://localhost:3000/api/xiaozhi/status

MCP服务器启动失败:检查环境变量和API密钥配置

数据库连接错误:确保 PostgreSQL 健康且可访问

端口冲突:检查端口 3000/5432 是否已被占用

卷挂载问题:验证文件路径和权限

调试命令

bash
# 查看容器状态
docker-compose ps

# 查看详细日志
docker-compose logs -f --tail=100 xiaozhi-mcphub

# 查看小智平台连接日志
docker-compose logs xiaozhi-mcphub | grep xiaozhi

# 进入容器调试
docker-compose exec xiaozhi-mcphub sh

# 重启服务
docker-compose restart xiaozhi-mcphub

# 完全重建
docker-compose down -v
docker-compose build --no-cache
docker-compose up -d

小智平台连接调试

bash
# 检查小智配置
curl http://localhost:3000/api/xiaozhi/config

# 重启小智连接
curl -X POST http://localhost:3000/api/xiaozhi/restart

# 查看工具同步状态
curl http://localhost:3000/api/xiaozhi/tools

性能优化

内存限制

yaml
services:
  xiaozhi-mcphub:
    deploy:
      resources:
        limits:
          memory: 1G
        reservations:
          memory: 512M

日志轮换

yaml
services:
  xiaozhi-mcphub:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

提示

  • 定期监控容器资源使用情况
  • 使用 Docker stats 命令查看实时指标
  • 为生产环境设置适当的重启策略
  • 定期更新镜像以获取安全补丁
  • 监控小智平台连接状态

安全提醒

  • 更改默认密码
  • 使用 Docker secrets 管理敏感信息
  • 定期备份数据
  • 限制容器网络访问
  • 保护小智平台WebSocket连接的JWT令牌