Docker - Conteneurisation

De Marijan Stajic | Wiki
Version datée du 28 février 2025 à 23:23 par Marijan (discussion | contributions) (→‎Docker Registry)
(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)
Aller à la navigation Aller à la recherche

Introduction

Docker banner.png

Comme expliqué dans la section sur la virtualisation légère, Docker est une plateforme de conteneurisation qui permet d'exécuter un seul processus ou un ensemble de processus. Ainsi, si nous avons des composants tels que Nginx et MySQL, nous devons créer deux conteneurs distincts, un pour chaque composant.

Déploiement

Ce logiciel de conteneurisation résout efficacement la problématique complexe du déploiement de plateformes et de logiciels, en garantissant un déploiement sans problèmes.

Par exemple, si nous utilisons plusieurs outils pour différentes applications (serveur web, base de données, etc.), il n'est pas nécessaire de vérifier leur compatibilité avec le système d'exploitation et le matériel utilisé.

De plus, lorsqu'un nouveau développeur rejoint l'équipe, il n'a pas à se soucier de la configuration de son système d'exploitation ni des versions des applications qu'il installe pour être en phase avec les autres. Il lui suffit simplement de déployer les conteneurs pour avoir un environnement identique à celui de l'équipe.

Lien avec DevOps

Docker et la conteneurisation sont des éléments fondamentaux de la méthodologie DevOps.

Prenons un exemple : imaginons une équipe de développeurs travaillant sur une application. Une fois celle-ci prête, ils envoient l’application accompagnée d’un guide listant toutes les dépendances nécessaires à l’équipe opérationnelle pour le déploiement. Cependant, ce processus est long et peut manquer de clarté.

C’est là qu’intervient Docker. Plutôt que de transmettre un simple guide, les développeurs créent une image Docker à l’aide d’un Dockerfile, qui contient toutes les configurations et dépendances nécessaires. Cette image est ensuite utilisée pour générer un conteneur que l’équipe opérationnelle peut facilement déployer, garantissant ainsi un environnement homogène et reproductible.

Notions

Docker introduit également les concepts de stateless, stateful et d'immutabilité, qui sont fréquemment utilisés dans l'univers de Docker.

  • Stateless et Stateful : Ce sont deux catégories de conteneurs. Les conteneurs stateful concernent les services tels que les bases de données MySQL, car ils conservent un état. Par exemple, si vous les éteignez puis les rallumez, vous les retrouverez dans le même état. En revanche, les conteneurs stateless sont l'inverse, c'est-à-dire qu'ils n'ont pas de mémoire persistante. Par exemple, avec les requêtes HTTP, vous devrez les refaire à chaque fois car le conteneur stateless ne conserve pas l'état entre les requêtes.
  • Immutabilité : C'est un concept essentiel pour nos conteneurs, car ils ne doivent pas conserver de données internes. En effet, toute modification apportée à un conteneur serait perdue lors de son redémarrage, à moins que ces données ne soient persistantes. Pour conserver des données, il est donc nécessaire de créer un volume dans lequel ces données peuvent être stockées de manière durable.

Docker Engine

Lors de l'installation de Docker sur une machine, trois composants principaux sont installés, formant ensemble le Docker Engine :

  • Docker CLI : Permet d’interagir avec Docker via la ligne de commande.
  • REST API : Interprète les commandes du CLI et les transmet au daemon.
  • Docker Daemon : Gère les objets Docker tels que les images, conteneurs, volumes et réseaux.

Il est également possible d’installer uniquement le Docker CLI sur une machine distante et de se connecter à un autre Docker Engine via la commande suivante :

docker -H [docker-engine-distant]:[port]

PID

Par défaut, dans un système Linux, plusieurs services démarrent automatiquement au lancement du système, chacun étant associé à un PID (Process ID). Lorsqu’une nouvelle application est exécutée, un nouveau PID est généré, et chaque PID est unique au sein du système.

Dans un conteneur Docker, lorsqu’un service est créé, celui-ci démarre dans un espace de processus isolé. Ainsi, le premier processus du conteneur aura le PID 1, le second le PID 2, et ainsi de suite.


Docker Namespace PID.png


