Docker - Les Compositions

by Tyleo Dv. Delaware

Share

Avec Docker, la création de conteneurs peut s'avérer assez longue et perturbante. Ainsi, la méthode des compositions docker avec docker-compose permet de simplifier fortement la conception d'installations Docker complexes. Le principe est basé sur un fichier docker-compose.yml utilisant le format YAML/YML dont la comprehension est assez facile à saisir.

Le langage YAML/YML est sensible à la casse et aux espaces/tabulations. En cas d'erreur de tab/space, la composition est tout simplement ignorée et une erreur sortira. Rien n'est créé si une erreur est générée.
{.is-warning}

La Composition - Les Bases

Concept de Services

Lors de la création d'un Compose, on parlera de services et on nommera ces derniers. Par défaut, Docker choisira les noms des conteneurs mais nous pouvons les spécifier si besoin.

Exemple basique

services:
  nom_service1:
    image: fournisseur/image:versiontag
    container_name: mon_conteneur1
    ports:
      - 80:80
      - 443:443
    volumes:
      - /données:/data
      - /ssl:/etc/ssl
    entrypoint: /init

Ce Compose basique permet de voir les paramêtres de bases d'un compose. C'est à dire :

Le tag latest est courant : En effet, cela permet d'avoir toujours la dernière version de l'image. Attention cependant : Si vous souhaitez figer la version entre les up, il faudra utiliser un tag fixe. Voir la page Docker Hub de l'image dans l'onglet "Tags".
Depuis la version 3 du programme Docker-Compose, l'indication de version avant service: n'est plus obligatoire. Elle peut être encore présente dans des composes sur les gits des applications. Lorsque version: n'est pas précisé, alors la dernière version du composite est utilisé, la plupart du temps, cela n'a aucun effet si vous n'utiliser pas de fonction très avancée.
{.is-info}

Exemple Basique MultiServices sans Dépendances

Ici, nous vous montrons un exemple de compose méttant en scéne plusieurs services.

services:
	nom_service1:
    image: fournisseur/image:versiontag
    container_name: mon_conteneur1
    ports:
      - 80:80
      - 443:443
    volumes:
      - /données:/data
      - /ssl:/etc/ssl
    entrypoint: /init
  nom_service2:
  	image: fournisseur2/image2:versiontag
    container_name: mon_conteneur2
    ports:
    	- 336:3336
      - 8800:8080
    volumes:
    	- /données/sql:/var/lib/mysql

Dans cet exemple, nous avons :

Exemple Basique MultiServices avec Dépendances

Contrairement au précedent exemple, nous allons relier les services en définissant une dépendance.

services:
	nom_service1:
    image: fournisseur/image:versiontag
    container_name: mon_conteneur1
    ports:
      - 80:80
      - 443:443
    volumes:
      - /données:/data
      - /ssl:/etc/ssl
    depends_on:
    	- nom_service2
    entrypoint: /init
  nom_service2:
  	image: fournisseur2/image2:versiontag
    container_name: mon_conteneur2
    ports:
    	- 336:3336
      - 8800:8080
    volumes:
    	- /données/sql:/var/lib/mysql

Ici, nous ajoutons depends_on: et listons les services dont dépend ce service. Une dépendance est a sens unique logique. Mais les deux conteneurs pourront communiquer l'un vers l'autre et l'autre vers l'un. A ne pas confondre avec links: !

Une dépendance permet aux deux conteneurs de connaître, par DNS interne, le nom et l'IP de l'autre conteneur. Ceci est souvent utilisé pour des bases SQL externes ou des services liés. Ce qui permet aussi de les relier avec une sécurité avancée niveau ports, car le port SQL ne doit jamais être exposé au Web ou a l'Intranet/Réseau Local
{.is-info}

Fonctionnement Général

Les ports

Dans les compositions, vous définissez les ports exposé a Internet ou au Réseau par la partie suivante :

		ports:
    	- 80:8080
      - 443:4443

