Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
421 changes: 415 additions & 6 deletions docs/build/deployment.md

Large diffs are not rendered by default.

358 changes: 352 additions & 6 deletions docs/build/docker.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,356 @@
---
tags:
- Build
---

# Docker 基础

> 占位页:本页内容待团队补充。
<div markdown="1" style="position:relative;overflow:hidden;border:1px solid rgba(67,160,71,0.28);border-radius:1rem;padding:1.25rem 1.35rem;margin:0.8rem 0 1.5rem;background:linear-gradient(135deg,rgba(67,160,71,0.14),rgba(0,150,136,0.09) 48%,rgba(255,167,38,0.10));box-shadow:0 0.65rem 1.8rem rgba(0,0,0,0.10);">
<span style="display:inline-block;padding:0.18rem 0.55rem;border-radius:999px;background:rgba(67,160,71,0.16);color:#1b5e20;font-size:0.78rem;font-weight:700;letter-spacing:0.02em;">Build · 第 5 站</span>
**"在我电脑上能跑啊!"** Docker 终结了这句话。本章教你用容器打包 AI 应用,让它在任何机器上都能一模一样地运行。
</div>

## 这章解决什么问题

你写了一个 AI 应用,在自己电脑上跑得好好的。发给同事,他装了半小时依赖还是报错。部署到服务器,Python 版本不对、CUDA 版本不对、某个库缺了系统依赖……

Docker 解决的就是这个问题:**把你的代码、依赖、配置全部打包成一个容器,在任何机器上都能一键运行**。

## 镜像 vs 容器

| 概念 | 类比 | 特点 |
|------|------|------|
| 镜像(Image) | 安装包 / 菜谱 | 只读模板,定义了环境和程序 |
| 容器(Container) | 运行中的程序 / 做出来的菜 | 镜像的实例,可以启动、停止、删除 |

```mermaid
%%{init: { 'htmlLabels': false } }%%
graph LR
A[Dockerfile] -->|docker build| B[镜像 Image]
B -->|docker run| C[容器 1]
B -->|docker run| D[容器 2]
```

### 基本命令

```bash
# 镜像相关
docker images # 查看本地镜像
docker pull python:3.11 # 拉取镜像
docker rmi python:3.11 # 删除镜像

# 容器相关
docker ps # 查看运行中的容器
docker ps -a # 查看所有容器
docker stop <容器ID> # 停止容器
docker rm <容器ID> # 删除容器
docker logs <容器ID> # 查看容器日志
docker exec -it <容器ID> bash # 进入容器
```

## Dockerfile:构建镜像的配方

### 基本结构

```dockerfile
# 基础镜像
FROM python:3.11-slim

# 设置工作目录
WORKDIR /app

# 复制依赖文件
COPY requirements.txt .

# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt

# 复制代码
COPY . .

# 暴露端口
EXPOSE 8000

# 启动命令
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```

### 常用指令

| 指令 | 作用 | 示例 |
|------|------|------|
| `FROM` | 基础镜像 | `FROM python:3.11-slim` |
| `WORKDIR` | 设置工作目录 | `WORKDIR /app` |
| `COPY` | 复制文件到镜像 | `COPY . .` |
| `RUN` | 构建时执行命令 | `RUN pip install -r requirements.txt` |
| `EXPOSE` | 声明端口 | `EXPOSE 8000` |
| `CMD` | 容器启动命令 | `CMD ["python", "main.py"]` |
| `ENV` | 设置环境变量 | `ENV MODEL_NAME=qwen2.5` |

### AI 应用的 Dockerfile

```dockerfile
FROM python:3.11-slim

WORKDIR /app

# 安装系统依赖
RUN apt-get update && apt-get install -y \
curl \
&& rm -rf /var/lib/apt/lists/*

# 复制并安装 Python 依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 复制代码
COPY . .

# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1

EXPOSE 8000

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

## Docker Compose:多服务编排

当你的应用有多个服务(如 Web 服务 + Ollama),用 Docker Compose 来管理。

### 完整的 AI 应用配置

```yaml
# docker-compose.yml
version: '3.8'

services:
# AI 聊天 API
chat-api:
build: .
ports:
- "8000:8000"
environment:
- OLLAMA_HOST=http://ollama:11434
- MODEL_NAME=qwen2.5:7b
depends_on:
ollama:
condition: service_healthy
restart: unless-stopped

# Ollama 模型服务
ollama:
image: ollama/ollama
ports:
- "11434:11434"
volumes:
- ollama_data:/root/.ollama
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped

volumes:
ollama_data:
```

### 常用命令

```bash
# 启动所有服务
docker compose up -d

# 查看服务状态
docker compose ps

# 查看日志
docker compose logs -f

# 停止所有服务
docker compose down

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