Cependant, ces PIDs sont indépendants de ceux du système hôte. Le PID 1 à l’intérieur d’un conteneur ne correspond pas nécessairement au PID 1 du système hôte. Docker utilise un espace de noms de processus (PID namespace), ce qui permet à chaque conteneur d’avoir ses propres PIDs isolés, même si ces processus existent également dans l’espace de processus global du système.

Ressource

Lors du déploiement d’un conteneur, ni le système hôte ni Docker ne lui imposent de limite de ressources par défaut. Pour gérer cela, il existe une fonctionnalité appelée cgroups (Control Groups), qui permet de restreindre l’utilisation des ressources CPU, mémoire, disque et réseau.

Cependant, ces limites doivent être définies soit dans le fichier docker-compose.yml, soit lors de l’exécution du conteneur :

docker run --cpus=.[CPU] [Image]

Installation

Nous allons installer la version Docker Community Edition sur Debian 11 et pour ce faire, il faudra dans un premier temps créer un compte sur Docker Hub

1. Dans un premier temps, nous allons mettre à jour notre système et installer les packages de base pour Docker :

sudo apt-get update && sudo apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common

2. Ensuite, nous allons ajouter le repository de Docker :

curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"

3. Maintenant, nous allons pouvoir installer Docker sur la machine :

apt update && apt-get install docker-ce docker-ce-cli containerd.io

4. Pour terminer, il va falloir nous ajouter les droits afin de pouvoir gérer le dameon (processus). Il faudra ensuite ce déconnecter et reconnecter sur la session pour appliquer la modification :

usermod -aG docker root

5. Nous pouvons désormais nous connecter sur Docker avec le compte créer au tout début sur Docker Hub :

docker login

Liste de commandes

Voici une liste des commandes de base pour l'administration de conteneur sur Docker :

  • Dans un premier temps, pour lister les images qui sont disponible sur notre machine, utilisez la commande suivante :
docker images
  • Pour télécharger des images, nous pouvons utiliser la commande suivante. Attention, si on souhaite télécharger des images depuis le Docker Hub, il faut bien s'assurer que nous sommes bien connecté :
docker pull [image]
  • Afin de démarrer notre image une fois télécharger, il suffit de faire la commande suivante :
docker run -it [image]
  • On peut voir les conteneurs actuellement disponible sur la machine avec cette commande :
docker ps

CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS          PORTS     NAMES
3a15c9584d9f   [image]      "docker-entrypoint.s…"   18 minutes ago   Up 18 minutes             beautiful_jackson
  • Pour stopper un conteneur, il suffit de faire la commande suivante suivi du CONTAINER ID :
docker stop 3a15c9584d9f 
  • Il est possible de démarrer le conteneur en détaché, c'est-à-dire de faire tourner le conteneur en arrière-plan afin d'avoir accès à la console :
docker run -it -d [image]
  • Il est également possible de rajouter des paramètres lors du démarrage des conteneurs. Par exemple, nous pouvons définir le port à utilisé pour le conteneur avec le -p :
docker run -d -p 8080:80 nginx
  • (Obsolète, privilégié DockerCompose) Si un conteneur doit communiquer directement avec un autre (par exemple, un service web avec une base de données), on peut utiliser le paramètre --links. Cette option enregistre dans le répertoire /etc/ du conteneur l'adresse IP et le nom du conteneur lié. Il est essentiel d'attribuer un nom au conteneur, car la résolution des noms repose sur celui-ci.
docker run -d -p 8080:80 --links redis:redis nginx 
  • Dans le cas où nous avons démarrer un conteneur en détaché et que on souhaite entrer dedans par la suite, il est possible de faire la commande suivante :
docker exec -it [id_conteneur] bash
  • On peut également exécuter des commandes sur des conteneurs, sans forcément entrer dedans :
docker exec [id_conteneur] [cmd]
  • Nous avons la possibilité de faire un clean de tous nos conteneurs, réseaux, images et cache en utilisant la commande suivante :
docker system prune
  • Si nous souhaitons stocker des données de manière persistante, il est possible de créer un volume avec la commande suivante :
docker volume [nom]
  • Pour supprimer une image du système, il suffit d'exécuter la commande suivante :
docker rmi [image]
  • Pour voir la configuration d'un conteneur déployé, nous pouvons utiliser la commande suivante :
docker inspect [id_conteneur]
  • Il est possible de visualiser les logs d'un conteneur :
docker logs [id_conteneur]

Dockerfile

Il est possible de télécharger des images depuis Docker Hub, mais il est également possible de créer ses propres images personnalisées.

Pour ce faire, vous pouvez créer un Dockerfile qui contiendra toutes les instructions nécessaires. À chaque étape de construction de l'image, Docker créera un nouveau layer ou couche. L'objectif est de limiter le nombre d'étapes pour rendre le fichier final le plus léger possible, ce qui améliore les performances de l'image.

1. Dans un premier temps, nous allons créer le fichier Dockerfile dans un répertoire Dockerfiles :

mkdir /Dockerfile

vim /Dockerfile/Dockerfiles

2. Ensuite, dans un premier temps nous allons définir l'image que nous utilisons de base (par ex. un OS, ou un application, service, etc.), en l'occurrence ici nous allons mettre Debian 11 :

FROM debian:11

3. Maintenant, nous allons mettre en place des instructions afin de les exécuter :

RUN apt-get update

4. Il est également possible d'exécuter des commandes :

CMD ["echo","Marijan Conteneur"]

5. Nous pouvons ensuite copier des fichiers, répertoires ou téléchargement depuis un URL vers un dossier de destination :

ADD /etc/source/marijan.txt /etc/destination/

6. Il possible de définir un nouveau répertoire courant sur le quel notre conteneur va ce baser :

WORKDIR /etc/source

7. Nous allons maintenant définir sur quel port notre conteneur va écouter :

EXPOSE 1041

8. Il est possible de définir quel répertoire nous souhaitons partager avec le système host :

VOLUME /etc/destination/

9. Maintenant que notre Dockerfile est prêt, nous allons pouvoir la créer afin d'avoir l'image personnalisé. Pour ce faire, il faudra exécuter la commande suivante :

docker build -t marijan_image .

Le paramètre -t permet de donner un nom à l'image créer. Le "." indique le répertoire où ce trouve le fichier Dockerfile, en l'occurrence à la racine de notre système.

Nous pouvons désormais exécuter le conteneur.

Docker va automatiquement créer un conteneur pour chaque instruction et sauvegardera le résultat dans une couche (layer). L'ensemble de ces layers constitue une image Docker complète. L'avantage de cette méthode est que si un layer ne change pas entre deux constructions, Docker ne le reconstruira pas pour optimiser le temps de construction de l'image. Seuls les layers situés après un layer reconstruit seront reconstruits.

Docker Hub

Une fois l'image créée à l'aide du Dockerfile, il existe principalement deux méthodes pour partager cette image.

  • La première consiste à fournir le Dockerfile aux personnes afin qu'elles puissent le créer elles-mêmes en utilisant la commande docker build, mais cette méthode peut prendre du temps.
  • La deuxième méthode serait de rendre l'image accessible via le registre Docker, tel que Docker Hub.

Pour la deuxième option, il est possible de le faire directement depuis l'interface de Docker Hub, en validant son adresse mail :

Docker Hub Create Repo.png

Sinon, il est également possible de le faire au travers de la machine Linux, en ligne de commande :

1. En premier, nous allons créer un lien entre notre image et l'image que nous souhaitons envoyer sur Docker Hub :

docker tag marijan_image:latest marijanstajic(username dockerhub)/marijan_image:latest
  • Si notre image ne contient pas de nom, il suffit de mettre l'identifiant du conteneur à la place.

2. Ensuite, nous allons envoyer notre image vers Docker Hub :

docker push marijan_image:latest marijanstajic(username dockerhub)/marijan_image:latest

The push refers to repository [docker.io/marijanstajic/test_msa]
3dec696a3faa: Mounted from library/debian
latest: digest: sha256:a4196b3e92bef5f5bccf4527df6bcf61930cf8e437e2308fee213eeaefb59004 size: 528
Docker Hub Repo.png

Il est possible de créer plusieurs versions de notre image en modifiant le tag :latest.

Par exemple, lorsqu'un développeur déploie son application sur Docker Hub, il peut spécifier un nom ou un numéro de version pour son image. Cela permet ensuite de télécharger une version spécifique de l’image selon les besoins.

Par exemple, si le développeur met en ligne une image avec les tags 0.0.1 et 0.0.2, il est possible de télécharger celle que l’on souhaite, tant qu’elle est toujours disponible.

docker run [image]:[tag]

Cependant, il est important de faire attention lors du téléchargement de notre image à partir du registre, car il sélectionnera toujours la version :latest.

.dockerignore

Il est possible de créer un fichier nommé .dockerignore afin d'indiquer au processus de construction de l'image Docker de ne pas inclure certains fichiers ou répertoires sensibles.

Par exemple, si vous avez un répertoire nommé Marijan contenant du contenu sensible, en spécifiant son nom dans le fichier .dockerignore, Docker ne l'inclura pas dans l'image finale. Cela offre une couche de protection supplémentaire pour s'assurer que les fichiers ou répertoires sensibles ne se retrouvent pas accidentellement dans l'image.

Même si vous ne spécifiez pas explicitement un fichier ou un répertoire sensible dans le fichier Dockerfile, Docker n'inclura pas automatiquement tous les fichiers présents dans le contexte de construction. Cependant, pour plus de sécurité, il est recommandé de spécifier les fichiers ou répertoires sensibles dans le fichier .dockerignore.

ENTRYPOINT

Il existe une différence importante entre un ENTRYPOINT et une CMD dans une image Docker. En effet, la commande CMD s’exécutera systématiquement avec la valeur définie, sauf si elle est remplacée lors de l’exécution du conteneur.

FROM ubuntu

CMD sleep 5

Ici, lors de l’exécution du conteneur, la commande sleep sera lancée avec une durée de 5 secondes, puis le conteneur s’arrêtera. Cependant, il est possible de modifier cette valeur au moment de l’exécution en spécifiant une autre durée :

docker run [image] sleep 10

Dans ce cas, la commande par défaut est remplacée par celle fournie au lancement du conteneur. Toutefois, cette approche n’est pas idéale si l’on souhaite imposer une commande tout en permettant la modification de ses arguments. Pour cela, il est préférable d’utiliser ENTRYPOINT.

FROM ubuntu

ENTRYPOINT ["sleep"]

Exited (0)

Il est important de savoir qu’un conteneur ne fonctionne que si l’application qu’il héberge est en état Running. En effet, si l’application s’arrête ou plante, le conteneur est automatiquement détruit et passe à l’état Exited (0).

Il est possible de créer un conteneur à partir d’une image, comme Ubuntu, mais celui-ci sera immédiatement détruit s’il ne contient aucun processus ou application en cours d’exécution. Les images de systèmes d’exploitation servent principalement de base pour exécuter d’autres applications, mais elles ne sont pas destinées à être lancées seules.

Variable d'environnement

Il est possible de définir la valeur des variables d'environnement lors du déploiement d'un conteneur Docker. Pour cela, il suffit d'utiliser le paramètre suivant :

docker -e [ENV_VAR]=[VALEUR] [IMAGE]

Il est également possible d'inspecter une image afin d'afficher les variables d'environnement définies. Ces informations se trouvent sous la section Config, puis Env. Voici un exemple avec MySQL :

docker inspect mysql

..
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "3306/tcp": {},
                "33060/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "GOSU_VERSION=1.17",
                "MYSQL_MAJOR=innovation",
                "MYSQL_VERSION=9.2.0-1.el9",
                "MYSQL_SHELL_VERSION=9.2.0-1.el9"
            ],
..

Docker Compose


Docker compose Banner.png


Docker Compose est un outil en Python qui permet de regrouper à l'aide d'un fichier YAML plusieurs conteneurs comme un ensemble de services. Ils vont tous être exécuter en même temps, sur le même Docker host.

Cela permet de faciliter le déploiement d'une application qui nécessite par exemple une base de donnée ainsi que d'autres outils.

Par défaut, sur Mac et Windows, cette outil est déjà présent par défaut. Pour nous qui sommes sur Linux, il faudra l'installer avec la commande suivante :

curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/bin/docker-compose && sudo chmod +x /usr/bin/docker-compose

Il est ensuite possible de vérifier la version installé avec la commande suivante :

docker-compose --version
docker-compose version 1.23.2, build 1110ad01

Les commandes pour l'administration de ce dernier sont très proche de ceux de Docker. Par exemple :

  • Pour installer des images, il suffit de faire la commande suivante :
docker-compose pull [image]
  • Afin d'exécuté un ensemble de conteneurs, il faut lancer la commande :
docker-compose up

