怎么用 Docker 把 KNow 部署到服务器?

前九篇完成了 KNow 产品的所有功能开发。本篇回答三个问题:
1. Docker 镜像怎么构建和优化?
2. docker-compose 怎么编排所有服务?
3. 上线前要做哪些安全检查?

Docker 镜像怎么构建和优化?

后端 Dockerfile

# backend/Dockerfile
FROM python:3.11-slim AS builder

WORKDIR /app
COPY requirements.txt .
# 在构建阶段安装依赖,利用 Docker 缓存
RUN pip install --no-cache-dir -r requirements.txt

# 正式镜像
FROM python:3.11-slim
WORKDIR /app

# 安装运行时依赖(不含构建工具,减小镜像体积)
RUN apt-get update && apt-get install -y --no-install-recommends \
    libmagic1 && \
    rm -rf /var/lib/apt/lists/*

# 从 builder 阶段复制已安装的包
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY . .

EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

为什么用多阶段构建? 构建阶段有编译器和构建工具,运行时不需要。多阶段构建可以把镜像体积从 1.2GB 降到 400MB。

前端 Dockerfile

# frontend/Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

前端 nginx 配置

# frontend/nginx.conf
server {
    listen 80;
    server_name _;
    root /usr/share/nginx/html;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location /api {
        proxy_pass http://backend:8000;
        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_read_timeout 120s;
    }
}

docker-compose 怎么编排所有服务?

完整编排文件

# docker-compose.yml
services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: know
      POSTGRES_USER: know
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U know"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]

  qdrant:
    image: qdrant/qdrant:latest
    volumes:
      - qdrant_data:/qdrant/storage

  minio:
    image: minio/minio:latest
    environment:
      MINIO_ROOT_USER: ${MINIO_USER}
      MINIO_ROOT_PASSWORD: ${MINIO_PASSWORD}
    volumes:
      - minio_data:/data
    command: server /data

  backend:
    build: ./backend
    env_file: .env
    depends_on:
      postgres: { condition: service_healthy }
      redis: { condition: service_healthy }
      qdrant: { condition: service_started }
      minio: { condition: service_started }

  frontend:
    build: ./frontend
    ports:
      - "80:80"
    depends_on:
      - backend

volumes:
  postgres_data:
  redis_data:
  qdrant_data:
  minio_data:

环境变量模板

# .env(不要提交 Git)
DB_PASSWORD=your_secure_password
MINIO_USER=know_admin
MINIO_PASSWORD=your_minio_password
LLM_API_KEY=sk-your-key
LLM_BASE_URL=https://api.deepseek.com/v1
JWT_SECRET=your_random_secret_here

一键部署

# 克隆代码
git clone https://github.com/your/know.git
cd know

# 配置环境变量
cp .env.example .env
# 编辑 .env 填入真实密钥

# 启动
docker compose up -d --build

# 查看日志
docker compose logs -f

# 更新
git pull
docker compose up -d --build

上线前要做哪些安全检查?

1. 密钥检查

# 不要把这些硬编码在代码里 JWT_SECRET = "123456" DB_PASSWORD = "password" API_KEY = "sk-test" 使用环境变量或密钥管理服务

2. CORS 配置

# 生产环境限制来源
app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://your-domain.com"],
    allow_methods=["GET", "POST"],
    allow_headers=["Authorization", "Content-Type"],
)

3. 速率限制

# 防止 API 被滥用
from slowapi import Limiter
limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter

@router.post("/api/chat/stream")
@limiter.limit("30/minute")
async def chat_stream():
    ...

4. 数据备份

# 定时备份数据库
0 3 * * * docker exec know-postgres pg_dump -U know know > /backup/know_$(date +\%Y\%m\%d).sql
# 保留最近 30 天
0 4 * * * find /backup -name "know_*.sql" -mtime +30 -delete

上线 checklist

□ 所有密码和密钥已修改(不追求认密码)
□ HTTPS 证书已配置
□ CORS 已限制域名
□ 速率限制已启用
□ 数据库备份已配置
□ 日志轮转已配置
□ Docker 镜像已优化(多阶段构建)
□ .env 文件未提交 Git
□ 容器以非 root 用户运行
□ 健康检查接口已配置

总结

步骤 做的事
构建镜像 多阶段构建,前端用 nginx 托管静态文件
编排服务 docker-compose 管理 6 个服务
安全加固 CORS、限流、密钥管理、备份
上线验证 按 checklist 逐项确认

本文是 《AI 全栈开发实战——做一个真正的产品》 系列的第 10 篇。
系列目录:1-9 已完成,10. Docker 部署 ← 你在这里
本文由 Zyentor(智元界) 原创发布