## GPU 透传

AI 推理需要 GPU 加速。Docker 默认不能访问宿主机的 GPU,需要安装 NVIDIA Container Toolkit。

### 安装(Ubuntu/Debian)

```bash
# 添加仓库
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \
| sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg

curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \
| sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' \
| sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

# 安装
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit

# 配置 Docker 并重启
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
```

### 验证 GPU 可用

```bash
docker run --rm --gpus all nvidia/cuda:12.2.0-base-ubuntu22.04 nvidia-smi
```

### 运行时指定 GPU

```bash
# 使用所有 GPU
docker run --gpus all my-ai-app

# 使用特定 GPU
docker run --gpus '"device=0"' my-ai-app
```

## 卷挂载:持久化模型数据

模型文件动辄几个 GB,不应该打包进镜像。用卷挂载把宿主机的目录映射到容器里。

```bash
# 挂载目录
docker run -v ./models:/app/models my-ai-app
```

### 卷类型对比

| 类型 | 语法 | 特点 | 适用场景 |
|------|------|------|----------|
| 命名卷 | `volume_name:/path` | Docker 管理,可移植 | 数据库数据、模型缓存 |
| 绑定挂载 | `/host/path:/path` | 直接映射本地目录 | 开发环境、配置文件 |

## 常见错误和调试

**容器内访问不到宿主机服务:**

```python
# 错误:localhost 在容器内指向容器自己
OLLAMA_HOST = "http://localhost:11434"

# 正确:使用宿主机地址
OLLAMA_HOST = "http://host.docker.internal:11434" # Docker Desktop
```

**pip install 超时:**

```dockerfile
# 使用国内镜像源
RUN pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
```

**调试命令:**

```bash
docker logs <容器ID> # 查看日志
docker exec -it <容器ID> bash # 进入容器
docker inspect <容器ID> # 查看详细信息
docker stats <容器ID> # 查看资源使用
```

## AI 工作负载最佳实践

### 1. 分离模型和代码

```yaml
# 不推荐:模型打包进镜像
FROM python:3.11
COPY ./models /app/models # 几 GB 的模型文件

# 推荐:模型通过卷挂载
docker run -v ./models:/app/models my-ai-app
```

### 2. 使用 .dockerignore

```

Check warning on line 285 in docs/build/docker.md

View workflow job for this annotation

GitHub Actions / build

markdown/fenced-code-missing-language

围栏代码块没有声明语言。 建议:在开头写明语言,例如 ```bash、```python 或 ```text。
# .dockerignore
.git
.env
__pycache__
*.pyc
.venv
node_modules
*.gguf
*.bin
models/
```

### 3. 优化构建缓存

```dockerfile
# 把不常变的层放前面
FROM python:3.11-slim
WORKDIR /app

# 依赖文件不常变,先复制
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 代码经常变,后复制
COPY . .
```

### 4. 资源限制

```yaml
services:
chat-api:
deploy:
resources:
limits:
cpus: '2'
memory: 4G
```

## 常见问题

??? question "Q:Docker 和虚拟机有什么区别?"

Docker 容器共享宿主机的内核,虚拟机有独立的内核。容器更轻量、启动更快。

| 对比项 | Docker 容器 | 虚拟机 |
|--------|-------------|--------|
| 启动速度 | 秒级 | 分钟级 |
| 资源占用 | 少 | 多 |
| 镜像大小 | MB 级 | GB 级 |

??? question "Q:模型文件应该打包进镜像吗?"

不推荐。模型文件通常很大,打包进镜像会导致构建时间长、镜像体积巨大。更好的方案:
- 用卷挂载映射本地模型目录
- 启动时自动下载模型

## 练习

1. **写一个 Dockerfile**:把你的 AI 应用打包成 Docker 镜像
2. **用 Docker Compose**:配置一个包含 Web 服务和 Ollama 的多服务应用
3. **GPU 透传**:在 Docker 中运行 Ollama,确保能用 GPU 加速
4. **卷挂载**:把模型目录挂载到容器外,重启容器后模型还在
5. **优化镜像**:用 `.dockerignore` 排除不需要的文件,减小镜像体积

## 建议内容
## 延伸阅读

- Docker 是什么
- 镜像与容器
- 最小 Dockerfile
- 常见错误
- [Docker 官方文档](https://docs.docker.com/) —— 完整教程和 API 参考
- [Docker Compose 文档](https://docs.docker.com/compose/) —— 多服务编排
- [NVIDIA Container Toolkit](https://github.com/NVIDIA/nvidia-container-toolkit) —— GPU 透传
- [Ollama Docker](https://ollama.com/blog/ollama-is-now-available-as-an-official-docker-image) —— Ollama 官方镜像
Loading
Loading