Il est possible d'ajouter des paramètres comme par exemple -d pour l'exécuté en arrière-plan.

  • Une fois une stack démarré, pour voir l'état de l'ensemble des conteneurs, il faut faire la commande suivante :
docker-compose ps
  • Pour stopper une stack Docker Compose, il faut exécuter la ligne suivante :
docker-compose stop
  • Il est possible de voir les logs des conteneurs avec la commande :
docker-compose logs -f --tail 5

Le paramètre --tail 5 permet d'afficher les 5 premières lignes uniquement. Il est bien entendu possible d'afficher plus.

  • Lors de l'écriture de notre fichier Docker Compose, il est possible de vérifier la syntaxe avec la commande suivante afin d'être sûr de ne pas avoir d'erreur lors du lancement :
docker-compose config

docker-compose.yml

Pour créer notre propre Docker Compose, il est nécessaire de créer et utiliser un fichier docker-compose.yml. C'est à l'intérieur de ce fichier que nous allons inclure toutes les informations relatives aux conteneurs, telles que l'image utilisée, le port, le réseau, et autres configurations.

Il est essentiel de déterminer ce que nous souhaitons mettre en place et quelles images nous prévoyons d'utiliser. Dans cet exemple, nous allons déployer Wordpress avec MySQL en tant que base de données.

1. Tout d'abord, dans le fichier .yml, nous allons spécifier la version de Docker-Compose que nous allons utiliser. Dans notre exemple, nous utiliserons la version la plus récente :

version: "3"

2. Ensuite, nous allons définir les conteneurs dans la section services du fichier. Pour chaque conteneur, il suffit de spécifier son nom ainsi que l'image que nous voulons utiliser :

services:
  db:
    image: mysql:latest
  • Dans le cas où l'image n'est pas encore présente sur la machine, elle sera téléchargée automatiquement lors de l'exécution du fichier.

3. Maintenant, nous devons définir un volume afin de faire persister les données :

services:
  db:
    image: mysql:latest
    volumes:
      - db_data:/var/lib/mysql
  • Nous devons spécifier le volume et son chemin, car par défaut, Docker n'assure pas la persistance des données stateful. Si nous souhaitons sauvegarder les données de la base de données sur le disque, il est nécessaire d'utiliser un volume en mode stateful.

4. Il est ensuite nécessaire de définir la politique de redémarrage du conteneur :

services:
  db:
    image: mysql:latest
    volumes:
      - db_data:/var/lib/mysql
    restart: always
  • Un conteneur fonctionne en utilisant un processus unique, ce qui signifie que s'il rencontre une erreur fatale, il s'arrête. Cependant, dans notre cas, si le serveur SQL s'arrête, il sera automatiquement redémarré en utilisant notre politique de redémarrage spécifiée.

5. Pour terminer avec notre premier service, il sera nécessaire de spécifier les variables d'environnements :

services:
  db:
    image: mysql:latest
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: somewordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
  • L'image de MySQL dispose de variables d'environnements utilisable. Ici, pour le bon fonctionnement avec Wordpress, nous allons définir le mot de passe root, le nom de la base de donnée, le nom d'utilisateur ainsi que son mot de passe.

6. Nous allons maintenant pouvoir passer au second service, Wordpress. Nous allons comment avant définir son nom ainsi que l'image à utiliser :

services:
  wordpress:
    image: wordpress:latest

7. Ensuite, nous allons ajouter un nouvelle argument afin de rendre ce conteneur dépendant du premier :

services:
  wordpress:
    depends_on:
      - db
    image: wordpress:latest
  • Aussi, en mettant cette argument, le conteneur indiquer dans la dépendance sera démarrer avant.

8. Il faudra ensuite définir qu'elle port nous souhaitons exposer de notre machine hôte vers le conteneur :

  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    ports:
      - "8000:80"

9. Maintenant, nous allons aussi mettre en place une politique de redémarrage pour ce conteneur :

  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    ports:
      - "8000:80"
    restart: always

10. Pour terminer, définir les variables d'environnements afin que WordPress puisse notamment ce connecter à la base de donnée :

  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    ports:
      - "8000:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress

Ci-dessous, vous trouverez la version finale du fichier docker-compose.yml :

version: '3'
services:
  db:
    image: mysql:latest
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: somewordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    
  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    ports:
      - "8000:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress

volumes:
  db_data: {}

Wordpress est donc bien accessible depuis le port 8000 comme défini dans le fichier docker-compose :

Wp for wiki.png

Paramètre build

Si notre application n'est pas une image disponible sur Docker Hub ou n'a pas encore été construite localement, on peut spécifier le paramètre build dans le fichier docker-compose.yml à la place de image.

application:
  build: ./mon-app
  ports:
      - 5000:80

Il suffit d'indiquer l'emplacement des fichiers et de s'assurer qu'un Dockerfile s'y trouve afin de guider la construction de l'image.

Réseau

Pour permettre la communication entre les conteneurs ainsi qu'avec l'extérieur, une infrastructure réseau est indispensable. Docker propose donc plusieurs types de drivers réseaux, chacun offrant des fonctionnalités spécifiques adaptées à différentes utilisations.

Voici quelques commandes de base pour la configuration et l'administration de ce dernier :

  • Pour créer un nouveau type de réseau, il suffit de faire la commande suivante :
docker network create [type] [nom]
  • Pour visualiser la configuration d'un réseau, comprenant des conteneurs connectés, un sous-réseau et d'autres éléments, il vous suffit d'exécuter la commande suivante :
docker network inspect [name]
  • Il est possible de lister les réseaux disponible :
docker network ls
  • Il est possible de supprimer un réseau. Avant de le faire, il faut s'assurer qu'aucun conteneur n'est pas connecté à l'interface réseau :
docker remove [nom]
  • Afin de connecter ou déconnecter un conteneur à un réseau, il suffit de faire la commande :
docker network connect [réseau] [conteneur]

docker network disconnect [réseau] [conteneur]
  • Il est également possible de connecter un conteneur à un réseau en forçant le paramètre au démarrage :
docker run --network [réseau] [image]

Bridge

Le réseau par défaut utilisé lorsque Docker est installé sans paramètre spécifique pour les conteneurs est le pilote Bridge. Ce drivers est automatiquement connecté à l'interface réseau docker0. Ce qui est le cas avec les Docker Compose à partir de la version 2.

Le pilote Bridge permet la communication entre tous les conteneurs ainsi qu'avec l'hôte. Les conteneurs peuvent obtenir une adresse IP unique dans ce réseau et communiquer entre eux via cette interface.

Bridge network docker.png

Ce type de réseau est le plus utilisé sur Docker.

None

Le réseau None dans Docker permet de couper toute communication interne et externe avec le conteneur, offrant une isolation complète. Dans ce mode, aucune interface réseau n'est mise à disposition à l'exception de l'interface loopback.

None network docker.png

Host

Le type de réseau Host dans Docker permet de supprimer la couche de réseau intermédiaire entre l'hôte et les conteneurs présente dans le mode Bridge.

Ainsi, les conteneurs configurés avec ce pilote ont un accès direct à l'extérieur sans passer par une redirection de ports ou une interface réseau supplémentaire. Cela facilite la communication directe entre les conteneurs et l'extérieur.

Host network docker.png

Overlay

Si vous utilisez plusieurs hôtes pour Docker, vous pouvez faciliter la communication entre les conteneurs en utilisant le réseau Overlay.

Ce type de réseau permet une gestion transparente du routage vers les hôtes et les conteneurs appropriés.

Overlay 2 network docker.png

Macvlan

Le driver Macvlan permet d'assigner une adresse MAC à un conteneur, le faisant ainsi apparaître comme un périphérique réseau physique. C'est généralement la meilleure option lorsque nous souhaitons connecter un conteneur directement à un réseau externe.

Macvlan network docker.png

Volumes

Les données stockées dans un conteneur sont temporaires et sont automatiquement supprimées lorsque le conteneur est arrêté. Afin de rendre ces données persistantes et de pouvoir sauvegarder les données d'un conteneur de manière optimale, il est nécessaire de créer un volume. Les volumes sont des répertoires et des fichiers situés sur le système de fichiers de l'hôte.

La localisation de ces volumes (et même de tous les objets liés à Docker) sur le système ce trouve dans /var/lib/docker (dans le dossier volume, pour les volumes).

Voici quelques commandes de base pour créer et gérer les volumes :

  • Afin de créer un volume, il suffit de faire la commande suivante :
docker volume create [nom]
  • Pour les lister, la commande est la suivante :
