4. 容器化环境搭建:Docker Engine安装与配置、NVIDIA Container Toolkit集成、Docker Compose管理多容器

说实话,搞AI基础设施这几年,我踩过最大的坑就是环境不一致。你在开发机上跑得好好的模型,一上生产服务器就崩,十有八九是依赖库版本对不上。容器化技术,说白了就是把你的AI应用连同它需要的所有依赖——CUDA、cuDNN、Python包、系统库——打包成一个独立的箱子,搬到哪都能跑。

这一章,我们就把这个箱子怎么造、怎么装轮子(GPU支持)、怎么同时管理多个箱子(多容器编排)讲清楚。嗯,都是我在生产环境里反复验证过的做法。

4.1 Docker Engine:地基要打牢

Docker Engine是整个容器化体系的基石。我见过不少团队直接在Ubuntu上apt install docker.io完事,结果后面遇到内核兼容性问题,排查起来非常痛苦。

我个人习惯用官方脚本安装,干净、可控。

# 卸载旧版本(如果有)
sudo apt-get remove docker docker-engine docker.io containerd runc

# 安装依赖
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg lsb-release

# 添加Docker官方GPG密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# 设置稳定版仓库
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 安装Docker Engine
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# 验证安装
sudo docker run hello-world
小技巧:安装完成后,记得把当前用户加入docker组,避免每次敲命令都要加sudo。
sudo usermod -aG docker $USER
newgrp docker

安装完第一件事是什么?不是急着拉镜像,而是配镜像加速器。国内网络环境你懂的,直接拉Docker Hub的镜像慢得让人抓狂。

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://<你的加速器地址>"],
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  },
  "storage-driver": "overlay2"
}
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker

这里我特别想强调log-opts的配置。有一次线上告警,说某台GPU节点的磁盘满了。我上去一看,Docker的日志文件吃了200多G。从那以后,我所有节点的日志上限都卡死在100m×3个文件。

4.2 NVIDIA Container Toolkit:让容器用上GPU

光有Docker还不够,AI训练推理离不开GPU。NVIDIA Container Toolkit就是那个让容器里能调用GPU的桥梁。

它的原理其实不复杂:通过nvidia-container-runtime这个运行时,把宿主机的GPU驱动和CUDA库挂载进容器。你想想看,容器里跑PyTorch,torch.cuda.is_available()返回True,靠的就是它。

4.2.1 安装步骤

# 添加NVIDIA容器工具包仓库
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit

# 配置Docker使用NVIDIA运行时
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
注意:安装前务必确认宿主机已安装NVIDIA驱动,且nvidia-smi能正常输出。我曾经遇到过驱动版本和容器工具包不兼容的情况,折腾了大半天才发现是驱动太旧。

4.2.2 验证GPU可用性

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

看到GPU信息输出,就说明集成成功了。这里有个细节:--gpus all表示分配所有GPU,如果你只想用某几块,可以写成--gpus '"device=0,1"'。

参数 说明 适用场景
--gpus all 分配所有可用GPU 单机多卡训练
--gpus '"device=0,1"' 指定特定GPU 多租户隔离、资源预留
--gpus '"capabilities=compute,utility"' 按能力筛选GPU 需要特定计算能力的场景

4.3 Docker Compose:多容器编排利器

单容器跑个简单推理还行,但一个完整的AI服务通常需要多个组件:模型推理服务、API网关、消息队列、监控面板……手动一个个启动、配置网络、管理依赖,那不得累死。

Docker Compose就是干这个的。它用一个YAML文件定义整个服务栈,一条命令全部拉起。

4.3.1 一个典型的AI推理服务栈

我拿一个实际项目举例:Triton推理服务器 + Redis缓存 + Prometheus监控。

version: '3.8'

services:
  triton-server:
    image: nvcr.io/nvidia/tritonserver:23.08-py3
    container_name: triton-inference
    runtime: nvidia
    environment:
      - NVIDIA_VISIBLE_DEVICES=0,1
    volumes:
      - /data/models:/models
      - /data/logs:/logs
    ports:
      - "8000:8000"   # HTTP
      - "8001:8001"   # gRPC
      - "8002:8002"   # Metrics
    command: tritonserver --model-repository=/models --log-file=/logs/triton.log
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/v2/health/ready"]
      interval: 30s
      timeout: 10s
      retries: 3
    networks:
      - ai-net
    restart: unless-stopped

  redis-cache:
    image: redis:7-alpine
    container_name: ai-cache
    volumes:
      - redis-data:/data
    ports:
      - "6379:6379"
    networks:
      - ai-net
    restart: unless-stopped

  prometheus:
    image: prom/prometheus:latest
    container_name: ai-monitor
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prom-data:/prometheus
    ports:
      - "9090:9090"
    networks:
      - ai-net
    restart: unless-stopped

volumes:
  redis-data:
  prom-data:

networks:
  ai-net:
    driver: bridge

关键点解析:

  • runtime: nvidia:让Triton容器能访问GPU,这是AI推理服务的标配
  • healthcheck:我习惯给核心服务加健康检查,配合restart: unless-stopped实现自动恢复
  • networks:所有服务放在同一个自定义网络里,服务名就是域名,互相通信不用记IP

4.3.2 常用操作命令

# 启动所有服务(后台模式)
docker compose up -d

# 查看服务状态
docker compose ps

# 查看日志(实时跟踪)
docker compose logs -f triton-server

# 重新构建并启动(修改了Dockerfile或镜像后)
docker compose up -d --build

# 停止并移除所有容器、网络、卷
docker compose down -v

docker compose down -v这个命令要慎用。-v会删除所有卷,包括你的模型缓存和监控数据。我刚开始用的时候手滑过一次,把积累了一周的监控历史全删了……嗯,从那以后我养成习惯,生产环境只用docker compose down,不带-v。

4.4 本章知识体系

下面这张图把容器化环境搭建的核心脉络串起来了,你可以对照着梳理自己的部署流程。

容器化环境搭建核心流程 Docker Engine NVIDIA Container Toolkit Docker Compose 多容器编排 推理服务 (Triton) 缓存/中间件 (Redis) 监控/日志 (Prometheus) 💡 核心要点 Docker Engine提供运行环境 → NVIDIA Toolkit打通GPU通道 → Compose统一编排多服务 三者缺一不可,顺序不能乱

4.5 避坑指南

最后分享几个我亲身踩过的坑,希望能帮你省点时间。

  • 磁盘空间爆炸:Docker默认日志驱动不限制大小,长时间运行的推理容器日志能轻松吃掉几十G。一定要在daemon.json里配好log-opts,或者用docker system prune定期清理。
  • GPU显存泄漏:容器退出后,有时候NVIDIA驱动不会自动释放显存。我习惯在docker compose down之后,手动执行nvidia-smi --gpu-reset(仅限测试环境)。
  • 网络冲突:多个Compose项目如果都用默认的bridge网络,端口映射容易冲突。我建议每个项目都显式声明networks,并指定子网段。
  • 镜像版本漂移:生产环境一定要锁定镜像的完整SHA256摘要,而不是只写标签。比如image: nvcr.io/nvidia/tritonserver:23.08-py3@sha256:xxxx,避免拉取到意外更新。

安全提醒:永远不要在生产容器里以root用户运行进程。在Dockerfile里加上USER 1000:1000,或者在Compose里指定user: "1000:1000"。我曾经见过一个团队因为容器里跑root,被攻击者通过容器逃逸拿到了宿主机权限……