Skip to content

Latest commit

 

History

History
471 lines (343 loc) · 12.9 KB

File metadata and controls

471 lines (343 loc) · 12.9 KB

Minder AI Docker 部署指南

本文档介绍如何使用 Docker Compose 将 Minder AI 部署到服务器。HTTPS 由服务器上已有的全局 Caddy (caddy-proxy) 自动管理。

目录

前置要求

  • Docker >= 20.10
  • Docker Compose >= 2.0
  • 至少 2GB 可用内存
  • 至少 10GB 可用磁盘空间
  • 域名已解析到服务器 IP(如 minderai.heywhale.com
  • 服务器上已运行全局 Caddy (caddy-proxy),使用 proxy-net Docker 网络

安装 Docker (如未安装)

# Ubuntu/Debian
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

# CentOS/RHEL
sudo yum install -y docker
sudo systemctl enable docker && sudo systemctl start docker

快速部署

1. 克隆项目

git clone https://github.com/LHMQ878/MarkAI.git
cd MarkAI

2. 初始化配置

chmod +x deploy.sh
./deploy.sh setup

3. 编辑环境变量

编辑 .env 文件,填入你的配置:

# 必须修改
POSTGRES_PASSWORD=your_secure_password_here
JWT_SECRET=your_random_jwt_secret_here

# 推荐配置(至少配置一个 API Key)
SILICONFLOW_API_KEY=your_siliconflow_api_key
QWEN_API_KEY=your_qwen_api_key

# 域名(Caddy 自动申请 HTTPS 证书)
MINDERAI_DOMAIN=minderai.heywhale.com

4. 启动服务

./deploy.sh start

4.5 注册域名到全局 Caddy(首次部署)

./deploy.sh setup-domain

此命令会自动将 minderai.heywhale.com 的反向代理配置追加到全局 Caddyfile 并重载。 Caddy 会自动申请 HTTPS 证书(约 30 秒)。

5. 访问服务

服务 地址
前端界面 https://minderai.heywhale.com
API 文档 https://minderai.heywhale.com/api/docs
健康检查 https://minderai.heywhale.com/api/health

配置说明

环境变量

变量 说明 默认值 必填
POSTGRES_USER 数据库用户名 minderai
POSTGRES_PASSWORD 数据库密码 -
POSTGRES_DB 数据库名称 minderai
JWT_SECRET JWT 签名密钥 -
SILICONFLOW_API_KEY SiliconFlow API Key - 推荐
QWEN_API_KEY 通义千问 API Key - 可选
MINDERAI_DOMAIN 域名 minderai.heywhale.com

生成安全密钥

# 生成随机 JWT Secret
openssl rand -base64 32

# 生成随机数据库密码
openssl rand -base64 24

域名 & HTTPS

Minder AI 复用服务器上已有的全局 Caddy (caddy-proxy) 作为反向代理,通过 proxy-net Docker 网络连接。

架构说明

用户浏览器
    │
    ▼ HTTPS:443 (自动证书)
┌──────────────────────────────────────┐
│  caddy-proxy (全局, proxy-net)       │  ← 自动 HTTPS + 反向代理
│  管理多个域名:                        │
│    metabase.datascience.heywhale.com │
│    minderai.heywhale.com ←── 新增    │
└──────────┬───────────────────────────┘
           │ HTTP via proxy-net
           ▼
┌──────────────────────────────┐
│  minderai-frontend (Nginx)   │  ← SPA + API 反代
│  networks: minderai-network  │
│            + proxy-net       │
│          ↓ /api              │
│  minderai-backend (FastAPI)  │
│  minderai-postgres           │
└──────────────────────────────┘

minderai-frontend 同时连接两个网络:minderai-network(内部通信)和 proxy-net(让全局 Caddy 访问)。

全局 Caddy 配置

全局 Caddyfile 位于 /data/user/xiao/nginx/Caddyfile,由 caddy-proxy 容器挂载。

运行 ./deploy.sh setup-domain 会自动追加以下配置:

minderai.heywhale.com {
    reverse_proxy /* minderai-frontend:80
    tls liyy@heywhale.com
    encode gzip
    header {
        X-Frame-Options "SAMEORIGIN"
        X-Content-Type-Options "nosniff"
        Strict-Transport-Security "max-age=63072000; includeSubDomains"
    }
}

修改后重载:./deploy.sh caddy-reload

DNS 配置

在腾讯云 DNS 解析控制台添加以下记录:

主机记录 记录类型 记录值 TTL
minderai A <你的服务器公网IP> 600

查看服务器公网 IP:

curl ifconfig.me

防火墙配置

80 和 443 端口由全局 caddy-proxy 使用,需确保已放行:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

腾讯云安全组也需要放行 80 和 443 端口。

验证部署

# 检查 HTTPS 是否正常
curl -I https://minderai.heywhale.com

# 检查 HTTP 是否自动跳转 HTTPS
curl -I http://minderai.heywhale.com

# 检查 API
curl https://minderai.heywhale.com/api/health

# 查看全局 Caddy 日志(证书申请状态)
docker logs -f caddy-proxy

# 检查 SSL 证书信息
openssl s_client -connect minderai.heywhale.com:443 -servername minderai.heywhale.com </dev/null 2>/dev/null | openssl x509 -noout -dates

常用命令

# 查看服务状态
./deploy.sh status

# 查看实时日志
./deploy.sh logs -f

# 查看特定服务日志
./deploy.sh logs -f backend
./deploy.sh logs -f frontend
./deploy.sh logs -f postgres

# 查看全局 Caddy 日志
docker logs -f caddy-proxy

# 重启服务
./deploy.sh restart

# 重新构建并启动(代码更新后)
./deploy.sh rebuild

# 停止服务
./deploy.sh stop

# 注册域名到全局 Caddy(首次部署)
./deploy.sh setup-domain

# 重载全局 Caddy 配置
./deploy.sh caddy-reload

# 完全清理(包括数据库数据)
./deploy.sh clean

服务内部端口映射

容器 内部端口 外部端口
caddy-proxy (全局) 80, 443 80, 443(共享)
frontend (Nginx) 80 不暴露,通过 proxy-net 访问
backend (FastAPI) 8000 不暴露,仅内部访问
postgres 5432 不暴露,仅内部访问

生产环境建议

1. 设置自动重启

Docker Compose 已配置 restart: unless-stopped,服务会在崩溃或系统重启后自动恢复。

2. 数据备份

# 备份数据库
docker exec minderai-postgres pg_dump -U minderai minderai > backup_$(date +%Y%m%d).sql

# 恢复数据库
docker exec -i minderai-postgres psql -U minderai minderai < backup.sql

# 备份上传文件
docker cp minderai-backend:/app/uploads ./uploads_backup

3. 监控日志

# 实时监控所有服务
./deploy.sh logs -f

# 保存日志到文件
./deploy.sh logs > logs_$(date +%Y%m%d).txt

4. 使用外部数据库

如需使用外部 PostgreSQL(如阿里云 RDS),在 .env 中设置:

DATABASE_URL=postgresql+asyncpg://user:password@host:5432/dbname

系统将自动跳过本地 PostgreSQL 容器启动。

故障排除

Caddy 无法申请证书

# 查看全局 Caddy 详细日志
docker logs -f caddy-proxy

# 常见原因:
# 1. 域名未解析到服务器 IP → 检查 DNS
# 2. 防火墙/安全组未放行 80/443 → 放行端口
# 3. 域名未备案(国内服务器)→ 完成 ICP 备案
# 4. 域名未添加到 Caddyfile → 运行 ./deploy.sh setup-domain

服务启动失败

# 查看详细日志
./deploy.sh logs backend
./deploy.sh logs postgres

# 检查容器状态
docker ps -a | grep minderai

数据库连接问题

# 检查 PostgreSQL 是否正常
docker exec minderai-postgres pg_isready -U minderai

# 进入数据库
docker exec -it minderai-postgres psql -U minderai minderai

proxy-net 网络不存在

# 确认全局 Caddy 正在运行
docker ps --filter name=caddy-proxy

# 如果没有运行,需要先启动全局 Caddy

磁盘空间不足

# 清理 Docker 未使用资源
docker system prune -a

# 查看 Docker 磁盘使用
docker system df

僵尸进程排查

登录服务器后若看到 There are N zombie processes,可按以下步骤排查是否与本项目(Minder AI)相关,并做处理。

1. 列出所有僵尸进程

# 查看状态为 Z (zombie) 的进程
ps aux | awk '$8 ~ /Z/'

# 或更清晰:显示 PID、PPID、状态、命令
ps -eo pid,ppid,stat,cmd | grep -E ' Z| Zs'

2. 确认父进程(谁没回收子进程)

僵尸进程的父进程 PID 在 PPID 列。根据父进程可判断来源:

# 根据上面得到的 PPID,查看父进程是什么
ps -p <PPID> -o pid,ppid,stat,cmd

# 若父进程在容器内,可查该 PID 属于哪个容器
docker ps -q | xargs -I {} docker top {} 2>/dev/null | grep -E "PID|PPID"
# 或:在宿主机上
cat /proc/<PPID>/cgroup 2>/dev/null | head -1
  • 若父进程是 containerd-shimdockerd:多半是某个容器内进程退出后,容器主进程(PID 1)未正确 wait() 子进程,导致僵尸留在宿主机。
  • 若父进程是 systemdinit (PID 1):一般是宿主机上的服务(如 cron、自定义 systemd 服务)未回收子进程;重启对应服务或系统会回收。

3. 判断是否来自 Minder AI 的容器

本项目的容器名为:minderai-backendminderai-frontendminderai-postgres

# 查看本项目容器的主进程 PID(在宿主机上)
docker inspect -f '{{.State.Pid}}' minderai-backend
docker inspect -f '{{.State.Pid}}' minderai-frontend
docker inspect -f '{{.State.Pid}}' minderai-postgres

若僵尸进程的 PPID 等于上述某个容器的 State.Pid,或属于该 PID 的子进程树,则可能来自该容器。
后端使用 uvicorn 单进程、前端为 nginx,通常不会产生大量僵尸;若僵尸的父进程不在上述容器内,则来自其他服务或其它 Docker 项目。

4. 处理方式

  • 不能直接 kill 僵尸进程:僵尸已退出,kill 无效;只有其父进程执行 wait() 或父进程退出后,僵尸才会被 init 回收。
  • 若父进程属于本项目某容器:重启对应容器,让新进程树替代旧的,僵尸会被回收:
    ./deploy.sh restart
    # 或只重启后端
    docker restart minderai-backend
  • 若父进程属于其他服务:重启该服务(如 sudo systemctl restart <服务名>),或安排系统重启(*** System restart required *** 时重启会清空僵尸)。
  • 长期减少僵尸:确保所有服务用正确方式回收子进程(如用 exec 启动主进程、或 PID 1 进程负责 wait);本项目当前镜像中 uvicorn/nginx 作为 PID 1 已符合常见用法。

5. 一键查看僵尸及其父进程(示例)

ps -eo pid,ppid,stat,cmd | awk '$3 ~ /Z/ {print; system("ps -p " $2 " -o pid,ppid,stat,cmd 2>/dev/null")}'

根据输出中的父进程命令判断是哪个服务或容器,再按上面步骤处理即可。

升级更新

# 拉取最新代码
git pull

# 重新构建并启动
./deploy.sh rebuild

架构图

  HTTPS:443 ──────┐
  HTTP:80 ────────┤
                  ▼
         ┌──────────────────────┐
         │  caddy-proxy (全局)  │  auto HTTPS
         │  [proxy-net]         │
         └────────┬─────────────┘
                  │ proxy-net
                  ▼
         ┌──────────────────────┐
         │  minderai-frontend   │
         │  (Nginx) :80         │
         │  [proxy-net +        │
         │   minderai-network]  │
         └────────┬─────────────┘
                  │ /api → minderai-network
                  ▼
         ┌──────────────────────┐
         │  minderai-backend    │
         │  (FastAPI) :8000     │
         │  [minderai-network]  │
         └────────┬─────────────┘
                  │
                  ▼
         ┌──────────────────────┐
         │  minderai-postgres   │
         │  :5432               │
         │  [minderai-network]  │
         └──────────────────────┘

容器资源

服务 CPU 内存
postgres 0.5 核 256MB
backend 1 核 512MB
frontend 0.25 核 128MB

总计:约 1.75 核 CPU,896MB 内存(基础运行,不含全局 caddy-proxy)


如有问题,请查看 GitHub Issues 或提交新 Issue。