Skip to content

nvidia-layer

Recipe card from the charly-distros plugin (Images — the deployable catalog).

NVIDIA runtime candy providing nvidia-container-toolkit for CDI device injection and VA-API hardware video acceleration. Driver userspace libraries (libcuda, libnvidia-ml, etc.) are NOT bundled — CDI provides host-matching driver libs at runtime, preventing version mismatches between container and host kernel module. Supports both Fedora and Arch Linux.

Property Value
Install files charly.yml, task:
Depends none

RPM (from negativo17 fedora-multimedia repo):

  • nvidia-container-toolkitnvidia-ctk CLI for CDI spec generation
  • libva-nvidia-driver — VA-API hardware video acceleration

PAC (Arch Linux):

  • nvidia-utils — NVIDIA GL/Vulkan userspace, nvidia-smi
  • nvidia-container-toolkitnvidia-ctk CLI for CDI spec generation
Variable Value
LD_LIBRARY_PATH /usr/lib64 (ensures CDI-injected host driver libs are found by the dynamic linker)

The nvidia-container-toolkit provides nvidia-ctk which generates CDI (Container Device Interface) specs. charly calls EnsureCDI() before launching containers with GPU — if CDI specs don’t exist at /etc/cdi/nvidia.yaml, it runs nvidia-ctk cdi generate to create them. This enables GPU access in nested containers where host CDI specs are not inherited.

Arch’s nvidia-container-toolkit ships a pacman post-install hook that invokes nvidia-ctk cdi generate. On a host with no NVIDIA driver loaded (e.g., an AMD-only build host), the hook fails NVML init:

ERROR: failed to generate CDI spec: failed to initialize NVML: Driver Not Loaded
error: command failed to execute correctly

This is benign for the build — pacman still exits 0 (hooks don’t affect the parent transaction’s status), the candy finishes installing, and the resulting image works at runtime on a GPU-bearing host (where the CDI spec is generated via EnsureCDI() at container-launch time, not build time). You can ignore the error message. RPM installs don’t trigger the hook, so Fedora-based boxes don’t see this noise.

If you ever build inside CI where even-benign hook errors matter, either build arch-nvidia images on a GPU-bearing runner, or patch the candy to carry a build-time NVIDIA_VISIBLE_DEVICES=void env var so nvidia-ctk skips CDI gen.

NVIDIA VAAPI acceleration requires the container to know which DRM render node to bind the EGL context against. On multi-GPU hosts there may be /dev/dri/renderD128, /dev/dri/renderD129, … and the correct one depends on which physical card backs the NVIDIA driver.

charly does not bake a hardcoded DRINODE=/dev/dri/renderD128 into this candy. Instead, it auto-detects the correct render node at container-launch time and injects it as an environment variable. The detection + injection is consolidated in a single function, appendAutoDetectedEnv() in candy/plugin-deploy-pod/config_setup_helpers.go (relocated wholesale from charly-core’s charly/devices.go in the 2026-07-22 dead-code-radical-removal batch), which is called by charly config, charly start, and charly shell via that candy’s own config_setup.go / resolve.go / resolve_f12.go resolvers — so the three commands always produce the same env set.

Selkies is the primary consumer: pixelflux’s Wayland compositor uses DRINODE to open the render node and set up the VAAPI H.264 encoder. Without the injection, selkies would fall back to software encode (libx264) and lose ~40% of its streaming bandwidth budget.

GPU device injection is consolidated into the single appendAutoDetectedEnv() function rather than scattered across the charly source tree. If you see DRINODE referenced in candy scripts, you can assume it was auto-detected and injected by charly, not set by the user.

See /charly-core:charly-doctor (Hardware Detection) for the detection probe and /charly-distros:rocm for the AMD-side counterpart using the same mechanism.

Cross-GPU portability (nvidia-base boxes on AMD hosts)

Section titled “Cross-GPU portability (nvidia-base boxes on AMD hosts)”

Boxes that declare base: nvidia (e.g., /charly-selkies:selkies-labwc-nvidia) still run cleanly on hosts with a different GPU vendor — the NVIDIA runtime libraries ride along as benign passengers. charly config auto-detects whatever the host actually exposes (e.g., /dev/dri/renderD128 + /dev/kfd for an AMD RDNA3), injects those device nodes + DRINODE, and Mesa handles rendering. For example, selkies-labwc-nvidia (base: nvidia) runs on an AMD gfx 11.0.0 host — all supervisord programs RUNNING, selkies streaming over Mesa, no CUDA calls attempted. The CUDA toolkit in the box simply goes unused.

Creates Vulkan ICD compatibility symlinks for nvidia-ctk CDI device injection.

  • /charly-image:layer — candy authoring reference (charly.yml schema, task verbs, service declarations)
  • /charly-check:check — declarative testing (check: block, charly check box, charly check live)