Le fonctionnement est défini tel que : [port externe]:[port interne].
Il est aussi possible de définir le mode de communication des ports. Par défaut, c'est l'accés par TCP qui est défini.

		ports:
    	- 80:8080/tcp
      - 443:4443/tcp

Définir un mode permet d'interdir l'usage de l'autre mode. Les modes disponibles sont :

		ports:
    	- 80:8080/tcp
      - 80:8080/udp
      - 443:4443/tcp
      - 443:4443/udp

Ici, les ports seront accessible par TCP et UDP.

Attention, l'activation d'UDP sur des services qui ne le nécessite pas du tout est un potentiel risque de sécurité important. L'application et le conteneur n'ayant pas de prévention UDP, il est possible de pirater ce conteneur en utilisant l'UDP. Ainsi, la prudence est de rigueur ! Par défaut, on active jamais UDP.
{.is-warning}

Port Overlap, c'est quoi ?

Un Port Overlap est un phoénomen qui se produit lorsque un conteneur, un compose ou un stack demande l'accés a un port déjà utilisé par un autre service sur Docker ou sur l'Hôte. Sur l'hôte, chaque port ne peut être utilisé par Docker qu'une seule fois. Ainsi, il faudra s'organiser afin de permettre l'usage d'un autre port. Exemple :

Si l'OS a un serveur Apache HTTPD installé en dur (sans Docker), et que Docker met en service un Nginx PM sur le port 80, c'est Nginx PM qui sera prioritaire. Tout les ports ne font pas d'Overlap pour des services sur l'OS. Mais ce sont toujours ceux de Docker qui seront délivrés en premier.
{.is-info}

Ici, il faudra trouver un port alternatif pour HTTPD. Dans cette situations, deux possibilités :

  1. Respecter les standards mais aussi ses limites, et utiliser le port 8080, deuxiéme port HTTP standard au lieu de 80.
  2. Ne pas respecter les standards, et être libre comme GNU, et utiliser le port 82 qui se trouve juste aprés le port 81 de Nginx Proxy Manager. Cette méthode est recommandé et permettra plus tard plus de possibilitées !

Pour l'organisation, il sera possible de s'organiser tel que :

Ainsi, nous maintenons une logique de ports et n'utilisons pas les standards.

Le seul cas ou l'usage des standards est requis, c'est quand l'application utilise de manière directe son port pour communiquer et pas SSL ou les requêtes HTTP/S. Ce qui reste extremement rare et largement dépassé. Mais techniquement, si elle le fesait, le port utilisé à l'exterieur sera celui choisi par vous et pas son port interne.
{.is-warning}

Exemple de déploiement #1 : Trilium Notes

Trilium Note est une application de prise de notes personnelle et privée. Docker Compose peut être utilisé pour déployer Trilium Note de manière simple et efficace. Voici les étapes à suivre pour déployer une instance de cette application :

Créez un fichier docker-compose.yml ou compose.yml dans un dossier de votre choix.

Ajoutez le contenu suivant au fichier docker-compose.yml :

version: '3'
services:
  trilium:
    image: zadam/trilium
    volumes:
      - ./trilium-data:/root/.local/share/trilium
    ports:
      - "8080:8080"

Créez un dossier trilium-data dans le même dossier que le fichier docker-compose.yml. Ce dossier sera utilisé pour stocker les données de Trilium Note.

Ouvrez un terminal et accédez au dossier contenant le fichier docker-compose.yml.

Exécutez la commande suivante pour démarrer le conteneur Trilium Note
Commande : docker-compose up -d

Vous pouvez maintenant accéder à Trilium Note en ouvrant un navigateur et en accédant à l'URL http://localhost:8080.

Pour arrêter le conteneur, exécutez la commande suivante :
docker-compose down

Notez que cette configuration utilise l'image Docker officielle de Trilium Note, qui est maintenue par la communauté et peut être mise à jour régulièrement. En outre, les données de Trilium Note sont stockées dans le dossier trilium-data, ce qui permet de conserver les données même si le conteneur est arrêté ou supprimé, il s'agit de la persistence des données.