Am nevoie de nvidia-container-runtime și de ce? [închis] (Programare, Docker, Containere, Gpu, Nvidia Docker, Podman)

Nemo a intrebat.

Vreau să accesez GPU-urile mele NVIDIA din interiorul containerelor. Pot face acest lucru fără nvidia-container-runtime?

A cere un runtime Docker personalizat doar pentru a vorbi cu un dispozitiv pare foarte ciudat. Există un întreg univers de dispozitive PCI. De ce are nevoie acesta de propriul runtime? De exemplu, să presupunem că aș avea atât GPU NVIDIA, cât și AMD. Nu aș putea să le accesez pe ambele din interiorul unui container?

Înțeleg că nvidia-container-runtime îmi permite să controlez ce GPU-uri sunt vizibile prin intermediul NVIDIA_VISIBLE_DEVICES. Dar nu mă interesează acest lucru. Nu folosesc containere pentru a izola dispozitivele; folosesc containere pentru a gestiona CUDA/CUDNN/TensorFlow versiunea h*ll. Și dacă am făcut-o doresc să izolez dispozitivele, aș folosi același mecanism ca întotdeauna: Prin controlul accesului la nodurile din /dev.

Pe scurt, întregul design „custom runtime” mi se pare defectuos.

Așadar, întrebări:

  • Ce îmi scapă?
  • Pot obține acces la GPU-urile mele NVIDIA folosind runtime-ul Docker (sau podman) stock?
  • Dacă nu, de ce nu?

2 răspunsuri
Robert Crovella

Cu siguranță nu voi putea răspunde la toate întrebările imaginabile legate de acest lucru. Voi încerca să fac un rezumat. O parte din ceea ce scriu aici se bazează pe ceea ce este documentat aici și aici. Discuția mea aici se va concentra, de asemenea, pe linux și docker (nu pe Windows, nu pe singularity, nu pe podman etc.). De asemenea, este puțin probabil să pot aborda în detaliu întrebări de genul „de ce alte dispozitive PCI nu trebuie să facă acest lucru?”. De asemenea, nu încerc să fac descrierile mele despre modul în care funcționează docker perfect exacte pentru un expert în domeniu.

Driverul NVIDIA GPU are componente care rulează în spațiul utilizatorului și, de asemenea, alte componente care rulează în spațiul kernel. Aceste componente lucrează împreună și trebuie să fie în armonie. Acest lucru înseamnă că componentele din modul kernel pentru driverul XYZ.AB trebuie să fie utilizate numai cu componentele din spațiul de utilizator din driverul XYZ.AB (nu orice altă versiune) și invers.

În linii mari, docker este un mecanism pentru a oferi o prezență izolată a spațiului de utilizator linux care rulează deasupra nucleului linux (unde se află toate lucrurile din spațiul de kernel) și se interfațează cu acesta. Kernelul linux se află în mașina de bază (în afara containerului), iar mare parte/majoritatea codului linux din spațiul utilizatorului se află în container. Acesta este unul dintre factorii arhitecturali care vă permit să faceți lucruri interesante, cum ar fi rularea unui container Ubuntu pe un kernel RHEL.

Din punctul de vedere al driverului NVIDIA, unele dintre componentele sale trebuie să fie instalate în interiorul containerului, iar altele trebuie să fie instalate în afara containerului.

Pot obține acces la GPU-urile mele NVIDIA folosind runtime-ul Docker (sau podman) standard?

Da, puteți, iar acest lucru a fost făcut înainte de existența nvidia-docker sau a nvidia-container-toolkit. Trebuie să instalați exact același driver atât în mașina de bază, cât și în container. Ultima dată când am verificat, acest lucru funcționează (deși nu intenționez să ofer instrucțiuni aici.) Dacă faceți acest lucru, componentele driverului din interiorul containerului se potrivesc cu cele din afara containerului și funcționează.

Ce îmi scapă?

NVIDIA (și probabil și alții) ar dori un scenariu mai flexibil. Descrierea de mai sus înseamnă că, dacă un container a fost construit cu orice altă versiune de driver (decât cea instalată pe mașina de bază) nu poate funcționa. Acest lucru este incomod.

Scopul inițial al nvidia-docker a fost de a face următoarele: La momentul încărcării containerului, să instaleze în container componentele de execuție ale driverului, care sunt prezente în mașina de bază. Acest lucru armonizează lucrurile și, deși nu rezolvă toate scenariile de compatibilitate, rezolvă o grămadă dintre ele. Cu o regulă simplă „păstrați driverul de pe mașina de bază actualizat la cea mai recentă versiune”, se rezolvă efectiv orice scenariu de compatibilitate care ar putea apărea din cauza unei nepotriviri între driver/CUDA runtime. (Setul de instrumente CUDA și tot ceea ce depinde de acesta, cum ar fi CUDNN, trebuie doar să fie instalat în container).

După cum subliniați, nvidia-container-toolkit a preluat o varietate de alte funcționalități, probabil utile, de-a lungul timpului.

Nu petrec prea mult timp aici vorbind despre strategia de compatibilitate („forward”) care există pentru codul CUDA compilat și strategia de compatibilitate („backward”) care există atunci când vorbim despre un driver specific și despre versiunile CUDA acceptate de acel driver. De asemenea, nu intenționez să furnizez instrucțiuni de utilizare a nvidia-container-toolkit, care este deja documentat, iar multe întrebări/răspunsuri despre acesta există deja și ele.

Nu voi putea răspunde la întrebări ulterioare de genul „de ce a fost arhitecturat în acest fel?” sau „asta nu ar trebui să fie necesar, de ce nu faceți asta?”.

Comentarii

  • Acest răspuns este cu totul insuficient. Rulez aceste containere fără rădăcină și funcționează. Codul care rulează fără root nu este un „driver”, prin definiție. Aș dori să aflu mai multe despre ceea ce face de fapt, dar, din moment ce sunteți, în mod normal, în defensivă în legătură cu acest proiect îngrozitor, cred că voi afla de la sursă. Vă mulțumesc pentru timpul acordat. –  > Por Nemo.
  • Dacă doriți să revedeți sursa, vă puteți face o idee aici care sunt unele dintre „componentele spațiului utilizatorului” ale driverului la care m-am referit, care sunt montate în container, în momentul montării. –  > Por Robert Crovella.
Nemo

Pentru a răspunde la propria întrebare: Nu, nu avem nevoie de nvidia-container-runtime.

Bibliotecile partajate NVIDIA sunt strâns legate de fiecare versiune punctuală a driverului. NVIDIA îi place să spună că „driverul are componente care rulează în spațiul utilizatorului”, dar, desigur, aceasta este o contradicție în termeni. Așadar, pentru orice versiune a driverului, trebuie să faceți ca versiunea corespunzătoare a acestor biblioteci partajate să fie accesibilă în interiorul containerului.

Un scurt cuvânt despre motivul pentru care aceasta este o proiectare proastă: În afară de complexitatea suplimentară, bibliotecile partajate NVIDIA au dependențe de alte biblioteci partajate din sistem, în special C și X11. Dacă o versiune mai nouă a bibliotecilor NVIDIA ar necesita vreodată caracteristici din bibliotecile C sau X11 mai noi, un sistem care rulează aceste biblioteci mai noi nu ar putea găzdui niciodată un container mai vechi. (Deoarece containerul nu ar putea rula bibliotecile mai noi injectate). Capacitatea de a rula containere vechi pe sisteme noi este una dintre cele mai importante caracteristici ale containerelor, cel puțin în anumite aplicații. Cred că trebuie să sperăm că acest lucru nu se va întâmpla niciodată.

Comunitatea HPC și-a dat seama de acest lucru și l-a făcut să funcționeze cu ceva timp în urmă. Iată câteva instrucțiuni vechi pentru crearea unui container portabil Singularity GPU care injectează bibliotecile partajate NVIDIA necesare atunci când containerul rulează. Ați putea urma cu ușurință o procedură similară pentru a crea un container portabil OCI sau Docker GPU portabil.

În zilele noastre, Singularity acceptă un --nv pentru a injecta automat bibliotecile partajate necesare. De asemenea, suportă și o opțiune --rocm indicator pentru GPU AMD. (Da, AMD a ales același design prost.) Probabil că ați putea combina aceste stegulețe dacă aveți nevoie de ambele.

Toate aceste detalii sunt destul de bine documentate în manualul Singularity.

În concluzie: Dacă vă puneți aceeași întrebare ca și mine, încercați Singularity.