docker volume ls
  • Pour accéder aux informations du volume, comme sont chemin et autres, il suffit de faire :
docker volume inspect [nom]
  • Voici la commande pour supprimer le volume :
docker volume remove [image]
  • Si vous souhaitez stocker des données dans un volume, vous devez d'abord créer un Dockerfile indiquant un dossier WORKDIR, par exemple data. Ensuite, lors du démarrage du conteneur, vous devez spécifier ce volume à l'aide du paramètre -v :
docker run -ti -v [volume]:/[chemin] [image]
  • Si on souhaite, on peut même stocker les données dans un autre dossier que celui par défaut de docker /var/lib/docker/volumes en spécifiant sa localisation :
docker run -v [localisation]:/[chemin] [image]

Il existe différent type de volume-driver, dont notamment AWS EBS, qui est un volume-driver qui permet de monter sur Docker, un volume provenant d'AWS. L'avantage, c'est que une fois terminé de travailler dessus, si on ferme ce container, le contenu sera sauvegarder dans le volume, stocké directement dans le Cloud de Amazon.

Le paramètre volume dans Docker permet de rendre les données persistantes de manière simple et efficace. Cependant, pour des besoins plus avancés et une meilleure gestion des options, il est recommandé d’utiliser --mount.

docker run -d --mount type=[type],source=[localisation],target=[chemin]

Sécurité

Dans cette section, certains points vis-à-vis de la sécurité sur Docker seront abordés.

Utilisateur

Lorsqu'un conteneur est exécuté, Docker utilise par défaut l'utilisateur root du conteneur. Cependant, cet utilisateur root n'est pas le même que celui du système hôte.

En effet, l'utilisateur root du conteneur ne possède pas tous les droits du root du système hôte. Ces droits, définis dans le fichier /usr/include/linux/capability.h, sont limités pour éviter des actions potentiellement perturbatrices, comme le redémarrage du système.

Il est possible d'ajouter des droits en modifiant ce fichier ou en ajoutant l'argument suivant lors de l'exécution d'un conteneur :

marijan$ docker run --cap-add <rules> <image>

Pour supprimer des droits, utilisez l'argument suivant :

marijan$ docker run --cap-drop <rules> <image>

Pour exécuter un conteneur avec tous les droits possibles, utilisez l'argument suivant :

marijan$ docker run --privileged <image>

Docker Registry

Lorsque vous exécutez une conteneur, par exemple, NGINX, avec la commande suivante :

docker run nginx

Vous télécharger indirectement l'image NGINX si elle n'est pas déjà présente sur le système. Par défaut, l'image est télécharger à partir du Docker Hub :

  • Registry : par défaut, pour Docker Hub, sa sera docker.io
  • Utilisateur : par défaut, ça sera un utilisateur générique, qui repose sur le namespace par défaut Library
  • Image : correspond à votre image télécharger

Il existe de nombreuses registry comme celle de Google, Kubernetes, etc.

Vous pouvez également créer votre propre registry, soit au travers de Cloud Provider, ou alors le votre, qui sera un On-Permise.

Pour vous connectez, il suffit simplement d'exécuter la commande suivante :

docker login [registry-prive].io

Docker Swarm

Docker Swarm est un orchestrateur de conteneurs directement intégré à Docker. Il fonctionne selon un modèle de Manager et Worker, où les nœuds dits Managers orchestrent et répartissent les tâches. Bien qu’il repose sur le même principe que Kubernetes, il est plus simple à déployer. Cependant, il est moins puissant et offre donc moins de fonctionnalités pour l'orchestration d'un cluster.

Projets

Voici ci-dessous mes projets Docker.

Portainer (Interface)


Docker portainer banner.png


Il est possible d'installer des interfaces graphiques pour faciliter l'utilisation de Docker dans la création de conteneurs, la gestion des images, et d'autres tâches. Parmi ces interfaces, on peut notamment retrouver Portainer.

Mise en place

Voici la procédure d'installation de Portainer sur un système Linux via la ligne de commande (shell) :

1. Dans un premier temps, créer un volume :

docker volume create portainer_data

2. Ensuite, télécharger et installer Portainer :

docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ee:latest
  • Nous avons défini les ports 8000 et 9443 pour le serveur Portainer. De plus, nous avons spécifié une politique de redémarrage, défini le volume à utiliser et spécifié quelle image télécharger.

