Det här är en dokumentationsbaserad design, inte ett färdigtestat labb. Upplägget har ännu inte testats från början till slut på EC2. Kostnaderna är uppskattningar, inte uppmätta utgifter. Kommandon och förväntade resultat är ett underlag för egen verifiering.
Att starta en maskin med NVIDIA-kort är inte samma sak som att bygga en AI-plattform. Drivrutiner ska fungera med operativsystemet. Containrar ska kunna nå kortet. Arbetslaster behöver få resurser, gå att följa och kunna startas igen efter ett avbrott.
Med min bakgrund inom nätverk är jag nyfiken på just den kedjan. Här skissar jag ett litet labb för att undersöka den, utan att köpa egen GPU-hårdvara. Målet är att förstå infrastrukturen, inte att träna en stor språkmodell eller erbjuda en produktionstjänst.
En maskin räcker för första frågorna
Utgångspunkten är en EC2-instans av typen g6.xlarge med vanlig Ubuntu 24.04 LTS för x86. Enligt AWS specifikation för G6 har den 4 vCPU, 16 GiB RAM och en NVIDIA L4 med 24 GB VRAM. Systemminnet och GPU-minnet är olika resurser. Modeller, cache och övriga tjänster behöver rymmas inom båda begränsningarna.
- EC2 och Ubuntu 24.04g6.xlarge med en NVIDIA L4
- K3s och containerdKubernetes styr poddar och containerkörning
- NVIDIA GPU OperatorDrivrutin, Container Toolkit och Device Plugin gör kortet tillgängligt
- CUDA-podd och DCGM ExporterTestet använder kortet. Exportern visar GPU-mätvärden.
EBS lagrar system och beständiga filer vid sidan av beräkningslagren. Administration sker via SSH från den egna IP-adressen.
Jag väljer K3s eftersom ett Kubernetes-kluster då kan köras på samma maskin som arbetslasten. EKS är relevant när man vill ha ett förvaltat kontrollplan, men dess återkommande klusteravgift fortsätter även när GPU-noder är stoppade. För korta labbpass är det en kostnad jag vill undvika.
Avvägningen är tydlig. En enda nod betyder ingen hög tillgänglighet, och jag ansvarar själv för uppdateringar och återställning. När instansen stoppas försvinner hela klustrets tillgänglighet. Det är rimligt för lärande, inte en produktionsarkitektur.
Sätt gränser innan maskinen startas
Börja med AWS Budgets och aviseringar vid flera nivåer. Kontrollera sedan att kontot har tillräcklig G-kvot för 4 vCPU och att instanstypen finns tillgänglig i vald zon i Stockholm. En godkänd kvot garanterar inte ledig kapacitet.
Använd en säkerhetsgrupp som bara tillåter inkommande SSH på port 22 från My IP, alltså din aktuella publika adress med ett snävt nätprefix. Öppna inte Kubernetes API på port 6443, NodePort eller en notebook mot internet. Kör administrationskommandona på servern genom SSH. Utgående anslutningar behövs för paket och containerbilder.
Välj en krypterad EBS-volym, exempelvis 100 GiB gp3, för system, containerbilder och labbfiler. Undvik NAT Gateway och lastbalanserare i första versionen. De behövs inte för den här övningen och kan skapa kostnader som inte syns i GPU-priset.
Låt en komponent äga drivrutinerna
En Deep Learning AMI, ofta kallad DLAMI, kan vara praktisk för att snabbt köra AI-ramverk. Här är poängen i stället att låta GPU Operator hantera NVIDIA-drivrutinen och Container Toolkit. Därför väljer jag vanlig Ubuntu utan förinstallerad NVIDIA-stack.
Blanda inte installation från operativsystemets pakethanterare med operatörens drivrutinshantering utan ett medvetet val. Om du använder en AMI med befintliga drivrutiner beskriver NVIDIAs installationsguide hur operatörens drivrutinsinstallation stängs av. Det är ett annat upplägg än detta.
Välj och dokumentera exakta versioner före installation. Jämför Ubuntu, den faktiska AWS-kärnan, K3s Kubernetes-version, containerd och operatörens komponenter med NVIDIAs kompatibilitetsmatris. Att Ubuntu-versionen finns med betyder inte att varje kärna och drivrutinskombination fungerar. Installera matchande kärnheaders om drivrutinen ska byggas på noden.
Installera sedan den valda K3s-versionen och Helm enligt respektive dokumentation. Använd K3s kubeconfig för Helm, men gör inte administratörsfilen läsbar för alla. Installera GPU Operator i ett eget namespace med en uttryckligen vald chartversion och granskade Helm-värden.
K3s har egna sökvägar för containerd. Konfigurationen finns normalt i /var/lib/rancher/k3s/agent/etc/containerd/config.toml och socketen i /run/k3s/containerd/containerd.sock. Anpassa operatörens Toolkit-inställningar efter dem. K3s dokumentation om containerd beskriver också version 2 och mallen config-v3.toml.tmpl. Ändra inte bara en genererad fil som skrivs över vid omstart.
GPU-injektion via CDI eller NVIDIA-runtime måste stämma med den valda operatörsversionen. Exemplet nedan förutsätter fungerande CDI eller NVIDIA som standardruntime. Om installationen i stället kräver explicit runtimeklass, lägg runtimeClassName: nvidia under spec efter att den runtimeklassen har konfigurerats. Det här integrationssteget behöver verifieras, inte antas fungera genom ett generellt installationskommando.
Börja med ett litet CUDA-test
Kontrollera först att noden är Ready, operatörens poddar är friska och att nodens Allocatable visar en resurs med namnet nvidia.com/gpu och värdet 1. Följ installationsguidens hälsokontroller. En nod kan vara Ready utan att GPU-kortet fungerar.
sudo k3s kubectl get nodes
sudo k3s kubectl get pods -n gpu-operator
sudo k3s kubectl get clusterpolicy
sudo k3s kubectl describe nodes
Skapa filen cuda-vectoradd.yaml på labbservern med följande innehåll. Bilden kommer från NVIDIAs CUDA-exempel och adderar två vektorer. Ubuntu 22.04 i bildnamnet beskriver containerns användarmiljö, inte värdens operativsystem.
apiVersion: v1
kind: Pod
metadata:
name: cuda-vectoradd
spec:
restartPolicy: Never
containers:
- name: cuda-vectoradd
image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda12.5.0-ubuntu22.04
resources:
limits:
nvidia.com/gpu: 1
Starta podden och läs loggen när containern har startat. Nedladdning av bilden kan ta tid.
sudo k3s kubectl apply -f cuda-vectoradd.yaml
sudo k3s kubectl get pod cuda-vectoradd
sudo k3s kubectl logs pod/cuda-vectoradd
Förväntat utfall är att podden blir Completed och loggen innehåller Test PASSED. Det är inte ett resultat som har erhållits i det här labbet ännu. Vid fel, börja med sudo k3s kubectl describe pod cuda-vectoradd och skilj schemaläggningsproblem från bildhämtning, runtime och drivrutinsfel.
Prova konkurrens och mät rätt saker
Nästa övning är två GPU-jobb samtidigt. Utan time-slicing eller annan delning tilldelas det enda GPU-kortet exklusivt. Om första podden håller det reserverat ska den andra bli Pending på grund av otillräcklig GPU-resurs. Kubernetes delar inte automatiskt kortet i halvor.
Vektorprovet avslutas snabbt. För ett tydligt kötest behövs därför två längre körningar, eller en testpodd som håller GPU-reservationen medan den väntar. När den första avslutas frigörs resursen. Pending kan också ha andra orsaker, så läs poddens schemaläggningshändelser innan du drar slutsatser.
DCGM Exporter kan ge mätvärden för exempelvis GPU-belastning, minne och temperatur. För historik behövs en insamlare, exempelvis Prometheus. Exportern mäter inte automatiskt applikationens svarstid, kötid, tokens per sekund eller svarskvalitet. De måtten behöver hämtas från applikationen. Hög GPU-belastning är inte i sig bevis på en bra AI-tjänst.
Stoppa, starta och testa igen
Gör en kontrollerad stop/start enligt AWS dokumentation om stopp och start. EBS-data finns kvar, medan lokal NVMe instance store är tillfällig och förloras vid stopp. Lägg därför inte enda kopian av modeller eller resultat där.
En automatiskt tilldelad publik IPv4-adress kan ändras efter starten. Kontrollera adressen före SSH och verifiera återigen nod, operatör och GPU. Radera sedan den gamla testpodden och skapa en ny med samma manifest. En gammal Completed-podd visar bara ett tidigare resultat, inte att GPU-kortet fungerar efter omstart.
sudo k3s kubectl delete pod cuda-vectoradd --ignore-not-found
sudo k3s kubectl apply -f cuda-vectoradd.yaml
sudo k3s kubectl get pod cuda-vectoradd
sudo k3s kubectl logs pod/cuda-vectoradd
Räkna på labbtimmar, inte bara timpris
Kalkylen antar Linux On-Demand i Stockholm, 0,854 USD per timme för g6.xlarge och 10 SEK per USD. Timpriset är ett prisantagande och växelkursen är en räknefaktor, inte en aktuell valutakurs. Kontrollera beloppen i AWS Pricing Calculator och vid start.
| Post | Antagande före moms |
|---|---|
| EC2 | 20 timmar gånger 0,854 USD gånger 10 ger ungefär 171 SEK. |
| EBS | 100 GiB gp3 under hela månaden uppskattas till 80 till 100 SEK utan extra köpt prestanda. |
| Publik IPv4 | En liten extra kostnad vid 20 timmars användning. En behållen Elastic IP kan kosta även under stopp. |
En planeringsbudget på ungefär 350 till 400 SEK ger viss marginal och utrymme för 25 procent moms om den är tillämplig. Större datatrafik, snapshots och extra tjänster behöver räknas separat. Kontinuerlig drift i 730 timmar blir däremot cirka 6 234 SEK enbart för EC2 före moms med samma antaganden.
En budget är ingen hård kostnadsgräns. Aviseringar kan komma med fördröjning. Använd gärna en stopptimer, men kontrollera dess behörigheter och att den verkligen fungerar. Bekräfta statusen Stopped i AWS efter varje pass. Då upphör instansens beräkningsdebitering, men EBS, snapshots och vissa adresser fortsätter att kosta. Stopp är inte samma sak som att avveckla labbet.
Bygg vidare först när grunden fungerar
När CUDA-test, resurskö och omstart är verifierade är nästa steg en liten modellserver med Triton eller vLLM. Välj en modell som ryms med marginal och mät applikationens beteende, inte bara GPU-kortet. Paketera därefter inställningar med Helm och prova GitOps för granskbara ändringar.
Namespaces hjälper till att organisera, men är inte ensamma en säkerhetsgräns. Komplettera med RBAC, resurskvoter, nätverkspolicyer och poddsäkerhet. GPU Operator behöver omfattande värdåtkomst och ska inte behandlas som en vanlig applikation. Infrastruktur som kod, IaC, blir ett senare steg för att återskapa och avveckla AWS-resurserna kontrollerat.
Det viktigaste resultatet vore en dokumenterad förståelse av vad som fungerar, vad som brister och vad varje labbpass kostar. Först då finns en grund att bygga vidare på.
Vi lär oss genom att prova.
Kevin