Ollama no Docker Compose com GPU e Armazenamento Persistente de Modelos

Servidor Ollama com prioridade na composição, suporte a GPU e persistência.

Conteúdo da página

Ollama funciona muito bem em metal nu. Torna-se ainda mais interessante quando tratado como um serviço: um endpoint estável, versões fixas, armazenamento persistente e uma GPU que está disponível ou não.

Este post foca em um objetivo: um “servidor” local Ollama reprodutível ou de nó único usando Docker Compose, com aceleração de GPU e armazenamento persistente de modelos.

ollama docker compose

Ele intencionalmente ignora os conceitos básicos genéricos do Docker e Compose. Quando você precisa de uma lista compacta dos comandos que mais utiliza (imagens, containers, volumes, docker compose), a Folha de Truques do Docker é um bom companheiro.

Quando você quer HTTPS à frente do Ollama, streaming e proxy WebSocket corretos, e controles de borda (autenticação, tempos limite, limites de taxa), consulte Ollama atrás de um proxy reverso com Caddy ou Nginx para streaming HTTPS.

Para saber como o Ollama se encaixa junto com vLLM, Docker Model Runner, LocalAI e compensações de hospedagem em nuvem, consulte Hospedagem de LLM em 2026: Local, Auto-hospedado e Infraestrutura em Nuvem Comparados.

Quando o Compose vence uma instalação em metal nu

Uma instalação nativa é sem atritos para um único desenvolvedor em uma única máquina. No momento em que você tem qualquer uma das seguintes situações, o Compose começa a vencer em ergonomia:

Uma configuração de equipe se beneficia porque a definição do serviço é um arquivo que você pode revisar, versionar e compartilhar. Um servidor de nó único se beneficia porque as atualizações se transformam em uma mudança de tag de imagem e uma reinicialização, enquanto seu armazenamento de modelos permanece no lugar (desde que esteja em um volume). O Ollama também tende a viver ao lado de sidecars: uma interface web, um proxy reverso, um gateway de autenticação, um DB vetorial ou um runtime de agente. O Compose é bom em “um comando para iniciar a pilha inteira”, sem transformar seu host em uma snowflake (instância única e não padronizada).

Esta abordagem se alinha bem com a forma como o container oficial do Ollama é projetado: a imagem executa ollama serve por padrão, expõe a porta 11434 e é destinada a manter o estado sob um diretório montável.

Um esqueleto de Compose que é realmente útil para o Ollama

Comece com duas decisões:

Primeiro, como você vai fixar versões. A imagem no Docker Hub é ollama/ollama, então você pode fixar uma tag específica em .env em vez de confiar em latest.

Segundo, onde os dados do modelo viverão. A documentação oficial monta um volume em /root/.ollama para que os modelos não sejam baixados novamente cada vez que o container for substituído.

Aqui está um arquivo Compose que incorpora essas decisões e mantém os “botões” próximos ao serviço:

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

    # Mantenha local por padrão, exponha depois se precisar.
    ports:
      - "${OLLAMA_BIND_IP:-127.0.0.1}:11434:11434"

    # Modelos persistentes e estado do servidor.
    volumes:
      - ollama:/root/.ollama

    environment:
      # A imagem oficial já define por padrão 0.0.0.0:11434 dentro do container,
      # mas manter explícito ajuda quando você sobrescreve coisas depois.
      - OLLAMA_HOST=0.0.0.0:11434

      # Ajustes de serviço.
      - OLLAMA_KEEP_ALIVE=${OLLAMA_KEEP_ALIVE:-5m}
      - OLLAMA_NUM_PARALLEL=${OLLAMA_NUM_PARALLEL:-1}
      - OLLAMA_MAX_LOADED_MODELS=${OLLAMA_MAX_LOADED_MODELS:-1}

      # Opcional, mas relevante quando uma UI baseada em navegador fala diretamente com o Ollama.
      # Veja a seção de Rede para saber por que isso existe.
      - OLLAMA_ORIGINS=${OLLAMA_ORIGINS:-}

    # A reserva de GPU é uma seção separada abaixo.
    # Adicione apenas em hosts que têm GPUs NVIDIA.

volumes:
  ollama: {}

Um .env correspondente mantém as atualizações sem graça:

# Fixa a versão da imagem que você testou.
OLLAMA_IMAGE_TAG=latest

# Local por padrão. Mude para 0.0.0.0 quando você expor intencionalmente.
OLLAMA_BIND_IP=127.0.0.1

# Ajustes de keep-alive para latência de cold-start vs pegada de memória.
OLLAMA_KEEP_ALIVE=5m

# Botões de concorrência.
OLLAMA_NUM_PARALLEL=1
OLLAMA_MAX_LOADED_MODELS=1

# Deixe vazio a menos que esteja servindo clientes de navegador que atinjam o Ollama diretamente.
OLLAMA_ORIGINS=

Uma pequena, mas importante nuance: o próprio Ollama tem um bind de host padrão de 127.0.0.1:11434 na configuração geral, mas a imagem oficial do container define OLLAMA_HOST=0.0.0.0:11434 para que o serviço seja acessível através de portas publicadas.

Se você quer uma verificação de sanidade rápida sem envolver qualquer SDK de cliente, a API do Ollama inclui um endpoint “listar modelos locais” em GET /api/tags.

Armazenamento persistente de modelos e a maneira menos dolorosa de movê-los

Se você lembrar apenas uma coisa, que seja esta: o container deve ter armazenamento persistente, caso contrário, cada reconstrução é um re-download.

O Ollama permite que você escolha o diretório de modelos usando OLLAMA_MODELS. Na implementação de referência, o padrão é $HOME/.ollama/models, e definir OLLAMA_MODELS sobrescreve isso.

Dentro da imagem oficial do Docker, $HOME mapeia naturalmente para o layout /root usado pela montagem de volume documentada (/root/.ollama), que é exatamente por que os exemplos oficiais de docker run montam aquele diretório.

Existem dois padrões de armazenamento que tendem a funcionar bem na prática:

Um volume Docker nomeado é o mais simples e portátil. Também é fácil deixá-lo órfão acidentalmente, então vale a pena nomeá-lo intencionalmente (por exemplo ollama) e mantê-lo estável através de refatorações do Compose.

Uma montagem de vínculo (bind mount) em um disco dedicado é melhor quando os tamanhos dos modelos começam a dominar o seu sistema de arquivos raiz. Nesse caso, você monta todo o /root/.ollama naquele disco, ou monta um diretório personalizado e aponta OLLAMA_MODELS para ele.

Se você está reorganizando ativamente o armazenamento, é aqui que um playbook explícito de “mover modelos” ajuda. Consulte: move-ollama-models .

Suporte a GPU NVIDIA com Compose e o NVIDIA Container Toolkit

O Ollama pode usar GPUs NVIDIA no Docker, mas a imagem não pode fazer uma GPU aparecer magicamente. O host precisa de drivers NVIDIA funcionando e do NVIDIA Container Toolkit, e o Docker deve ser configurado para usá-lo. A documentação Docker do Ollama chama explicitamente a atenção para instalar nvidia-container-toolkit, configurar o runtime via nvidia-ctk runtime configure --runtime=docker e reiniciar o Docker.

No lado do Compose, a maneira limpa e moderna é a reserva de dispositivos. O Docker documenta o acesso à GPU no Compose usando deploy.resources.reservations.devices, com capabilities: [gpu], driver: nvidia e seja count (incluindo all) ou device_ids.

Adicione isso ao serviço ollama quando você estiver em um host NVIDIA:

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

Se você tiver várias GPUs e quiser manter o Ollama em dispositivos específicos, troque count por device_ids conforme documentado pelo Docker (eles são mutuamente exclusivos).

Algumas vezes você verá exemplos legados do Compose que usam runtime: nvidia. Isso pode falhar em configurações mais novas com erros como “unknown or invalid runtime name: nvidia”, o que é uma forte dica de que você deve migrar para o padrão de reserva de dispositivo suportado e garantir que o toolkit esteja configurado no host.

Um detalhe útil escondido à vista de todos: a imagem oficial ollama/ollama define NVIDIA_VISIBLE_DEVICES=all e NVIDIA_DRIVER_CAPABILITIES=compute,utility. Estes são botões padrão reconhecidos pelo runtime de container NVIDIA e eles já estão presentes a menos que você os sobrescreva.

