
Extensions Compose (extends, include)
Optimisez vos fichiers Docker Compose complexes en réutilisant la configuration grâce aux directives 'extends' et 'include'. Gardez vos projets DRY et maintenables.
Le défi de la complexité et de la répétition
A mesure que vos applications multi-conteneurs grandissent, vos fichiers `docker-compose.yml` peuvent devenir volumineux, complexes et répétitifs. Vous pourriez avoir besoin de configurations similaires pour différents environnements (développement, test, production) ou partager des définitions de services communes entre plusieurs projets. Gérer ces fichiers monolithiques devient difficile, augmentant le risque d'erreurs et violant le principe DRY (Don't Repeat Yourself).
Pour répondre à ce besoin d'organisation et de réutilisabilité, Docker Compose propose des mécanismes d'extension : principalement les directives `extends` et `include`. Ces fonctionnalités vous permettent de définir des configurations de base ou des fragments réutilisables dans des fichiers séparés, puis de les incorporer ou de les spécialiser dans votre fichier Compose principal. Cela conduit à des configurations plus modulaires, plus faciles à lire et à maintenir.
La directive `extends` : héritage de configuration de service
La directive `extends` permet à un service d'hériter de la configuration d'un autre service, potentiellement défini dans un autre fichier Compose. C'est un mécanisme d'héritage au niveau du service, utile pour créer des variations d'un service de base sans dupliquer toute sa configuration.
Syntaxe :services:
base-service: # Défini ici ou dans un autre fichier
image: ubuntu
environment:
- BASE_VAR=base_value
volumes:
- /data
my-service:
extends:
# Optionnel : Chemin vers un autre fichier Compose
file: common-services.yml
# Nom du service dont on hérite dans le fichier spécifié (ou le fichier courant)
service: base-service
# On peut surcharger ou ajouter des configurations ici
environment:
- MY_VAR=my_value # Ajoute ou surcharge BASE_VAR si redéfini
ports:
- "8080:80" # Ajouté spécifiquement pour my-service
command: /app/run # Surcharge la commande de base-serviceRègles de fusion :- Les clés simples (comme `image`, `command`, `restart`) sont surchargées par la configuration du service qui étend.
- Les listes (comme `ports`, `expose`, `depends_on`, `dns`) sont concaténées (les éléments des deux services sont ajoutés).
- Les dictionnaires (comme `environment`, `labels`, `volumes`, `devices`) sont fusionnés ; les clés définies dans le service qui étend surchargent celles du service de base. Pour `volumes`, si un même chemin de montage est défini dans les deux, celui du service qui étend l'emporte.
La directive `include` : composition de fichiers Compose
Introduite plus récemment avec la spécification Compose (utilisée par `docker compose` V2+), la directive `include` offre une approche de composition plus puissante et flexible. Au lieu d'hériter au niveau du service, `include` permet d'intégrer le contenu d'un ou plusieurs autres fichiers Compose dans votre fichier principal.
Syntaxe :`include` est une directive de premier niveau (au même niveau que `services`, `networks`, etc.). Elle prend un chemin de fichier unique ou une liste de chemins.
# docker-compose.yml (fichier principal)
# Inclure un seul fichier
include: ./common/base.yml
# Ou inclure une liste de fichiers (fusionnés dans l'ordre)
# include:
# - ./common/database.yml
# - ./services/backend.yml
# - ./services/frontend.yml
# On peut toujours définir des services, réseaux, etc. ici
# Ils seront fusionnés avec le contenu des fichiers inclus
services:
monitoring:
image: prom/prometheus
ports:
- "9090:9090"Fonctionnement : Docker Compose lit les fichiers spécifiés dans `include` et fusionne leur contenu (services, réseaux, volumes, etc.) avec le contenu du fichier principal. Les règles de fusion sont similaires à celles de l'utilisation de plusieurs fichiers avec l'option `-f` : les définitions dans les fichiers listés plus tard ou dans le fichier principal surchargent celles des fichiers précédents en cas de conflit pour une même clé (par exemple, si deux fichiers définissent un service nommé `web`).Cas d'usage :- Modularisation : Découper une application complexe en fichiers logiques (ex: `database.yml`, `backend.yml`, `monitoring.yml`) et les assembler dans un fichier principal.
- Partage de configurations communes : Créer un fichier `common.yml` contenant des réseaux ou des volumes partagés et l'inclure dans plusieurs projets différents.
- Superposition d'environnements : Avoir un `base.yml` et un `development.yml` (ou `production.yml`) et utiliser `include` pour les combiner.
`extends` vs `include` : Quand choisir quoi ?
Bien que les deux servent à la réutilisation, leur approche et leurs cas d'usage diffèrent :
- Utilisez `extends` si :
- Vous voulez créer des variations spécifiques d'un service unique de base.
- Vous avez besoin d'un mécanisme simple d'héritage pour surcharger quelques attributs d'un service.
- Vous travaillez peut-être avec d'anciennes versions de Compose (bien que `include` soit maintenant largement supporté).
- Utilisez `include` si :
- Vous voulez décomposer une application complexe en fichiers modulaires plus petits et plus gérables.
- Vous voulez partager des ensembles complets de services, réseaux ou volumes entre différents projets ou environnements.
- Vous préférez une approche de composition claire plutôt qu'un héritage potentiellement plus opaque.
- Vous utilisez une version récente de `docker compose` (V2+).
En général, pour les nouveaux projets et les refactorisations, `include` est souvent considéré comme l'approche la plus moderne et la plus flexible pour organiser des configurations Compose complexes.
Considérations pratiques et débogage
Lorsque vous utilisez `extends` ou `include`, la configuration finale de votre application résulte de la fusion de plusieurs fichiers et directives. Il est essentiel de pouvoir vérifier et comprendre cette configuration fusionnée.
La commande `docker compose config` est votre meilleure alliée. Elle lit tous les fichiers Compose spécifiés (via `include` ou l'option `-f`), effectue la fusion et l'interpolation des variables, puis affiche le résultat final au format YAML. C'est indispensable pour :
- Valider la syntaxe de l'ensemble de votre configuration.
- Comprendre comment les différentes parties ont été fusionnées et quelles valeurs ont finalement été appliquées.
- Déboguer les erreurs ou les comportements inattendus résultant de la fusion.
# Affiche la configuration complète après fusion des 'include' et interpolation
docker compose configAutres conseils :- Organisez vos fichiers de manière logique (par exemple, un dossier `compose/` avec des sous-dossiers `common/`, `services/`, `environments/`).
- Utilisez des chemins relatifs dans `extends` et `include` pour que votre configuration reste portable.
- N'abusez pas de l'imbrication : une structure trop profonde d'`extends` ou d'`include` peut devenir aussi difficile à gérer qu'un fichier monolithique.
- Combinez judicieusement avec les variables d'environnement et les fichiers `.env` pour gérer les différences spécifiques à l'environnement sans nécessiter systématiquement des fichiers Compose distincts.
En utilisant `extends` et surtout `include` de manière réfléchie, vous pouvez considérablement améliorer la maintenabilité, la lisibilité et la réutilisabilité de vos configurations Docker Compose, même pour les applications les plus complexes.