Aller au contenu
Développement medium

Le socle de la stack souveraine : Ollama, Qdrant, LiteLLM

9 min de lecture

logo python

Avant l'assistant, avant l'interface, il faut le socle — les services dont tout le reste dépend. Cette première étape du fil rouge assemble, en un seul Docker Compose, les trois fondations de la stack souveraine : Ollama pour les modèles, Qdrant pour la base vectorielle, LiteLLM comme passerelle d'accès aux modèles. Et elle le fait sécurisé dès le départ : un réseau interne, des services non exposés, des clés sur chaque accès, des ports liés à la machine locale. Vous obtiendrez un socle vérifié par six tests — la fondation sur laquelle l'assistant documentaire viendra se brancher. Public visé : développeur qui a suivi le parcours et veut l'assembler en infrastructure réelle.

  • Assembler Ollama, Qdrant et LiteLLM en un Docker Compose.
  • Accélérer Ollama par GPU et le garder non exposé.
  • Protéger Qdrant et LiteLLM par des clés.
  • Isoler les services sur un réseau interne, lier les ports à localhost.
  • Valider le socle avant de bâtir dessus.

Le socle réunit trois rôles distincts, chacun déjà connu du parcours, désormais assemblés.

Ollama sert les modèles — le modèle de chat Mistral Small 3.2 et le modèle d'embedding nomic-embed-text. Mistral Small est un modèle à poids ouverts de Mistral AI, une entreprise française : pour une stack qui se veut souveraine, le modèle relève du même périmètre de maîtrise que le reste de l'infrastructure. Ollama s'exécute sur GPU pour des temps de réponse acceptables.

Qdrant est la base vectorielle : c'est elle qui stockera, à l'étape suivante, le corpus indexé de l'assistant documentaire.

LiteLLM est la passerelle : un point d'accès unique aux modèles, qui ajoute une clé maître, et qui découplera l'assistant du détail des modèles servis derrière.

Ces trois services sont décrits dans un seul fichier compose.yml. Un docker compose up lève tout le socle.

Le service Ollama réclame deux choses : l'accès au GPU, et un volume pour conserver les modèles téléchargés.

ollama:
image: ollama/ollama:0.12.3@sha256:c622a7adec67cf5bd7fe1802b7e26aa583a955a54e91d132889301f50c3e0bd0
restart: unless-stopped
networks:
- souveraine
volumes:
- ollama_data:/root/.ollama
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]

Le bloc deploy.resources.reservations.devices réserve le GPU au conteneur — c'est lui qui rend l'inférence rapide. Le volume ollama_data conserve les modèles : ils ne sont téléchargés qu'une fois.

Un point décisif de sécurité : Ollama n'a aucune ligne ports. Il n'est pas exposé — ni à l'hôte, ni au réseau. Seuls les autres services du socle le joignent, par son nom sur le réseau interne. Un service sans port publié n'offre aucune surface d'attaque depuis l'extérieur.

Qdrant stocke les vecteurs. Par défaut, son API est ouverte — inacceptable pour une stack qu'on veut sûre. On lui impose une clé d'API.

qdrant:
image: qdrant/qdrant:v1.18.0@sha256:b3063c673f3973877c038eeecc392bad5011f072ee7892b56c9a8e204a3bdea9
restart: unless-stopped
networks:
- souveraine
environment:
QDRANT__SERVICE__API_KEY: ${QDRANT_API_KEY}
volumes:
- qdrant_data:/qdrant/storage
ports:
- "127.0.0.1:6333:6333"

La variable QDRANT__SERVICE__API_KEY active la protection : toute requête à l'API doit désormais porter l'en-tête api-key. Sans clé, Qdrant répond 403.

Le port, lui, est publié sur 127.0.0.1:6333 — et non 0.0.0.0:6333. La différence est capitale : lié à 127.0.0.1, Qdrant n'est joignable que depuis la machine hôte, jamais depuis le réseau. C'est ce dont l'assistant et les tests ont besoin, sans ouvrir la base à l'extérieur.

LiteLLM s'intercale entre les applications et Ollama. Il offre une API compatible OpenAI unique, protégée par une clé maître, et un fichier de configuration qui déclare les modèles.