Para confirmar se você está realmente obtendo inferência por GPU (não apenas um container que inicia), o Ollama recomenda usar ollama ps e verificar a coluna “Processor”, que mostra se o modelo está na memória da GPU.

Verificação de realidade da plataforma: O Ollama observa que a aceleração de GPU no Docker está disponível no Linux (e no Windows com WSL2), e não está disponível no Docker Desktop para macOS devido à falta de passagem de GPU.

Escolhas de rede: host vs bridge, portas e CORS

A rede é onde a maioria dos bugs “roda, mas meu app não consegue conectar” vêm de.

Rede bridge com portas publicadas

A rede padrão do Compose é uma rede bridge. Nesta configuração, publicar 11434:11434 torna o Ollama acessível do host na porta 11434, enquanto outros containers devem falar com ele usando o nome do serviço ollama (não localhost). Muitas pessoas tropeçam nisso porque localhost dentro de um container significa “este container”, não “o container Ollama”.

O próprio Ollama executa um servidor HTTP na porta 11434 (a imagem o expõe), e a convenção comum é que os clientes usem http://localhost:11434 no host quando as portas estão publicadas.

Rede do host

network_mode: host pode ser tentador em um servidor de nó único porque remove a publicação de portas e torna a semântica de localhost mais simples. A compensação é que você perde os benefícios de isolamento e namespace de uma rede bridge, e é mais provável que você encontre conflitos de porta.

Expondo o Ollama intencionalmente

O Ollama em uma instalação normal se vincula a 127.0.0.1 por padrão, e a maneira documentada de mudar o endereço de bind é OLLAMA_HOST.

No Docker, você tem duas camadas:

Endereço de bind do Ollama, controlado por OLLAMA_HOST (a imagem do container define por padrão o bind em todas as interfaces dentro do container).

Acessibilidade de fora do container, controlada por Compose ports e o firewall do host.

Um padrão que gosto é “bind local por padrão” via 127.0.0.1:11434:11434, e então mudar para 0.0.0.0:11434:11434 apenas quando tenho uma razão para expor.

Clientes de navegador e OLLAMA_ORIGINS

Se uma UI baseada em navegador ou extensão chama o Ollama diretamente, você está no território de CORS. O Ollama permite solicitações cross-origin de 127.0.0.1 e 0.0.0.0 por padrão, e você pode configurar origens adicionais usando OLLAMA_ORIGINS.

Isso importa mesmo em um único nó, porque “funciona com curl” não significa “funciona de um app de navegador”.

Padrões de atualização e rollback que se encaixam em um servidor de nó único

O Ollama evolui rapidamente. Seu arquivo Compose pode tornar isso um processo calmo em vez de uma surpresa na madrugada.

Atualização aumentando uma tag, não esperando que “latest” se comporte

A estratégia de atualização mais prática é fixar a imagem em uma tag conhecida e boa no .env, e aumentá-la intencionalmente. A imagem é publicada como ollama/ollama no Docker Hub.

Como os dados do modelo e o estado do servidor são armazenados sob um diretório montado (/root/.ollama na documentação oficial), substituir o container não implica re-baixar modelos.

Rollback é apenas trocar a tag de volta

O rollback é o mesmo mecanismo no sentido inverso: defina a tag anterior, recrie o container, mantenha o mesmo volume. É aqui que o fixar de tags paga o seu preço.

Migração de dados é principalmente sobre caminhos de armazenamento

A maioria das “migrações” em uma configuração de nó único não é sobre esquemas de banco de dados. São sobre layout de disco. Se você mudar o diretório de modelos (via OLLAMA_MODELS) ou mover o volume montado para um novo disco, você está fazendo uma migração de dados, chame isso como quiser.

Se você quer um guia prático para reorganizar o diretório de modelos em máquinas reais, consulte: move-ollama-models .

Uma nota final que é fácil de perder: a documentação da API do Ollama diz explicitamente que a API é esperada para ser estável e compatível com versões anteriores, com depreciações raras anunciadas nas notas de lançamento. Isso torna “atualizar o servidor, manter clientes funcionando” uma expectativa padrão razoável para um endpoint de serviço de nó único.

Falhas comuns: permissões de GPU, incompatibilidade de driver e OOM

Esta seção é intencionalmente baseada em sintomas. O objetivo não é “cada erro Docker possível”, apenas as falhas que aparecem especificamente em configurações Ollama + GPU + armazenamento persistente.

