进阶Docker 4 分钟阅读发布于 · 更新于

Docker:Ollama 的 NVIDIA / AMD GPU 透传

容器化 Ollama 并启用 GPU — 隔离模型、固定版本、与其他服务共存。

面向的技术栈

Linux 上的 Docker Engine · NVIDIA Container Toolkit 或 AMD ROCm 设备 · ollama/ollama(AMD 用 :rocm)· GGUF Q4_K_M

最近一次修改后未重新实机运行 —— 命令请当作起点,而不是已验证的配方。

DockerOllamaNVIDIAAMDGPUCompose

开始之前

需要 Linux 上的 Docker Engine,再加上一样取决于显卡的东西。NVIDIA 需要 NVIDIA Container Toolkit,而装上这个包只是一半。`nvidia-ctk runtime configure` 负责把运行时注册给 Docker,之后 Docker 必须重启才会认到。漏掉任何一步,容器照样能启动,只是看不到 GPU。AMD 没有 toolkit:直接把 `/dev/kfd` 和 `/dev/dri` 两个设备交给容器。动 Ollama 之前先确认容器能看到 GPU,因为“容器看不看得到 GPU”比“Docker 里的 Ollama 为什么慢”好查得多。

bash
# NVIDIA: after installing nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

# NVIDIA's own check: the toolkit injects nvidia-smi into a plain image
sudo docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi

# AMD: these must exist on the host
ls -l /dev/kfd /dev/dri

compose 文件

大多数抄来的示例,GPU 那部分要么配错,要么干脆没写。NVIDIA 是 `deploy.resources.reservations.devices` 这一段;AMD 是 `devices` 列表加上 `:rocm` 镜像标签。Ollama 的默认镜像还带 Vulkan,只要能访问到 GPU 设备就会使用,所以 ROCm 不支持的 Radeon 可以用普通镜像配同样两个设备试试。除非你确实想对外开放 API,否则把端口绑定到 127.0.0.1:Ollama 没有任何鉴权,而且 Docker 发布的端口会绕过 ufw。

yaml
# NVIDIA
services:
  ollama:
    image: ollama/ollama
    container_name: ollama
    ports:
      - "127.0.0.1:11434:11434"
    volumes:
      - ollama_data:/root/.ollama
    restart: unless-stopped
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

volumes:
  ollama_data:

# AMD: same file, but replace image + deploy with
#    image: ollama/ollama:rocm
#    devices:
#      - /dev/kfd
#      - /dev/dri

启动并拉取模型

把容器起来,然后往里面拉一个模型。模型存放在命名卷里,所以 `down` 再 `up` 不用重新下载。Llama 3.1 8B 的 Q4_K_M 在 4K 上下文下约需 5.6 GB,而 4K 正是 Ollama 的默认窗口,所以任何 8GB 及以上的显卡都适合先拉它。

bash
docker compose up -d
docker exec ollama ollama pull llama3.1:8b

确认它真的跑在 GPU 上

容器化让这一步特别容易被跳过:不管在 CPU 还是 GPU 上,容器都会正常启动,只有速度能看出区别。要问容器,而不是问宿主机:容器里的 `ollama ps` 会报告已加载模型实际放在哪里。容器日志里也会写明 Ollama 启动时找到的 GPU,这是 AMD 上最快的检查办法。

bash
docker exec ollama ollama run llama3.1:8b "hi" >/dev/null
docker exec ollama ollama ps
# NAME           ID     SIZE      PROCESSOR    UNTIL
# llama3.1:8b    …      6.1 GB    100% GPU     4 minutes from now

docker logs ollama 2>&1 | grep -i -E "gpu|rocm|cuda|vulkan" | head

# NVIDIA, on the host:
nvidia-smi --query-gpu=memory.used,utilization.gpu --format=csv -l 1

数字大概该是什么样

容器是把 GPU 直通进去,而不是模拟它,所以直通一旦正常,就没有理由指望速度会不一样。本站没有实测过容器内和原生运行的对比,所以这是预期,不是测量结果。我们能给的是上限:Llama 3.1 8B 的 Q4_K_M 权重是 4.6 GB,每生成一个 token 都要把它们全读一遍。在带宽 1,008 GB/s 的 RTX 4090 上,这把生成速度封顶在约 218 tok/s。本索引在同一张卡上用 llama.cpp 跑这个模型和量化档位,实测是 148,而 Ollama 底层用的就是 llama.cpp。如果结果低了一个数量级,说明容器跑在 CPU 上。

出问题时

容器内 `ollama ps` 显示有 CPU 份额,而宿主机上 `nvidia-smi` 正常:第一步的 toolkit 检查能告诉你缺的是哪一块。检查不通过,就是 toolkit 没装或者 `nvidia-ctk runtime configure` 从没运行过,Ollama 这边怎么配都绕不过去;检查通过,就是 compose 文件少了 `deploy` 那一段。AMD 上容器能启动却找不到 GPU:确认宿主机上存在 `/dev/kfd` 和 `/dev/dri`,并且写在 `devices` 里;在启用 SELinux 的发行版上,Ollama 文档给出的办法是 `sudo setsebool container_use_devices=1`,允许容器使用这些设备。`docker compose down` 之后模型没了:没用命名卷,或者用 `-v` 把卷删了。在 Windows 上,NVIDIA 需要 Docker Desktop 的 WSL2 后端并开启 GPU 支持。在 Mac 上请直接原生运行 Ollama,因为 macOS 上的 Docker 容器用不到 Apple GPU。

常见问题

Docker 里的 Ollama 为什么用 CPU 而不是 GPU?

NVIDIA 上几乎总是 container toolkit 或 compose 文件的问题:要么没装 NVIDIA Container Toolkit;要么装了,但没运行 `sudo nvidia-ctk runtime configure --runtime=docker` 并重启 Docker;要么 compose 文件里没有 `deploy.resources.reservations.devices` 这一段。先用 `sudo docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi` 单独测试 toolkit,如果这一步失败,问题就不在 Ollama。AMD 上,容器需要传入 `/dev/kfd` 和 `/dev/dri`,并使用 `ollama/ollama:rocm` 镜像。

能在 AMD 显卡上用 Docker 跑 Ollama 吗?

可以,在 Linux 上。Ollama 文档用的是 `ollama/ollama:rocm` 镜像,加上 `--device /dev/kfd --device /dev/dri`,不涉及任何 container toolkit。默认的 `ollama/ollama` 镜像也带 Vulkan,只要能访问到同样的设备就会使用,ROCm 不支持的 Radeon 可以试这个。用 `docker logs ollama` 查看它找到了哪块 GPU。

在 Docker 里跑 Ollama 会变慢吗?

GPU 正确直通之后不应该变慢,因为容器是把真实设备交给 Ollama,而不是模拟它。不过本站没有实测过容器内与原生运行的对比。大家遇到的明显变慢,几乎都是容器悄悄退回了 CPU,在容器里运行 `ollama ps` 一眼就能看出来。

重建容器之后怎么保留已下载的模型?

像上面 compose 文件那样,用一个命名卷映射到 `/root/.ollama`。这样模型文件就在容器的生命周期之外,`docker compose down` 再 `up` 不会触发重新下载。用 `down -v` 删除卷会把它们一起删掉,所以要避开的就是这一条命令。

这篇指南用到了什么

格式
GGUF

接下来

本文涉及的模型

它真的跑起来了吗?

复制命令并不等于它能用,所以站内只在这里问一次。除了你的这个回答之外,不收集任何东西。

相关指南

部署指南仅供学习参考。每个模型均有独立许可协议 — 下载或部署前请阅读 Hugging Face 官方模型卡。