Ollama in Docker Compose met GPU en persistente modelopslag

Componeren-als-basis Ollama-server met GPU en persistentie.

Inhoud

Ollama werkt uitstekend op bare metal. Het wordt nog interessanter wanneer je het als een service behandelt: een stabiel eindpunt, vastgezet versies, persistente opslag en een GPU die ofwel beschikbaar is of niet.

Dit artikel richt zich op één doel: een reproduceerbare lokale of single-node Ollama-“server” met Docker Compose, inclusief GPU-versnelling en persistente modelopslag.

ollama docker compose

Het slaat bewust de algemene basis van Docker en Compose over. Wanneer je een compact overzicht nodig hebt van de commando’s die je het meest gebruikt (images, containers, volumes, docker compose), is de Docker Cheatsheet een goede metgezel.

Wanneer je HTTPS voor Ollama wilt, correcte streaming en WebSocket-proxying, en randcontroles (auth, time-outs, rate limits), zie dan Ollama achter een reverse proxy met Caddy of Nginx voor HTTPS streaming.

Voor hoe Ollama past naast vLLM, Docker Model Runner, LocalAI en de afwegingen bij cloud-hosting, zie LLM-hosting in 2026: Lokaal, Self-Hosted & Cloud-infrastructuur vergeleken.

Wanneer Compose wint van een bare metal-installatie

Een native installatie is soepel voor één ontwikkelaar op één machine. Op het moment dat je een van de volgende situaties hebt, begint Compose te winnen qua gebruiksgemak:

Een teamopstelling profiteert omdat de servicedefinitie een bestand is dat je kunt reviewen, versiebeheren en delen. Een single-node server profiteert omdat upgrades neerkomen op het aanpassen van een imagetag en een herstart, terwijl je modelopslag op zijn plek blijft (zolang het op een volume staat). Ollama neigt er ook naar om naast sidecars te leven: een webinterface, een reverse proxy, een auth-gateway, een vector-database of een agent-runtime. Compose is goed in “één commando om de hele stack te starten”, zonder je host in een snowflake te veranderen.

Deze aanpak sluit goed aan bij hoe de officiële Ollama-container is ontworpen: het image voert standaard ollama serve uit, exposeert poort 11434 en is bedoeld om staat onder een mountbare map te houden.

Een Compose-skelet dat echt nuttig is voor Ollama

Begin met twee beslissingen:

Ten eerste, hoe je versies vastzet. Het Docker Hub-image is ollama/ollama, dus je kunt een specifieke tag vastzetten in .env in plaats van te vertrouwen op latest.

Ten tweede, waar de modeldata zal worden opgeslagen. De officiële documentatie mount een volume naar /root/.ollama zodat modellen niet elke keer opnieuw worden gedownload wanneer de container wordt vervangen.

Hier is een Compose-bestand dat deze beslissingen vastlegt en de “knoppen” dicht bij de service houdt:

services:
  ollama:
    image: ollama/ollama:${OLLAMA_IMAGE_TAG:-latest}
    container_name: ollama
    restart: unless-stopped

    # Houd het standaard lokaal, exposeer het later als je het nodig hebt.
    ports:
      - "${OLLAMA_BIND_IP:-127.0.0.1}:11434:11434"

    # Persistente modellen en serverstaat.
    volumes:
      - ollama:/root/.ollama

    environment:
      # Het officiële image default al naar 0.0.0.0:11434 binnen de container,
      # maar het expliciet houden helpt wanneer je later dingen overschrijft.
      - OLLAMA_HOST=0.0.0.0:11434

      # Service-tuning.
      - OLLAMA_KEEP_ALIVE=${OLLAMA_KEEP_ALIVE:-5m}
      - OLLAMA_NUM_PARALLEL=${OLLAMA_NUM_PARALLEL:-1}
      - OLLAMA_MAX_LOADED_MODELS=${OLLAMA_MAX_LOADED_MODELS:-1}

      # Optioneel, maar relevant wanneer een browsergebaseerde UI direct met Ollama praat.
      # Zie het Netwerksectie voor waarom dit bestaat.
      - OLLAMA_ORIGINS=${OLLAMA_ORIGINS:-}

    # GPU-reservering is een apart sectie hieronder.
    # Voeg het alleen toe op hosts die daadwerkelijk NVIDIA GPUs hebben.

volumes:
  ollama: {}

Een bijpassende .env houdt upgrades saai:

# Zet de imagetag vast die je hebt getest.
OLLAMA_IMAGE_TAG=latest

# Standaard lokaal. Verander naar 0.0.0.0 wanneer je het bewust exposeert.
OLLAMA_BIND_IP=127.0.0.1

# Keep-alive aanpassingen cold-start latentie vs geheugenvoetafdruk.
OLLAMA_KEEP_ALIVE=5m

# Concurrentie-knoppen.
OLLAMA_NUM_PARALLEL=1
OLLAMA_MAX_LOADED_MODELS=1

# Laat leeg tenzij je browserclients serveert die Ollama direct raken.
OLLAMA_ORIGINS=

Een kleine maar belangrijke nuance: Ollama zelf heeft een standaard host-bind van 127.0.0.1:11434 in de algemene configuratie, maar het officiële containerimage zet OLLAMA_HOST=0.0.0.0:11434 zodat de service toegankelijk is via gepubliceerde poorten.

Als je een snelle gezondheidscontrole wilt zonder enige client SDKs te betrekken, bevat de Ollama API een “lijst lokale modellen” eindpunt op GET /api/tags.

Persistente modelopslag en de minst pijnlijkste manier om het te verplaatsen

Als je maar één ding onthoudt, laat het dan dit zijn: de container moet persistente opslag hebben, anders is elke rebuild een herdownload.

Ollama laat je de modelmap kiezen met OLLAMA_MODELS. In de referentie-implementatie is de standaard $HOME/.ollama/models, en het instellen van OLLAMA_MODELS overschrijft dat.

Binnen het officiële Docker-image mappt $HOME natuurlijk naar de /root-lay-out die wordt gebruikt door de gedocumenteerde volumemount (/root/.ollama), wat precies de reden is waarom de officiële docker run-voorbeelden die map mounten.

Er zijn twee opslagpatronen die in de praktijk goed werken:

Een benoemd Docker volume is het eenvoudigst en meest portabel. Het is ook makkelijk per ongeluk te wezen, dus het is de moeite waard om het intentioneel te benoemen (bijvoorbeeld ollama) en het stabiel te houden tijdens Compose-refactoringen.

Een bind-mount naar een dedicated schijf is beter wanneer modelgroottes beginnen met domineren van je root-filesystem. In dat geval mount je ofwel de gehele /root/.ollama naar dat schijf, of mount je een aangepaste map en wijs OLLAMA_MODELS daarheen.

Als je actief opslag herorganiseert, is dit waar een expliciete “modellen verplaatsen”-playbook helpt. Zie: move-ollama-models .

NVIDIA GPU-ondersteuning met Compose en het NVIDIA Container Toolkit

Ollama kan NVIDIA GPUs gebruiken in Docker, maar het image kan geen GPU uit het niets creëren. De host moet werkende NVIDIA-drivers en het NVIDIA Container Toolkit hebben, en Docker moet hierop geconfigureerd zijn. De Ollama Docker-documentatie noemt expliciet het installeren van nvidia-container-toolkit, het configureren van de runtime via nvidia-ctk runtime configure --runtime=docker, en het herstarten van Docker.

Aan de Compose-kant is de schone, moderne manier apparaatreserveringen. Docker documenteert GPU-toegang in Compose met deploy.resources.reservations.devices, met capabilities: [gpu], driver: nvidia, en ofwel count (inclusief all) of device_ids.

Voeg dit toe aan de ollama-service wanneer je op een NVIDIA-host bent:

deploy:
  resources:
    reservations:
      devices:
        - driver: nvidia
          count: all
          capabilities: [gpu]

Als je meerdere GPUs hebt en Ollama op specifieke apparaten wilt houden, schakel dan van count naar device_ids zoals gedocumenteerd door Docker (ze zijn onderling uitsluitend).

Je zult soms legacy Compose-voorbeelden zien die runtime: nvidia gebruiken. Dat kan mislukken op nieuwere setups met fouten zoals “unknown or invalid runtime name: nvidia”, wat een sterk hint is dat je moet overstappen naar het ondersteunde apparaatreserveringspatroon en ervoor zorgen dat het toolkit op de host is geconfigureerd.

Een nuttig detail dat in het openbaar verborgen ligt: het officiële ollama/ollama-image zet NVIDIA_VISIBLE_DEVICES=all en NVIDIA_DRIVER_CAPABILITIES=compute,utility. Dit zijn standaardknoppen die worden herkend door de NVIDIA-container-runtime, en ze zijn al aanwezig tenzij je ze overschrijft.

Om te bevestigen of je daadwerkelijk GPU-inferentie krijgt (niet alleen een container die start), adviseert Ollama om ollama ps te gebruiken en de “Processor”-kolom te controleren, wat toont of het model in GPU-geheugen staat.

Platform-reality check: Ollama merkt op dat GPU-versnelling in Docker beschikbaar is op Linux (en Windows met WSL2), en niet beschikbaar is op Docker Desktop voor macOS vanwege het gebrek aan GPU-pass-through.

Netwerkkeuzes: host vs bridge, poorten en CORS

Netwerk is waar de meeste “het loopt maar mijn app kan niet verbinden” bugs vandaan komen.

Bridge-netwerk met gepubliceerde poorten

Het standaard Compose-netwerk is een bridge-netwerk. In deze setup maakt het publiceren van 11434:11434 Ollama toegankelijk vanaf de host op poort 11434, terwijl andere containers ermee moeten praten via de servicenaam ollama (niet localhost). Veel mensen struikelen hierover omdat localhost binnen een container “deze container” betekent, niet “de Ollama-container”.

Ollama zelf draait een HTTP-server op poort 11434 (het image exposeert het), en de algemene conventie is dat clients http://localhost:11434 gebruiken op de host wanneer poorten zijn gepubliceerd.

Host-netwerk

network_mode: host kan verleidelijk zijn op een single-node server omdat het poortpublicatie verwijdert en localhost-semantiek eenvoudiger maakt. De afweging is dat je de isolatie- en namespacevoordelen van een bridge-netwerk verliest, en je vaker in poortconflicten komt.

Ollama intentioneel expose

Ollama op een normale installatie bindt standaard aan 127.0.0.1, en de gedocumenteerde manier om het bindadres te wijzigen is OLLAMA_HOST.

In Docker heb je twee lagen:

Ollama-bindadres, beheerd door OLLAMA_HOST (het containerimage default naar binding op alle interfaces binnen de container).

Toegankelijkheid van buiten de container, beheerd door Compose ports en de host firewall.

Een patroon dat ik leuk vind is “standaard lokaal binden” via 127.0.0.1:11434:11434, en dan pas switchen naar 0.0.0.0:11434:11434 wanneer ik een reden heb om het te exposen.

Browserclients en OLLAMA_ORIGINS

Als een browsergebaseerde UI of extensie Ollama direct aanroept, bevind je je in CORS-territorium. Ollama staat cross-origin requests toe van 127.0.0.1 en 0.0.0.0 standaard, en je kunt extra oorsprongen configureren met OLLAMA_ORIGINS.

Dit maakt ook op een single-node verschil, omdat “het werkt met curl” niet betekent “het werkt vanuit een browserapp”.

Upgrade- en rollbackpatronen die passen bij een single-node server

Ollama evolueert snel. Je Compose-bestand kan dat een kalm proces maken in plaats van een late-night verrassing.

Upgrade door een tag te bomen, niet door te hopen dat “latest” zich goed gedraagt

De meest praktische upgrade-strategie is om het image vast te zetten op een bekende goede tag in .env, en het intentioneel te bomen. Het image wordt gepubliceerd als ollama/ollama op Docker Hub.

Omdat modeldata en serverstaat worden opgeslagen onder een gemounte map (/root/.ollama in de officiële documentatie), impliceert het vervangen van de container niet het herdownloaden van modellen.

Rollback is gewoon het tag terugzetten

Rollback is hetzelfde mechanisme in omgekeerde volgorde: zet de vorige tag, hercreëer de container, behoud hetzelfde volume. Dit is waar het vastzetten zijn waarde bewijst.

Datamigratie gaat grotendeels over opslagpaden

De meeste “migraties” in een single-node setup gaan niet over databaseschema’s. Het gaat over schijflay-out. Als je de modelmap verandert (via OLLAMA_MODELS) of het gemounte volume naar een nieuwe schijf verplaatst, voer je een datamigratie uit, of je het zo noemt of niet.

Als je een praktische gids wilt voor het herorganiseren van de modelmap op echte machines, zie: move-ollama-models .

Een laatste opmerking die makkelijk over het hoofd wordt gezien: de Ollama API-documentatie zegt expliciet dat de API stabiel en backwards compatible wordt verwacht, met zeldzame deprecities die in release notes worden aangekondigd. Dit maakt “upgrade de server, houd clients werkend” een redelijke standaardverwachting voor een single-node service-eindpunt.

Veelvoorkomende falen: GPU-rechten, driver-mismatch en OOM

Dit sectie is doelbewust symptoomgedreven. Het doel is niet “elk mogelijke Docker-fout”, alleen de falen die specifiek optreden in Ollama + GPU + persistente opslag setups.

GPU zichtbaar op de host, ontbrekend in de container

Als de host een werkende NVIDIA-driver heeft maar de container geen GPU ziet, zijn de oorzaken vaak:

Het NVIDIA Container Toolkit is niet geïnstalleerd of de Docker-runtime is niet geconfigureerd via nvidia-ctk. Ollama’s Docker-documentatie noemt dit direct.

Compose reserveert geen GPU-apparaat. De ondersteunde manier is deploy.resources.reservations.devices met de gpu-capaciteit zoals gedocumenteerd door Docker.

Een legacy runtime: nvidia-configuratie wordt gebruikt op een daemon die het niet herkent, wat resulteert in “unknown or invalid runtime name: nvidia”.

Voor validatie geeft ollama ps je een pragmatische check: het toont of een model in GPU-geheugen is geladen.

Toegang geweigerd op GPU-apparaten

De “toegang geweigerd”-variant van GPU-falen wijst typisch op omgevingsbeperkingen in plaats van Ollama zelf. Voorbeelden zijn rootless Docker draaien, beveiligingsbeleid, of apparaatnodes niet zoals verwacht worden blootgesteld. De Docker Compose GPU-ondersteuningsdocumentatie is expliciet dat de host GPU-apparaten moet hebben en dat de Docker-daemon dienovereenkomstig moet worden ingesteld.

Bij twijfel, vermindert de variabelen: bevestig de toolkit-configuratie (host), bevestig dan GPU-reservering (Compose), en bevestig dan GPU-gebruik (ollama ps).

Foute driver, foute verwachting

Ollama in Docker vertrouwt op de host-drivertstack. Als de host-driver ontbreekt, te oud is of verkeerd is geconfigureerd, zie je falen die eruitzien als “Ollama is kapot” maar eigenlijk “CUDA-stack is niet bruikbaar”. De officiële documentatie plaatst het container-toolkit en de Docker-daemon-configuratie als vereisten voor NVIDIA GPU-gebruik.

Out of memory: VRAM of RAM verdwijnt snel

OOM is de meest voorspelbare faalmode voor lokale inferentie, en het is meestal zelfopgelegd door configuratie.

Ollama ondersteunt concurrente verwerking via meerdere geladen modellen en parallelle verzoekverwerking, maar het is beperkt door beschikbaar geheugen (system RAM bij CPU-inferentie, VRAM bij GPU-inferentie). Wanneer GPU-inferentie wordt gebruikt, moeten nieuwe modellen passen in VRAM om concurrente modelloads toe te staan.

Twee configuratiedetails zijn het waard om te behandelen als eersteklas “server-instellingen”:

OLLAMA_NUM_PARALLEL verhoogt parallelle verzoekverwerking per model, maar vereist geheugen schaalt met OLLAMA_NUM_PARALLEL * OLLAMA_CONTEXT_LENGTH.

OLLAMA_KEEP_ALIVE beheert hoe lang modellen geladen blijven (standaard is 5 minuten). Modellen geladen houden vermindert cold-start latentie, maar het pikt ook geheugen vast.

Als je een single-node service onder belasting stabiliseert, zien de niet-dramatische fixes er meestal zo uit:

Verlaag parallelisme en context-standaarden voordat je iets anders verandert.

Beperk hoeveel modellen er gelijktijdig geladen mogen blijven.

Overweeg geheugenreductiefuncties zoals Flash Attention (OLLAMA_FLASH_ATTENTION=1) en lagere precisie K/V cache-types (OLLAMA_KV_CACHE_TYPE) wanneer je bottleneck geheugen is, niet ruwe rekenkracht.

Wanneer het geen Ollama is: Docker Model Runner kiezen in plaats daarvan

Soms is de “fout” eigenlijk een tooling-mismatch. Als je organisatie al standaardiseert op Docker-native artefacten en workflows, kan Docker Model Runner (DMR) een betere fit zijn dan Ollama als een langlevende service-container draaien.

Docker positioneert DMR als een manier om modellen direct via Docker te beheren, draaien en serveren, trekkend van Docker Hub of andere OCI-registers, en OpenAI-compatibele en Ollama-compatibele APIs serveren.

Het ondersteunt ook meerdere inferentie-engines (inclusief llama.cpp, en vLLM op Linux met NVIDIA GPUs), wat kan uitmaken als je om doorvoerkenmerken geeft, niet alleen “een model lokaal draaien”.

Als je een praktisch commando-overzicht en een dieper vergelijkingshoek wilt, zie: Docker Model Runner Cheatsheet: Commando’s & Voorbeelden.