GPU visível no host, ausente no container

Se o host tem um driver NVIDIA funcionando, mas o container não vê uma GPU, as causas comuns são:

O NVIDIA Container Toolkit não está instalado ou o runtime Docker não está configurado via nvidia-ctk. A documentação Docker do Ollama chama isso diretamente.

O Compose não está reservando um dispositivo GPU. A maneira suportada é deploy.resources.reservations.devices com a capacidade gpu conforme documentado pelo Docker.

Uma configuração legada runtime: nvidia está sendo usada em um daemon que não a reconhece, produzindo “unknown or invalid runtime name: nvidia”.

Para validação, ollama ps dá uma verificação pragmática: mostra se um modelo está carregado na memória da GPU.

Permissão negada em dispositivos GPU

O sabor de falhas de GPU “permissão negada” geralmente aponta para restrições de ambiente em vez do próprio Ollama. Exemplos incluem executar Docker rootless, políticas de segurança, ou nós de dispositivo não sendo expostos como esperado. A documentação de suporte GPU do Docker Compose é explícita de que o host deve ter dispositivos GPU e que o daemon Docker deve ser definido conforme.

Em caso de dúvida, reduza as variáveis: confirme a configuração do toolkit (host), depois confirme a reserva de GPU (Compose), depois confirme o uso de GPU (ollama ps).

Driver errado, expectativa errada

O Ollama no Docker depende da pilha de drivers do host. Se o driver do host estiver ausente, muito antigo ou mal configurado, você verá falhas que parecem “Ollama está quebrado” mas são realmente “pilha CUDA não utilizável”. A documentação oficial coloca o toolkit do container e a configuração do daemon Docker como pré-requisitos para uso de GPU NVIDIA.

Fora de memória: VRAM ou RAM desaparece rápido

OOM é o modo de falha mais previsível para inferência local, e geralmente é auto-infligido por configuração.

O Ollama suporta processamento concorrente através de múltiplos modelos carregados e tratamento de solicitações paralelas, mas é limitado pela memória disponível (RAM do sistema em inferência CPU, VRAM em inferência GPU). Quando a inferência de GPU é usada, novos modelos devem caber na VRAM para permitir cargas de modelos concorrentes.

Dois detalhes de configuração valem a pena tratar como “configurações de servidor” de primeira classe:

OLLAMA_NUM_PARALLEL aumenta o processamento de solicitações paralelas por modelo, mas a memória necessária escala com OLLAMA_NUM_PARALLEL * OLLAMA_CONTEXT_LENGTH.

OLLAMA_KEEP_ALIVE controla por quanto tempo os modelos permanecem carregados (padrão é 5 minutos). Manter modelos carregados reduz a latência de cold-start, mas também fixa a memória.

Se você está estabilizando um serviço de nó único sob carga, as correções não dramáticas geralmente parecem:

Diminuir paralelismo e contextos padrão antes de mudar qualquer outra coisa.

Limitar quantos modelos são permitidos permanecerem carregados concomitantemente.

Considere recursos de redução de memória como Flash Attention (OLLAMA_FLASH_ATTENTION=1) e tipos de cache K/V de menor precisão (OLLAMA_KV_CACHE_TYPE) quando seu gargalo é memória, não computação bruta.

Quando não é o Ollama: escolher o Docker Model Runner em vez disso

Às vezes a “falha” é realmente uma incompatibilidade de ferramentas. Se sua organização já padroniza em artefatos e fluxos de trabalho nativos do Docker, o Docker Model Runner (DMR) pode ser um ajuste melhor do que executar o Ollama como um container de serviço de vida longa.

O Docker posiciona o DMR como uma maneira de gerenciar, executar e servir modelos diretamente via Docker, puxando do Docker Hub ou outros registros OCI, e servindo APIs compatíveis com OpenAI e Ollama.

Ele também suporta múltiplos motores de inferência (incluindo llama.cpp, e vLLM no Linux com GPUs NVIDIA), o que pode importar se você se importar com características de throughput, não apenas “executar um modelo localmente”.

Se você quer uma referência de comando prática e um ângulo de comparação mais profundo, consulte: Folha de Truques do Docker Model Runner: Comandos & Exemplos.