Practical guides

Run GPU containers on a cloud VM

Run GPU containers on a rented VM with Docker and the NVIDIA Container Toolkit: check the setup, the --gpus flag, CUDA image versions and common errors.

The NVIDIA Container Toolkit is the piece that lets Docker hand a GPU to a container, and on a DeployGPU VM the quickest way to learn whether it is set up is to run one command and read what comes back. This guide covers that check, NVIDIA's install steps for when it fails, the --gpus flag, choosing a CUDA image your driver supports, a Compose file with a GPU, and the one networking rule that matters on a VM nobody firewalls for you.

Launch a GPU VM on an RTX A6000

Opens the deploy page on the cheapest 1x RTX A6000 offer at 2026-10-15 22:03 UTC: QuantaCloud, $0.48/hr. You can pick another GPU there before paying.

Three commands tell you whether Docker can see the GPU

The plain GPU VM is the provider's Ubuntu image with NVIDIA drivers and Docker. Whether the toolkit is configured on top of that is not documented per provider, so check instead of assuming:

Code example
nvidia-smi
nvidia-ctk --version
sudo docker run --rm --gpus all ubuntu nvidia-smi

The first prints the driver and the GPUs. The second prints the toolkit version, and a command not found error means the toolkit is missing. The third is the example from Docker's GPU access documentation and NVIDIA's sample workload. If the container prints the same table as the host, Docker can see the GPU.

If it fails with could not select device driver "" with capabilities: [[gpu]], Docker has no NVIDIA driver registered. Docker's source registers one only when it finds a toolkit hook program on its path as the daemon starts, so a missing toolkit and a Docker daemon that was not restarted after the install look identical. App templates run a version of this check themselves: the startup script (public at api.deploygpu.ai/bootstrap.sh) starts a --gpus all container that runs nvidia-smi and gives up after 30 attempts, five seconds apart, so a template that reaches Running has already passed it.

Install the toolkit when the check fails

These are NVIDIA's steps for Ubuntu and Debian from the install guide, checked on 1 October 2026:

Code example
sudo apt-get update && sudo apt-get install -y --no-install-recommends \
   ca-certificates \
   curl \
   gnupg2

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

export NVIDIA_CONTAINER_TOOLKIT_VERSION=1.20.1-1
sudo apt-get install -y \
    nvidia-container-toolkit=${NVIDIA_CONTAINER_TOOLKIT_VERSION} \
    nvidia-container-toolkit-base=${NVIDIA_CONTAINER_TOOLKIT_VERSION} \
    libnvidia-container-tools=${NVIDIA_CONTAINER_TOOLKIT_VERSION} \
    libnvidia-container1=${NVIDIA_CONTAINER_TOOLKIT_VERSION}

sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

NVIDIA pins a version in that guide, 1.20.1-1 on 1 October 2026, so copy the current one from the page. The nvidia-ctk runtime configure step edits /etc/docker/daemon.json, and the restart is what makes Docker pick the toolkit up. Docker's live restore documentation says the daemon shuts down running containers when it terminates by default, so do this before you start your own containers.

The --gpus flag and choosing GPUs

--gpus all gives the container every GPU on the VM. On a 2, 4 or 8 GPU VM you can hand out some of them instead, by index or by UUID, which nvidia-smi -L lists. The comma form needs the odd quoting, because Docker's documentation notes the value contains a comma:

Code example
sudo docker run --rm --gpus device=0 ubuntu nvidia-smi
sudo docker run --rm --gpus '"device=0,2"' ubuntu nvidia-smi

That is how you run one container per GPU on a multi-GPU VM, for example one transcription worker on each card. The multi-GPU page covers what the VM sizes look like.

Pick a CUDA image tag your driver supports

Read the CUDA version in the top right of the nvidia-smi header. NVIDIA's nvidia-smi documentation calls it the CUDA UMD Version and defines it as the latest CUDA version the driver supports. Pick an image tag at or below it. Official CUDA images set a requirement on the CUDA version, and NVIDIA's Docker documentation says that when the driver is too old to run that version, the container does not start. The refusal reads like this, with the version the image wants after cuda>=:

Code example
requirement error: unsatisfied condition: cuda>=13.4, please update your driver to a newer version, or use an earlier cuda container

These tags exist on Docker Hub as of 1 October 2026:

The nvidia-smi header showsA tag to start from
CUDA 12.2nvidia/cuda:12.2.2-base-ubuntu22.04
CUDA 12.8nvidia/cuda:12.8.2-base-ubuntu22.04
CUDA 12.9nvidia/cuda:12.9.2-base-ubuntu22.04
CUDA 13.4nvidia/cuda:13.4.2-base-ubuntu22.04