litellm:
image: ghcr.io/berriai/litellm:main-v1.74.3-stable@sha256:229665e372493ab0948f36ca813a5a20f352e258424383d6a7043bf088eb12fb
command: ["--config", "/app/config.yaml", "--port", "4000"]
networks:
- souveraine
volumes:
- ./litellm-config.yaml:/app/config.yaml:ro
environment:
LITELLM_MASTER_KEY: ${LITELLM_MASTER_KEY}
ports:
- "127.0.0.1:4000:4000"
depends_on:
- ollama

La configuration relie les noms de modèles publics à leur adresse réelle sur le réseau interne — http://ollama:11434.

model_list:
- model_name: mistral-small
litellm_params:
model: ollama_chat/mistral-small3.2
api_base: http://ollama:11434
- model_name: nomic-embed-text
litellm_params:
model: ollama/nomic-embed-text
api_base: http://ollama:11434
litellm_settings:
drop_params: true

Deux détails comptent. Le préfixe ollama_chat/ pour le chat, ollama/ pour les embeddings — chacun route vers le bon mécanisme d'Ollama. Et drop_params: true : un client OpenAI envoie des paramètres qu'Ollama ne connaît pas (comme encoding_format) ; sans ce réglage, LiteLLM rejette la requête. Avec, il retire poliment les paramètres inconnus.

La sécurité ne s'ajoute pas après coup — elle est dans la structure du compose.yml. Quatre choix la portent.

Le réseau interne d'abord. Tous les services rejoignent un réseau souveraine ; ils se parlent par leur nom de service, jamais par une adresse exposée. Ollama, qui n'a aucun port publié, n'existe que sur ce réseau.

Les ports liés à 127.0.0.1 ensuite. Qdrant et LiteLLM doivent être joignables depuis l'hôte — pour l'assistant, pour les tests. Mais 127.0.0.1: les enferme sur l'hôte : invisibles depuis le réseau. L'exposition vers de vrais utilisateurs est réservée à l'étape suivante, derrière un reverse proxy.

Les clés sur chaque accès : clé d'API Qdrant, clé maître LiteLLM. Aucun service n'est ouvert.

Les secrets hors du dépôt enfin. Les clés vivent dans un fichier .env, ignoré par Git. Un .env.example sert de modèle, sans valeur réelle. On ne versionne jamais un secret.

Le socle se lève en quelques commandes, puis se vérifie.

Fenêtre de terminal
cp .env.example .env # puis y mettre des valeurs générées
docker compose up -d
docker compose exec ollama ollama pull mistral-small3.2
docker compose exec ollama ollama pull nomic-embed-text

Un socle qu'on ne vérifie pas est un socle dont on ne sait rien. La suite de tests du lab le contrôle sur six points : la configuration du proxy (test déterministe), la santé de Qdrant, le fait que Qdrant et LiteLLM exigent une clé — deux tests de sécurité —, et enfin un chat et un embedding réels à travers la passerelle. Six tests verts : le socle est prêt à porter l'assistant.

SymptômeCause probableSolution
Ollama démarre sans GPURuntime nvidia absentInstaller le nvidia container toolkit
model not foundModèles non tirésdocker compose exec ollama ollama pull ...
Embedding rejeté par le proxydrop_params absentAjouter litellm_settings: drop_params: true
Qdrant accepte des requêtes sans cléQDRANT__SERVICE__API_KEY non définiDéfinir la variable, vérifier le .env
litellm ne joint pas Ollamaapi_base incorrectPointer sur http://ollama:11434 (nom de service)
  • Le socle réunit Ollama, Qdrant et LiteLLM en un seul Docker Compose.
  • Ollama tourne sur GPU et n'a aucun port — il vit seulement sur le réseau interne.
  • Qdrant et LiteLLM sont protégés par des clés ; aucun service n'est ouvert.
  • Les ports sont liés à 127.0.0.1 — joignables depuis l'hôte, pas depuis le réseau.
  • drop_params: true est obligatoire pour servir des embeddings Ollama via LiteLLM.
  • Les secrets vivent dans un .env non versionné ; le socle se valide par des tests.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn