Docker Engine → Container Engine
The main interface for users to interact with containers.
Manages images, networks, and container lifecycles.
containerd → Container Runtime (High-Level)
A lightweight runtime that handles container lifecycle management.
Manages container execution, networking, and storage.
runc → Container Runtime (Low-Level, OCI-Compliant)
A lightweight runtime that actually runs the container process using Linux namespaces and cgroups.
Follows the Open Container Initiative (OCI) standard.
Chaque container a un namespace et un cgroup :
Namespace :
Grâce aux Namespaces, un conteneur, par exemple, peut avoir son propre espace de processus, ses propres interfaces
réseau, son propre système de fichiers, etc. Cela permet de simuler un environnement virtuel complet, tout en
partageant le noyau sous-jacent.
Les Namespaces sont une fonctionnalité du noyau Linux qui permettent d'isoler les ressources entre les conteneurs. Ils
permettent de créer des groupes de processus isolés du reste de la machine.
Un namespace est un mécanisme d’isolation des ressources dans le système d'exploitation, permettant de diviser un
même environnement en plusieurs sous-environnements, appelés "espaces de noms" (ou "namespaces" en anglais).
Chaque namespace crée une sorte de frontière ou d'isolation pour certains types de ressources systèmes, de sorte que
les processus qui fonctionnent dans ces espaces peuvent coexister sur la même machine tout en étant isolés les uns des
autres.
Cgroup :
Les Cgroups ou Control Groups, est une fonctionnalité du noyau Linux, utilisée pour limiter, compter et isoler
l’utilisation des ressources (comme le CPU, la mémoire, les disques, etc) par un groupe de processus. Les cgroups
permettent donc de contrôler la manière dont les processus utilisent les ressources matérielles, et permettent de créer
des limites (par exemple, limiter la quantité de CPU ou de mémoire qu'un groupe de processus peut utiliser) et de
suivre l'utilisation des ressources.
Le "Matrix from Hell" en containerisation et IT désigne une situation où la gestion des compatibilités entre plusieurs
technologies devient extrêmement complexe et difficile à maintenir. Cela survient lorsqu’une pile d’applications
composée de divers services (ex: [Link], MongoDB, Redis, Ansible) rencontre des conflits de versions, des
dépendances incompatibles avec l’OS, des mises à jour problématiques et des différences entre environnements
(Dev/Test/Prod). Cette interdépendance excessive entraîne des défis majeurs en déploiement, maintenance et
scalabilité, rendant l’infrastructure instable et difficile à gérer.
Solution : conteneurisation , chaque service dans un container .
Difference entre VM et container :
Les conteneurs sont des environnements complètement
isolés, qui ont leurs propres processus pour les services,
leurs propres interfaces réseau, leurs propres points de
montage, etc, mais ils partagent tous le même noyau du
système d'exploitation.
Avantages :
Flexibilité : Héberge diverses applications avec leurs dépendances.
Légèreté : Moins gourmand en ressources que les machines virtuelles.
Interchangeabilité : Facile à déployer, mettre à jour et remplacer.
Portabilité : Fonctionne sur tout environnement sans souci de configuration.
Évolutivité : Permet d'ajuster dynamiquement les ressources selon la demande.
L’architecture de Docker est basée sur une architecture de type client-serveur. Cette architecture repose
sur une interaction entre deux composants principaux qui sont : le Docker Client et le Docker server ou
Docker Daemon (appelé aussi dockerd). Ci-dessous une description détaillée de cette architecture :
1-Docker Client : est l'interface que l'utilisateur utilise pour interagir avec Docker. Il s'agit du Docker CLI (Linux) ou
Remote API (Mac, Windows). Il est responsable de l'envoi de commandes à Docker pour créer, exécuter et gérer des
conteneurs. Il peut être exécuté localement sur la machine où Docker est installé, ou à distance si l'utilisateur se
connecte à un hôte Docker distant.
2-Docker Daemon : est le cœur de Docker. C'est le serveur qui reçoit et traite les requêtes envoyées par Docker Client
(gestion des conteneurs, des images, des volumes, des réseaux, etc).
3-REST API : qui permet au client de communiquer avec le serveur Docker de manière standardisée.
4-Docker Engine : Docker Client + Rest API + Docker server. C'est une partie fondamentale de la plateforme Docker, qui
permet notamment d’exécuter un conteneur, de construire une Docker image, ou encore de partager les Docker
images avec d’autres via Docker Hub.
5-Docker Registry : est une bibliothèque qui stocke les images Docker. Il peut être public ou privé. Le Docker Registry
permet au Docker Daemon de récupérer les images nécessaires pour créer des conteneurs. Il permet ainsi de stocker,
partager et distribuer des images entre les utilisateurs et les machines. est une bibliothèque de Docker images. Le
Docker Registry public géré par Docker s’appelle Docker Hub ; il contient les images officielles et permet aux
développeurs de stocker et de partager des images qu’ils ont créé.
6-Docker images : sont des modèles statiques (templates) utilisés pour créer des conteneurs. Elles contiennent tout le
nécessaire pour exécuter une application, y compris le code, les bibliothèques, les dépendances et les configurations.
Une image est un fichier immuable qui sert de base à un conteneur Docker.
7-Docker containers : sont des instances en cours d'exécution d'une image Docker.
Créer une image docker : méthode 1 scatch :
FROM scratch
COPY hello /
CMD ["/hello"]
La création d'images Docker "From scratch" consiste à utiliser l'image spéciale scratch de Docker, qui ne contient aucun
système d'exploitation préinstallé. Contrairement aux autres images Docker, scratch n'est pas une image parente, mais
une directive indiquant que l'image sera construite sans dépendre d'aucune autre image existante.
👉 Cette méthode est particulièrement recommandée lorsque les priorités sont la légèreté, la sécurité et un contrôle
total sur les dépendances.
Créer une image docker : méthode 2 dockerfile :
Docker file exemple : dockerfile_1
FROM ubuntu:20.04 # Définir l'image de base (avec sa version)
WORKDIR /app # Définir le répertoire de travail dans le conteneur
RUN apt-get update && apt-get install python3 # Exécuter des commandes durant le build
COPY . /source /app # Copier des fichiers au conteneur (statiquement), COPY . . (cad dans /app qui le workdir)
ADD [Link] /app # Copier des fichiers (ou .tar) au conteneur (dynamiquement)
ENTRYPOINT ["echo"] # Définir l'ENTRYPOINT et ajouter un CMD supplémentaire
CMD ["echo", "Hello, World!"] # Commandes au lancement du conteneur (run) (ne cree pas une
couche dans l’image)
VOLUME ["/data"] # Définir un volume anonyme pour le container
LABEL version="0.1" # Ajoute des métadonnées, comme la version de l'application,
LABEL maintainer="John Smith" le mainteneur et la date de la version.
LABEL release-date="2020-04-05"
ENV APP_ENV=production # Définir une variable d'environnement
ARG THEARG="foo" # Définir un argument avec une valeur par défaut
RUN echo "L'argument est : $THEARG" # Utiliser l'argument dans une commande RUN
USER user1 # Spécifier l'utilisateur (sinon root par défaut)
EXPOSE 80 # Expose le port 80 pour la communication réseau
---------------------------------------------------------------------------------------
Après on fait le build : (docker file dockerfile_1 exite sous / donc on ecrit . comme contexte de construction)
docker build -f dockerfile_1 --tag mon_image:tag_1 . on aura une image nommée mon_image
RQ : Optimisation avec le système de cache
Si on exécute à nouveau la même version, cela sera instantané, car Après chaque étape de construction, Docker prend
un instantané (ou cache) de l'état de l'image résultante.
Avant d’exécuter une étape, Docker vérifie si une étape identique a déjà été construite auparavant.
Docker utilise strictement les chaînes exactes définies dans ton fichier Dockerfile. Cela inclut :
L'ordre des commandes : exemple, RUN apt-get install figlet cowsay est différent de RUN apt-get install cowsay figlet.
Les commandes dépendantes des mises à jour externes : par exemple, RUN apt-get update ne sera pas réexécuté si
les dépôts sont mis à jour, car l'état du cache reste inchangé.
Pour ignorer le cache et reconstruire entièrement l'image, utilise l'option :
docker build --no-cache
Créer une image docker : méthode 3 container-commit :
Docker commit mon_container mon_image faire un commit avec le nom du container
Docker commit a8g5cd816sod2 mon_image faire un commit avec l’ID du container
Multi-stage build :
# Étape 1 : Construire l'application Angular
FROM node:14 AS build-stage
WORKDIR /app
COPY . .
RUN npm install && npm run build
# Étape 2 : Créer une image finale légère avec Nginx
FROM nginx:alpine
COPY --from=build-stage /app/dist /usr/share/nginx/html
L'image finale ne contient que les fichiers nécessaires à la production, spécifiquement ceux présents dans le dossier
dist, ce qui permet de réduire considérablement sa taille. La sécurité est améliorée, car les outils et composants non
nécessaires ne sont pas présents dans l'image, limitant ainsi les risques d'exploitation. Seulement les instructions du
dernier stage (dernier FROM) sont considérées comme couches dans l’image finale.
Docker Hub
Types d'images :
Images officielles : Des images fournies par Docker ou des éditeurs reconnus, comme Linux, Nginx, MySQL…
Images tierces : Images créées et partagées par d'autres utilisateurs.
Bind mount :
Le Bind Mount est un mécanisme de stockage persistant qui permet de stocker les données d'un conteneur
directement dans un répertoire de l'hôte. Contrairement aux volumes Docker, les Bind Mounts peuvent être situés
n'importe où sur le système hôte et peuvent pointer vers des fichiers ou des répertoires système critiques.
Volumes de donnees :
Sont des volumes complètement isoles du systèmes de fichier de l’hote et sont gérer automatiquement , ils sont
stockes sous /var/lib/docker/volumes/, il existe 2 types de volumes de données :
1- volumes anonymes :
Les volumes anonymes dans Docker sont des volumes créés sans être explicitement nommés. Autrement dit, lorsqu'un
conteneur est lancé avec l’option " -v " sans spécifier de nom pour le volume, Docker génère automatiquement un
volume anonyme destiné à stocker les données.
Dans les volumes anonymes : Les données sont perdues lorsque le conteneur est supprimé. Ils sont utiles pour les
taches temporaires et ne sont pas conçus pour le partage.
2- volumes nommés :
Les volumes nommés sont des volumes Docker explicitement créés et attribués à un nom spécifique. Contrairement aux
volumes temporaires, ils sont stockés en dehors du système de fichiers du conteneur, ce qui permet de les gérer
facilement, de les sauvegarder et de les partager entre différents conteneurs.
Dans les volumes nomes : les données sont persistantes lorsque le container est supprimé, ces volumes sont conçus
pour le partage.
Docker Network
1-Bridge : est le pilote réseau docker par défaut. Les réseaux bridge sont généralement utilisés lorsque vos applications
s'exécutent dans des conteneurs autonomes (standalone) qui doivent communiquer. En effet, les conteneurs sur le
même réseau bridge peuvent communiquer entre eux, mais sont isolés du reste du réseau.
Le driver bridge crée un réseau local de type pont sur l'hôte Docker, et chaque conteneur connecté à ce réseau reçoit
une adresse IP locale. Par défaut, Docker crée un réseau appelé "bridge" et de type bridge.
le bridge network est connecte à une interface réseau appelée docker0 : docker0 est un pont virtuel auquel tous les
NIC (Network Interface Card) créés dans des conteneurs s'y connectent. L'adresse IP sera allouée dans un sous-réseau
de docker0 et la passerelle est docker0.
Default bridge :
Les conteneurs connectés au réseau Default Bridge Network peuvent communiquer entre eux uniquement via
l'adresse IP. (Pas de résolution de noms)
Le Default Bridge Network nommé "bridge" est limité aux conteneurs d'un hôte unique exécutant le moteur Docker.
Les conteneurs qui utilisent ce driver, ne peuvent communiquer qu'entre eux. Cependant, ils ne sont pas accessibles
depuis l'extérieur. Pour que les conteneurs sur le réseau "bridge" puissent communiquer ou être accessibles depuis le
monde extérieur, on doit configurer le mappage de port.
Pour effectuer un mappage de port, on utilise la commande suivante :
docker run -p <HOST PORT>:<CONTAINER PORT> <IMAGE NAME>
User-defined bridge : cree par l’utilisateur(isolation amélioré):
Il est recommandé d’utiliser des réseaux Bridges définis par l’utilisateur pour contrôler quels conteneurs peuvent
communiquer entre eux, et ainsi permettre la résolution DNS des noms d’hôtes des conteneurs avec les adresses IP.
2-Host : ce type de réseau permet aux conteneurs d'utiliser la même interface que l'hôte. Il supprime donc l'isolation
réseau entre les conteneurs et seront par défaut accessibles depuis l'extérieur. De ce fait, il prendra la même IP que
votre machine hôte.
Par exemple, si un service sur l’hôte écoute sur un port particulier et que nous voulons qu’un conteneur interagisse
directement avec lui sans passer par le réseau bridge, on attache ce conteneur au réseau host. Cependant, cela
comporte plusieurs risques liés à la sécurité, à l'isolation et au conflit de ports.
3-Overlay : est le driver qui permet de créer des réseaux virtuels qui peuvent s'étendre sur plusieurs hôtes Docker. Il
crée un réseau distribué entre plusieurs hôtes possédant le moteur Docker. Docker gère de manière transparente le
routage de chaque paquet vers et depuis le bon hôte et le bon conteneur.
4-None : est le type de réseau idéal, si on souhaite interdire toute communication interne et externe avec le conteneur.
Le conteneur sera, dans ce cas, dépourvu de toute interface réseau.
Docker compose (orchestration des containers dans un VM)
Commandes de bases :
Lancer un conteneur Ubuntu en mode interactif (interagir avec un conteneur sans qu’il se ferme immédiatement) :
docker run -i ubuntu
Lancer un conteneur interactif avec un terminal :
docker run -it ubuntu
Lancer un conteneur Ubuntu en spécifiant sa version :
docker run -it ubuntu:22.04
Exécuter un conteneur Ubuntu et le supprime automatiquement une fois il est arrêté :
docker run --rm ubuntu
Créer un conteneur Ubuntu nommé "mycontainer" :
docker run --name mycontainer ubuntu
Créer un lien entre un conteneur Ubuntu et un conteneur de base de données appelé "mydb" :
docker run --link mydb:mysql ubuntu
Exécuter un conteneur Ubuntu en arrière-plan (mode détaché) :
docker run -d ubuntu
Mapper le port 80 du conteneur au port 8080 de l'hôte :
docker run -p 8080:80 ubuntu
Démarrer un conteneur :
docker run -d --name mon_conteneur nginx
Afficher les conteneurs en cours d'exécution : (-a pour afficher tous les conteneurs)
docker ps
Inspecter un conteneur et obtenir des informations détaillées :
docker inspect nom_ou_id_du_conteneur
Afficher les logs du conteneur :
docker logs mon_conteneur
Exécuter une commande dans le conteneur en cours d’exécution (running) :
docker exec -it 5581613813 /bin/bash
Cela exécutera la commande /bin/bash dans le conteneur en ouvrant le terminal interactif.
docker exec mon_conteneur ls -l
Cela exécutera la commande ls -l dans le conteneur et affichera la sortie sans ouvrir de terminal interactif.
Exécuter une commande dans le conteneur lors de sa création :
docker run -it --name mon_container alpine ls -a
Renommer un conteneur :
docker rename my_old_container my_new_container
Attacher au conteneur en cours d’exécution, permettant d'interagir avec son processus principal.
docker attach mon_conteneur
Arrêter le conteneur de manière gracieuse :
docker stop mon_conteneur
Démarrer le conteneur qui n’est pas au cours d’exécution (stopped) :
docker start mon_conteneur
Redémarrer le conteneur (stop + start ou start):
docker restart mon_conteneur
Termine immédiatement un conteneur en cours d'exécution, forçant son arrêt :
docker kill mon_conteneur
Créer une image appelée mon_image avec le tag v1.0 à partir du Dockerfile situé dans le répertoire actuel . :
docker build -t mon_image:v1.0 .
Ignorer le cache lors du build de l’image :
docker build --no-cache -t mon_image:v1.0 .
Créer l'image à partir du Dockerfile situé dans /chemin/vers/dockerfile :
docker build -t mon_image:mon_tag /chemin/vers/dockerfile
Créer une image appelée mon_image(repository) avec le tag tag_1 à partir du Dockerfile dockerfile1 situé dans le
répertoire actuel . ( . est le context de constructon qui contient le docker file et ses fichers pour la construction) :
docker build -f dockerfile1 --tag mon_image:tag_1 .
Remplacer la commande de l’enrtypoint dans le docker file par une nouvelle commande :
docker run --entrypoint <new_command> <image_name> <new_command_arguments>
Supprimer une image :
docker rmi mon_image:tag_1
Chercher une image dans DockerHub : (afficher toutes les images dont le nom commence avec ubuntu) :
docker search ubuntu
Télécharger (pull) une image du DockerHub sur la machine : (il vérifie d’abord de l’existance de l’image localement)
docker image pull ubuntu:22.04
Afficher les couches (les instructions) de l’image (comme CMD, RUN, COPY, ENTRYPOINT, VOLUME …) :
docker image history ubuntu :22.04
Lister toutes les images sur la machine :
docker images
Se connecter au compte docker hub :
docker login -u youssef
Taguer une image docker avant de faire le push :
docker tag <nom_image> <nom_utilisateur>/<nom_image>:<tag>
Push une image sur docker hub :
docker push <nom_utilisateur>/<nom_image>:<tag>
Comparer l'état initial avec l’état actuel du conteneur :
docker diff <containerId>
A : Fichiers ajoutés.
C : Fichiers modifiés.
D : Fichiers supprimés.
Créer une image docker à partir de l’état d’un container existant :
docker commit <containerId>
oubien : docker commit <containerId> <tag>
Ajouter le tag a une image docker pour l’utiliser au lieu de l’ID :
docker tag <imageId> <new_tag>
Créer un bind mount appelé C1_bind qui monte le dossier /home/test sur la VM sut le dossier /data sur le container :
docker run -it --name C1_bind -v /home/test:/data alpine
Inspecter le bind mount :
Docker inspect C1_bind
Créer un container avec un volume anonyme (sans nom) attache au dossier /data sur le container :
docker run -it --name container_anonymous -v /data alpine
Créer un volume nomme appellé mon_volume :
docker volume create mon_volume
Créer un container et lui attache un volume nomme appelé mon_volume (sera créé après le run s’il n’existe pas) :
docker run -it --name container_named -v mon_volume:/data alpine
Monter un volume nommée en mode lecture seule (par default rw si ro n’est pas mentionné) :
docker run -d --name conteneur_ro -v mon_volume:/app/data:ro alpine
Creer un container qui partage le meme volume avec un autre container (on peut appliquer les modes comme ro) :
docker run -it --name container_share --volumes-from container_named alpine
Afficher les volumes :
docker volume ls
Inspecter un volume :
docker volume inspect mon_volume
Supprimer un volume (Cette action est définitive, les données stockées seront perdues) :
docker volume rm mon_volume
Supprimer tous les volumes anonymes locaux non utilisés :
docker volume prune
Liser tous les reseau sur une vm :
docker network ls
Créer un réseau de type bridge appelé my_network aven une adresse réseau [Link]/24 et un gateway : (si on
ne spécifie pas par défaut bridge)
docker network create --driver=bridge --subnet=[Link]/24 --gateway=[Link] my_network
Inspecter le reseau :
docker network inspect my_reseau
Créer un container et le connecter au réseau host (par exemple) : (avec host il faut mapper les port)
docker run -it --network host --name container4 ubuntu
Connecter un container a un réseau : (par défaut les container sont connectes au réseau bridge)
docker network connect my_network my_container
Déconnecter un container d’un reseau :
docker network disconnect my_network my_container
Supprimer un reseau :
docker network rm my_network
Supprimer tous les réseaux non utilisés :
docker network prune
Afficher l’interface docker0 :
ip addr show docker0
Linker contr1 a contr2 afin de pinguer par résolution de nom : (dans le cas de default bridge et c’est unidirectionel)
docker run -it --name contr1 --link contr2_alias ubuntu
contr1 seulement peut pinguer contr2 en utilisant sont nom
Démarrer et exécuter l'application (docker compose) : (si le file est [Link] , pas de -f <file name>)
docker compose -f <file name> up
Démarrer et exécuter l'application en arrière-plan :
docker compose up -d
Afficher la liste des conteneurs associés à l'application, qu'ils soient en cours d'exécution ou arrêtés :
docker compose ps
Afficher la configuration de l'application (tous les paramètres et configurations : services, volumes, réseaux) :
docker compose config
Afficher les logs des conteneurs :
docker compose logs
Arrêter une stack Docker Compose(l'application) sans supprimer les ressources créées :
docker compose stop
Arrêter les conteneurs et supprime les ressources créées par Docker Compose, y compris les réseaux et volumes :
docker compose down