3. Portainer est désormais accessible depuis un navigateur à l'adresse 127.0.0.1:9446 :

Portainer for wiki.png

Traefik (Reverse-Proxy)


Traefik banner.png


Traefik est un reverse-proxy moderne.

Un reverse-proxy est un élément de communication intermédiaire très utilisé dans les infrastructures informatiques pour faire le lien entre un réseau privé et Internet.

Lorsque nous avons des applications dans notre réseau privé qui ne sont pas accessibles depuis l'extérieur pour des raisons de sécurité, nous pouvons mettre en place un reverse-proxy pour gérer les routes et transférer les requêtes vers les services appropriés.

L'un des principaux avantages de Traefik par rapport à Nginx réside dans sa capacité à mettre à jour dynamiquement les informations sur les routes. En effet, Traefik est capable de détecter automatiquement les nouveaux services déployés et d'extraire les informations nécessaires telles que le chemin, le domaine, etc. Il met ensuite à jour ces informations sans nécessiter une intervention manuelle de la part de l'administrateur.

Sachant que sur Docker, par défaut, à chaque redémarrage, les conteneurs changent d'adresse IP. Cela va permettre d'attribuer un nom à chaque services et que même après un redémarrage, le nom restera lié au bon service.

Mise en place

Voici la procédure d'installation de Traefik sur un système Linux via la ligne de commande (shell) :

1. Afin de déployer Traefik dans un conteneur, nous allons le faire dans un Docker-Compose :

version: "3"
services:
  traefik:
    image: traefik:latest
    command: --api.insecure=true --providers.docker
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - treafik_network
networks:
  treafik_network:
    driver: bridge
  • Nous avons simplement défini le service en incluant l'image ;
  • Les commandes spécifiques à Traefik ;
  • Le volume sur le socket Unix lui permettant ainsi de communiquer avec le démon de Docker afin de récupérer toutes les informations nécessaires dont notamment les nouveaux services ;
  • Les ports à utiliser ;
  • Un nouveau réseau afin d'isoler ce reverse-proxy uniquement avec certains services afin de mettre de l'ordre. Ce réseau sera créé automatiquement dès que nous exécuterons le service.

2. Ensuite, nous allons démarrer le docker-compose afin de mettre en service Traefik :

docker-compose up

3. Traefik est désormais accessible depuis un navigateur à l'adresse localhost sur le port 8080 :

Traefik for wiki.png


Connexion des conteneurs

Maintenant que notre Traefik est en ligne, nous allons devoir connecter nos conteneurs afin qu'ils fonctionnent avec le reverse-proxy. Pour l'exemple, nous allons reprendre le docker-compose.yml du service Wordpress ainsi que MySQL.

1. Créer un fichier docker-compose.yml avec les informations suivantes :

version: '3'
services:
  db:
    image: mysql:latest
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: somewordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    networks:
      - traefik
    
  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    expose:
      - "80"
    labels:
      - "traefik.http.routers.wordpress.rule=Host(`wordpress.localhost`)"
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
    networks:
      - traefik

volumes:
  db_data: {}

networks:
  traefik:
    external:
      name: traefik_webgateway
  • La plupart des paramètres ont été expliqué sous la chapitre Docker-Compose ;
  • Le paramètre expose est similaire au paramètre port, mais avec une différence : port permet de rediriger des ports entre le réseau de l'hôte et le conteneur, tandis que expose déclare les ports sur lesquels les services du conteneur écoutent, mais sans effectuer de redirection de port vers l'hôte ;
  • Le paramètre network permet de spécifier le réseau que nous souhaitons utiliser pour notre conteneur. Il est essentiel de définir à la fin du fichier de configuration la localisation du réseau auquel le conteneur doit se connecter ;
  • L'option label permet de définir des paramètres supplémentaires sur des services, notamment avec Traefik. Ici, cela permet de définir le nom à utiliser pour le reverse-proxy.

2. Ensuite, nous allons démarrer le docker-compose afin de mettre en service le conteneur :

docker-compose up

3. Maintenant, à partir du panneau de contrôle de Traefik, nous pouvons constater que le nouveau service a été détecté et que Traefik lui a attribué créer une route pour y accéder automatiquement.

Traefik wp.png