Docker Hub describes three flavors: base has the CUDA runtime, runtime adds the math libraries and NCCL, and devel adds headers and build tools. There is no latest tag, so a bare sudo docker pull nvidia/cuda fails with a manifest unknown error. NVIDIA's compatibility guide gives the floors behind the rule: CUDA 13.x needs driver 580 or newer, and CUDA 12.x needs 525 or newer, with minor version compatibility inside each family. Matching the header is the conservative way to stay clear of all of it.

Docker Compose with a GPU

Compose reserves a GPU through a device entry. Docker's Compose GPU documentation says the capabilities field is required and that count and device_ids cannot be combined:

Code example
services:
  gpu-check:
    image: nvidia/cuda:12.2.2-base-ubuntu22.04
    command: nvidia-smi
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

Run it with sudo docker compose up. If sudo docker compose version fails, the Compose plugin is missing, and Docker's Compose install page covers adding it. For a server, add a ports entry that binds to loopback, as in the next section.

Publish ports on 127.0.0.1 only

DeployGPU does not firewall VMs, and Hyperstack VMs are created with inbound traffic open. Docker's port publishing documentation says publishing is insecure by default, because the port becomes reachable from the outside world, and that including 127.0.0.1 in the flag limits it to the Docker host. Its firewall documentation adds that traffic to published ports is diverted before it reaches the rules ufw manages. So ufw does not protect a published port, and the 127.0.0.1 binding is the control:

Code example
sudo docker run -d --name server --gpus all -p 127.0.0.1:8000:8000 YOUR_IMAGE
ssh -N -L 8000:127.0.0.1:8000 ubuntu@YOUR_VM_IP -p 22

In a Compose file the same line is - "127.0.0.1:8000:8000" under ports, and the Compose file reference warns that a port with no host IP binds to all interfaces. The user in the tunnel command is ubuntu on QuantaCloud and Hyperstack, Ubuntu with a capital U on Massed Compute and root on Verda, so copy the exact command from the deployment. The Docker page also says that releases older than 28.0.0 let hosts on the same layer 2 segment reach ports published to localhost, so check sudo docker version. The vLLM guide is a full example of a server run this way.

Errors you will meet

MessageWhat it meansWhat to do
could not select device driver "" with capabilities: [[gpu]]Docker has no NVIDIA driver registeredInstall the toolkit and restart Docker, as above
requirement error: unsatisfied condition: cuda>=...The image needs a newer CUDA than the driver supportsUse a tag at or below the nvidia-smi version
Failed to initialize NVML: Unknown Error in a container that worked earlierThe container lost GPU accessNVIDIA's troubleshooting page says to delete the container and start a new one
Failed to initialize NVML: Driver/library version mismatchA driver upgrade the loaded kernel module has not picked upSee the NVML mismatch fix
A permission error on the Docker socketThe login user is not in the docker groupWrite sudo docker

NVIDIA's page says a container can lose GPU access when systemctl daemon-reload runs on a system where systemd manages the container's cgroups, and lists setting "exec-opts": ["native.cgroupdriver=cgroupfs"] in /etc/docker/daemon.json as a workaround. Deleting the container on a template deployment deletes what is inside deploygpu-workload, so copy anything you need out with sudo docker cp first. The first five minutes guide has the rest of the checks to run on a new VM, and the GPU VM page covers the image and the login users.

Frequently asked questions

Do I need to install the NVIDIA Container Toolkit on a DeployGPU VM?

Only if the check fails. Run nvidia-smi, then a GPU container, and if the container prints the same table as the host the toolkit is already set up. DeployGPU does not document it per provider.

Why does a newer CUDA image refuse to start?

Official CUDA images require a minimum CUDA version, and the container does not start when the host driver is older than that. Use a tag at or below the CUDA version shown by nvidia-smi.

Can one container use only some of the GPUs on an 8-GPU VM?

Yes. Pass the indexes to the gpus flag, for example device=0 for one GPU or a quoted list for several, and start another container for the remaining cards.

Does ufw protect ports that Docker publishes?

No. Docker routes published ports before the rules ufw manages, so bind the port to 127.0.0.1 and reach it through an SSH tunnel.

Why do the commands start with sudo docker?

The default login user is not in the docker group on every provider, so sudo is the form that works everywhere.

Does Docker Compose work with GPUs on these VMs?

Yes, with the Compose plugin installed and a devices reservation that sets capabilities to gpu. The Compose section above has a working file.