Docker Compose 配置 GPU 后报 devices was unexpected
GPU 镜像能单独运行,Compose 却拒绝 reservations 下的 devices,可能是实际调用了不支持设备请求的旧程序。核对入口、升级插件,再分别验证配置和 GPU 访问。
同一个 GPU 镜像通过 docker run --gpus 能访问显卡,放进 Compose 后,却在创建容器之前失败:
services.gpu_check.deploy.resources.reservations value
Additional properties are not allowed ('devices' was unexpected)
如果报错路径正是 deploy.resources.reservations,并且实际执行的是很旧的 docker-compose,应先查 Compose 对设备请求的支持。旧版 Compose 1.17.1 不支持这种 GPU 预留配置;该能力在历史版本 1.28.0 中加入。Docker Engine 本身支持 GPU,并不意味着另一套 Compose 程序能解析对应的 YAML。
下面针对 Linux 上的 Docker Compose 与 NVIDIA GPU。若已经能用同一台 Docker 主机上的容器访问 GPU,先保留现有驱动和运行时配置,集中处理 Compose 解析失败;如果从未成功访问过 GPU,还需要单独验证驱动与容器运行时。
确认失败命令实际用了哪个 Compose
在发生错误的终端、脚本或 CI 执行环境中检查:
docker-compose version
docker compose version
docker version
前两条分别检查连字符入口和 Docker CLI 的 Compose 子命令。只安装了其中一个时,另一条可能不存在,据此确认当前可用的入口。不要仅凭命令拼写认定版本;以实际输出为准,同时核对启动脚本仍在调用哪个入口。
第三条显示 Docker 客户端与服务端版本。它们和 Compose 的版本是不同信息。若通过远程 Docker 主机运行容器,驱动与 GPU 运行时应在服务端检查,而解析 YAML 的 Compose 则位于执行命令的一端。
把文件开头的 version: "3.5" 改成更大数字不会升级 Compose 程序。当前 Compose 中,这个字段已是过时的描述性信息;本文示例直接省略它。旧程序不支持设备请求时,也不要通过删除 devices 段让配置勉强通过,那会丢失 GPU 请求。
升级使用入口,再验证配置结构
优先使用当前受维护的 Compose 插件。历史上的 1.28.0 是能力起点,不是现在应锁定安装的目标;也不必照搬旧环境中下载 1.29.2 二进制的安装办法。
对于已配置 Docker 官方软件源、且系统版本仍受该软件源支持的 Ubuntu 或 Debian 环境,安装或更新插件的命令为:
sudo apt-get update
sudo apt-get install docker-compose-plugin
docker compose version
没有该软件源、使用其他发行版或由平台管理 Docker 的环境,应通过对应的安装渠道更新,不要把这组命令套到所有机器上。更新后同步调整实际执行脚本;交互终端使用新插件,而 CI 仍调用旧程序,报错就会继续出现。
先保留原 Compose 文件、环境文件和原命令,再用明确的文件路径验证。以下假设待部署文件名为 compose.yaml:
docker compose -f compose.yaml config --quiet
这条命令只校验配置,不启动 GPU 任务。通过之后,已经排除了这一轮字段解析错误,但尚未证明容器能够访问显卡。查看展开后的配置时,可去掉 --quiet;输出可能包含插值后的环境变量,不要直接贴到公开渠道。
将设备请求放到正确的层级
下面是一个独立的最小检查文件。保存为 compose.gpu-check.yaml,其中 example/gpu-check:approved 是占位镜像,必须替换成你已有的、包含 nvidia-smi 且与宿主机驱动兼容的固定镜像版本。最好使用之前通过普通容器方式验证过的同一个镜像,避免同时引入镜像升级变量。
services:
gpu_check:
image: example/gpu-check:approved
command: nvidia-smi
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
devices 是 reservations 下的列表。每个列表项描述一次设备请求,这里申请一块 NVIDIA GPU,并声明必需的 capabilities: [gpu]。
如果有多块卡,需要限定具体设备,可将同一个列表项中的 count: 1 替换成 device_ids: ["0"],并按主机实际设备 ID 调整。不要同时保留 count 与 device_ids,这两个字段互斥。不写数量并不表示申请零块卡;没有数量或具体 ID 限制时,可能会请求所有符合能力要求的设备。
服务下也有名为 devices 的设备映射配置,但它和这里的 GPU 预留列表不是同一个位置或结构。不要为了消除未知字段提示,把整段列表移到服务根部。
把语法验收与 GPU 验收分开
替换好镜像后,在有空闲 GPU 的测试环境中校验并运行这个独立文件:
docker compose -f compose.gpu-check.yaml config --quiet
docker compose -f compose.gpu-check.yaml run --rm --no-deps gpu_check
前一条应正常结束,不再报告 devices 是不允许的属性。后一条才会创建容器并运行 nvidia-smi;预期应显示分配到的 GPU 信息,命令结束后移除临时容器。这个示例没有业务数据挂载,也不需要清理业务卷。
如果配置校验已经通过,运行时却找不到 NVIDIA 设备驱动、无法选择满足 GPU 能力的驱动,或镜像中的程序无法访问显卡,说明需要继续检查 Docker 服务端的 NVIDIA 驱动、Container Toolkit 与运行时配置。升级 Compose 只解决它负责的解析和设备请求能力,不能替代这些前提。
检查运行时前应区分普通 Docker 与 rootless 部署;它们的配置位置和服务管理方式可能不同。不要在业务运行中盲目重启 Docker 或覆盖 daemon.json。调整运行时需要另行安排维护窗口,并先备份配置。
确认最小检查通过后,再将同样的设备请求合并回业务服务,核对应用实际识别到的 GPU。保留升级前的配置与工具版本用于回退;若退回不支持设备请求的 Compose,含有这段 GPU 配置的文件仍会失败,应恢复原先已验证的部署方式,而不是悄悄删除 GPU 需求。


