Docker
Docker est une plateforme de virtualisation permettant d'emballer des applications et leurs dépendances dans des conteneurs, facilitant ainsi le déploiement et la gestion d'applications.
Informations
Date de publication :
Date de modification :
Catégories : docker, yaml
Auteur :
meezyr

Docker est un outil open-source écrit en langage Go et créé en 2012 par trois ingénieurs français. Il résulte de développements internes de l'entreprise dotCloud co-fondés par deux français d'Epitech. Docker permet une utilisation plus efficiente des ressources d'un système tout en permettant les mêmes avantages qu'une machine virtuelle : c'est-à-dire principalement l'isolation et la reproductibilité. Pour en savoir plus sur Docker, consultez le site officiel.
1. Les bases de Docker
1.1 Conteneurs
Les principes des conteneurs Docker sont les suivants :
- Ils sont flexibles : n'importe quelle applications, même les plus complexes, peuvent être containerisée (on dit aussi "
dockerisée"). - Ils sont légers : le fait qu'ils partagent les ressources et le noyau
Linuxdu système d'exploitation de la machine hôte font qu'ils sont beaucoup plus légers que des machines virtuelles. - Ils sont portables : ils sont utilisables sur n'importe quel environnement (tout
OS, aussi bien pour le développement local que sur des centaines de serveurs dans lecloud). - Ils ont un couplage faible : cela signifie que les conteneurs sont autonomes car ils sont isolés. Il est facile de les supprimer, les ajouter, les modifier (mise à jour par exemple) sans perturber les autres conteneurs tournant sur une machine.
- Ils sont scalables : des outils permettent de déployer des centaines voir des milliers de conteneurs en quelques minutes voir secondes sur un très grande nombre de serveurs. Il est même possible d'automatiser le déploiement de nouveaux conteneurs (
auto-scaling). - Ils sont sécurisés : les contraintes et l'isolation par défaut des conteneurs apporte une grande sécurité des environnements déployés.
1.2 Docker Engine
Il faut bien comprendre que Docker utilise le noyau Linux et l'environnement GNU de votre système. Le Docker Engine ou moteur Docker est une application sur un modèle client / serveur.
1.3 Images
Une image Docker est un schéma en lecture seule qui contient les instructions pour créer un conteneur Docker. Pour créer une image, il faut utiliser un fichier spécifique appelé Dockerfile qui a une syntaxe particulière permettant de définir les étapes nécessaires à la création de l'image.
Un conteneur est une instance d'une image en cours d'exécution qui peut prendre des options de configuration passées lors du lancement.
1.4 Volumes
Les volumes permettent aux conteneurs de stocker des données.
1.5 Docker Compose
Docker Compose est l'outil Docker permettant de définir et de lancer des applications multi-conteneurs. Pour en savoir plus sur Docker Compose, consultez la documentation officielle.
1.6 Docker Swarm
Docker Swarm est un orchestrateur qui permet de gérer facilement plusieurs conteneurs (souvent nombreux) sur de multiples serveurs. Kubernetes est également un orchestrateur mais développé par Google et non par Docker. Pour en savoir plus sur Docker Swarm, consultez la documentation officielle.
2. Commandes
La commande docker permet d'obtenir de l'aide sur toutes les commandes, on peut également utiliser la commande docker help.
L'option --help permet d'obtenir de l'aide sur une commande spécifique, comme dans l'exemple suivant :
docker container ls --help
2.1 Docker run
La commande docker run est en réalité un raccourci notamment pour plusieurs commandes Docker que nous étudierons plus tard : docker pull image, docker container create -d image, docker container start ID, docker container -a ID.
La commande docker run va commencer par créer un conteneur, qui revient à créer un système de fichiers isolé pour le conteneur, ainsi qu'un réseau privé et un arbre des processus isolé, créer une couche avec les droits d'écriture activés (writable container layer) au-dessus de la couche de l'image en lecture seule et exécuter la commande prévue dans l'image en utilisant la configuration par défaut spécifiée. La configuration peut être relative à l'exécution en premier plan ou en arrière plan, à l'identification du conteneur, aux paramètres réseaux et à des limites d'utilisation des ressources (CPU, mémoire etc). Par exemple :
docker run -a stdin -a stdout image
L'option -i permet de garder l'entrée standard ouverte même si le processus est lancé par défaut en arrière plan ou qu'il ne démarre pas de service et donc quitte immédiatement, comme dans l'exemple suivant :
docker run -i image
L'option -it permet de démarrer un pseudo-TTY (c'est-à-dire un terminal) et de l'allouer au conteneur, comme dans l'exemple suivant :
docker run -it image
L'option -d permet de démarrer un conteneur en mode background (docker run -d alpine ping google.fr), comme dans l'exemple suivant :
docker run -d image
Pour rendre un ou plusieurs ports disponibles à un service extérieur à Docker il faut les publier. Pour publier un port il faut utiliser l'option --publish ou -p. Cela va ajouter une règle dans le pare-feu et va lier un port du conteneur à un port sur la machine hôte, comme dans l'exemple suivant :
docker run -it -p 80:80 test // -p PORT_HOTE:PORT_CONTENEUR
2.2 Container
Afin de lister les conteneurs en cours d'exécution, on peut utiliser la commande suivante :
docker container ls
Les options -a et --all permettent de lister tous les conteneurs, y compris ceux qui sont seulement créés ou qui ne sont plus en cours d'exécution (exited).
Pour supprimer un conteneur qui n'est pas en cours d'exécution (avec le statut UP), on peut utiliser la commande suivante :
docker container rm NOM_OU_ID
Les options --force et -f permettent de forcer la suppression d'un conteneur.
Afin de supprimer tous les conteneurs arrêtés, il faut utiliser la commande suivante :
docker container prune
Afin de stopper tout les conteneurs en cours d'exécution, vous pouvez utiliser la commande suivante :
docker stop $(docker ps -aq)
La commande docker container cp SOURCE DESTINATION permet de copier des fichiers et des dossiers entre un conteneur et le système de fichiers de la machine hôte. Par exemple :
docker cp CHEMIN_SOURCE CONTENEUR:CHEMIN_DESTINATION // Dans le sens hôte -> conteneur
docker cp CONTENEUR:CHEMIN_SOURCE CHEMIN_DESTINATION // Dans le sens conteneur -> hôte
Voici quelques commande utile pour gérer des conteneurs :
docker container create: Permet de créer un conteneur mais de ne pas l'exécuter.docker container start NOM_OU_ID: Permet d'exécuter un conteneur, les options-itrendent le conteneur interactif et l'option-al'attache à votre terminal.docker container logs NOM_OU_ID: Permet de voir leslogsdu conteneur.docker container stop NOM_OU_ID: Permet de stopper un conteneur.docker container kill NOM_OU_ID: Permet de stopper immédiatement l'exécution d'un conteneur, un container qui estkillne pourra pas exécuter d'action avant de quitter.docker container rename CONTENEUR NOUVEAU_NOM: Permet de renommer un conteneur après sa création.docker container pause: Permet de suspendre tous les processus d'un ou de plusieurs conteneurs spécifiés.docker container exec: Permet d'exécuter des commandes dans des conteneurs en cours d'exécution, on peut utiliser des options-dpour exécuter la nouvelle commande en arrière plan,-iet-t.docker exec -it NOM_OU_ID bash: Permet d'obtenir un terminal connecté à un shell dans n'importe quel conteneur.docker container diff CONTENEUR: Permet d'inspecter les changements dans le système de fichiers d'un conteneur. La lettreAsignifie qu'un fichier ou un dossier a été ajouté. La lettreDsignifie qu'un fichier ou un dossier a été supprimé. La lettreCsignifie qu'un fichier ou un dossier a été modifié.docker container top CONTENEUR: Permet de lister tous les processus d'un conteneur sur un conteneur en cours d'exécution.docker container inspect CONTENEUR: Permet d'obtenir toute la configuration d'un conteneur.docker container stats: Permet de visualiser la consommation de toutes les ressources par les conteneurs en cours d'exécution.docker container commit: Permet de créer une image à partir des modifications effectués dans un conteneur.
2.3 Image
Afin de lister les images locales, on peut utiliser la commande suivante :
docker image ls
Pour supprimer une image, il faut utiliser la commande suivante :
docker image rm NOM_OU_ID
Les options -f et --force permettent de forcer la suppression d'une image.
Pour supprimer les images dangling et qui ne sont pas utilisées par un conteneur en cours d'exécution. Les images dangling sont les images qui ne sont pas versionnées par un tag. On peut utiliser la commande suivante :
docker image prune
L'option -a permet de supprimer l'ensemble des images locales qui n'ont pas de conteneur en cours d'exécution associé.
Afin d'inspecter une image et d'obtenir toute la configuration de Docker pour sa création, on peut utiliser la commande suivante :
docker image inspect
Pour créer un tag à une image, il faut utiliser la commande suivante :
docker image tag
Afin de lister les couches ou les images qui utilisées pour la construction de l'image. Cela permet de voir comment une image a été créée et quelles instructions ont été exécutées. On peut utiliser la commande suivante :
docker image history
2.4 Suppression
Afin de tout supprimer, les containers, les images, les caches... On peut utiliser la commande suivante :
docker system prune
Pour en plus supprimer les images qui sont taguées, donc toutes les images sauf celles utilisées par un conteneur en cours d'exécution, on peut utiliser l'option --all ou -a.
2.5 Visualisation
Pour visualiser l'espace disque utilisé sur la machine hôte par les images, les conteneurs et les volumes. On peut utiliser la commande suivante :
docker system df
Pour avoir le détails pour chaque éléments et non des totaux agrégés, il faut utiliser l'option -v pour verbose.
2.6 Volumes
Lorsque l'on crée un volume il est stocké dans un dossier sur l'hôte (/var/lib/docker/volumes/ pour GNU/Linux). Ce volume peut ensuite être monté (c'est-à-dire utilisé) dans un conteneur, le dossier est alors utilisé. Un volume peut être utilisé par plusieurs conteneurs. Pour créer un volume, on utilise la commande suivante :
docker volume create
Afin de lister tous les volumes Docker existants, on utilise la commande suivante :
docker volume ls
La commande qui permet d'inspecter un volume est la suivante :
docker volume inspect ID_NOM
Pour supprimer un seul volume, il faut utiliser la commande suivante :
docker volume rm ID_NOM
La commande qui permet de supprimer tous les volumes est la suivante :
docker volume prune
2.7 Network
Afin de lister les réseaux existants, on peut utiliser la commande suivante :
docker network ls
Pour inspecter les réseaux et voir les détails d'un réseau, on peut utiliser la commande suivante :
docker network inspect
La commande qui permet de créer un réseau personnalisé est la suivante :
docker network create
Afin de supprimer un ou plusieurs réseaux, on utilise la commande suivante :
docker network rm
La commande qui permet de connecter un volume avec un réseau est la suivante :
docker network connect
Afin de déconnecter un volume avec un réseau, on peut utiliser la commande suivante :
docker network disconnect
3. Dockerfile
3.1 Bases du fichier
Un Dockerfile contient les instructions permettant à Docker de construire (build) une image automatiquement. Par exemple dans un fichier nommé Dockerfile :
FROM alpine
RUN apk add --update nodejs
COPY ./app.js /app/
CMD [ "node", "/app/app.js" ]
Pour en savoir plus sur le Dockerfile, consultez la documentation officielle.
3.2 Commandes de lancement
Afin de construire une image grâce au fichier Dockerfile qui est contenu dans le dossier actuel, on peut utiliser la commande suivante :
docker image build .
Afin de donner un nom à une image, c'est à dire taguer ou donner un tag, il faut utiliser l'option -t de la commande build, comme dans l'exemple suivant :
docker build -t node:latest .
3.3 Les instructions
L'instruction FROM permet d'indiquer quelle est l'image parente depuis laquelle vous allez effectuer les modifications spécifiées dans vos instructions. Tous les Dockerfile doivent utiliser une instruction FROM comme première instruction. Par exemple :
FROM image@digest
FROM image:tag
FROM image
L'instruction RUN permet d'exécuter toutes les commandes spécifiées dans une nouvelle couche (layer) au-dessus de la dernière image intermédiaire puis de sauvegarder le résultat. La forme exec utilise un tableau JSON de mots qui seront ensuite interprétés en une instruction. Elle permet d'exécuter des commandes avec des exécutables sans utiliser nécessairement un shell, l'utilisation des guillemets doubles est obligatoire. La forme shell permet d'exécuter une ou plusieurs commandes par un shell qui est par défaut sh. Par exemple :
RUN ["executable", "param1", "param2"]
RUN ["/bin/bash", "-c", "echo Bonjour !"]
// Ou
RUN echo "Bonjour !"
RUN apt update && apt dist-upgrade -y
Il est obligatoire de mettre apt-get update et apt-get install dans la même instruction RUN du Dockerfile. Dans le cas contraire vous aurez de graves problèmes de cache.
L'instruction ADD permet de copier des fichiers, des dossiers ou des fichiers distants en utilisant des URL et de les ajouter au système de fichiers de l'image. Par exemple :
ADD SOURCE... DESTINATION
ADD ./exemple.txt /app/
ADD ./back/ /app/
L'instruction COPY permet de copier des fichiers et des dossiers et de les ajouter au système de fichiers de l'image. Il est donc recommandé de n'utiliser ADD que lorsque vous avez besoin des fonctionnalités de décompression ou du téléchargement de sources depuis des URL. Par exemple :
COPY SOURCE... DESTINATION
L'instruction WORKDIR permet de modifier le répertoire de travail pour toutes les instructions RUN, CMD, ENTRYPOINT, COPY et ADD. Par exemple :
WORKDIR /app
L'utilisation de variables d'environement est possible :
ENV DIR=/app
WORKDIR $DIR/back
RUN pwd // Affiche /app/back
L'instruction CMD permet de fournir la commande exécutée par défaut pour les conteneurs lancés depuis l'image. Il ne peut y avoir qu'une seule instruction CMD par Dockerfile, par exemple :
CMD ["exécutable","param1","param2"] // Forme exec qui n'est pas lancé par un shell (recommandé)
// Ou
CMD commande param1 param2 // Forme shell qui est lancée par le shell sh
L'instruction ENTRYPOINT permet de configurer un conteneur qui sera lancé comme un exécutable. Par exemple :
ENTRYPOINT ["exécutable", "param1", "param2"]
L'instruction ENTRYPOINT s'utilise en combinaison avec l'instruction CMD, par exemple :
FROM alpine
ENTRYPOINT ["/bin/ping"]
CMD ["localhost"]
docker run test // Résultat : PING localhost (127.0.0.1): 56 data bytes
docker run -it test bash // Résultat : ping: bad address 'bash'
docker run -it test google.fr // Résultat : PING google.fr (216.58.204.131): 56 data bytes
L'instruction ARG permet de définir des variables qui seront utilisables par l'utilisateur lançant les conteneurs. Il ne faut pas utiliser ARG pour passer des secrets (clés, mots de passe etc). Par exemple :
ARG env // Valeur par défaut : ARG env=dev
docker build --build-arg env=prod // Commande pour assigner prod à env
L'instruction ENV permet de définir des variables d'environnement. La différence avec ARG est que les variables d'environnement sont persistées dans l'image après le build. Par exemple :
ENV CLE="Une valeur"
ENV CLE1="Une valeur1" CLE2="Une valeur2"
Le problème du path signifie que node ne sait pas où se trouve le programme /app/nodemon et qu'il ne peut donc pas le lancer. On peut le corriger comme cela :
ENV PATH=$PATH:/app/node_modules/.bin
L'instruction LABEL permet d'ajouter des métadonnées à une image. C'est-à-dire des informations sur le contenu, l'auteur, la version etc de l'image. Par exemple :
LABEL version="2.3.1"
LABEL auteur="jean@gmail.com"
L'instruction EXPOSE permet d'informer Docker qu'un conteneur écoute sur les ports spécifiés lors de son exécution. L'instruction EXPOSE ne publie pas le port spécifié. Il faut toujours passer l'option -p. Par exemple :
EXPOSE 80
EXPOSE 80/udp
Pour en savoir plus sur les instructions de Dockerfile, consultez la documentation officielle.
4. Docker Hub
Docker Hub est la plateforme d'image officielle de Docker. Il s'agit d'un registry, c'est-à-dire d'un service d'hébergement qui contient un très grand nombre de repositories d'images. Pour en savoir plus, consultez le site officiel.
La commande docker login permet de se connecter sur Docker Hub pour publier une image.
La commande docker logout permet de se déconnecter du Docker Hub.
5. Import et export
La commande docker image save permet de sauvegarder une ou plusieurs images dans une archive tar. Par exemple :
docker image save -o mon_image.tar mon_image
docker save mon_image | gzip > mon_image.tar.gz
La commande docker image load permet de charger une image depuis une archive passée en entrée standard. Par exemple :
docker image load < mon_image.tar
docker image load -i mon_image.tar
La commande docker container export permet d'exporter le système de fichiers d'un conteneur dans une archive tar. Par exemple :
docker container export -o conteneur_fs.tar mon_conteneur
docker container export mon_conteneur > conteneur_fs.tar
Afin d'importer le système de fichiers d'une archive tar pour créer une image, on peut utiliser la commande suivante :
docker image import http://exemple.com/exampleimage.tgz
docker image import conteneur_fs.tar
6. Dockerignore
Le fichier .dockerignore doit être dans le dossier racine du contexte, le fonctionnement du fichier .dockerignore est très similaire à celui de Git. L'ordre des règles est très important dans le .dockerignore, la syntaxe est la suivante :
#: Permet d'insérer un commentaire.*/temp*: Permet d'exclure les fichiers et les dossiers qui commencent partempdans les dossiers enfants du répertoire racine du contexte.*/*/temp*: Permet d'exclure les fichiers et les dossiers qui commencent partempdans les dossiers qui sont à deux niveaux du répertoire racine du contexte.fichier?: Permet d'exclure tous les dossiers et les fichiers dans le dossier racine du contexte qui commence par fichier et sont suivis d'un caractère alphanumérique.**: Signifie n'importe quel niveau de dossier. Donc par exemple**/*.txtpermet d'exclure tous les fichiers terminant par.txtdans n'importe quel dossier du contexte.!: Signifie exception, cela permet par exemple de ne pas exclure un fichier qui serait normalement exclus suivant les règles précédentes.
7. Persistance des données
Les bases de données servent à persister des données et il faut donc pouvoir ne pas perdre toutes les données à chaque fois que vous modifiez ou relancez un conteneur. Pour ce faire, Docker propose l'utilisation de bind mounts et de volumes qui permettent de résoudre les problèmes de performance (en écrivant directement dans le système de fichiers de l'hôte) et les problèmes de persistance (ils sont conservés après la suppression du conteneur).
- Dans le cas d'un bind mount : Il s'agit tout simplement de fichiers et de dossiers n'importe où sur le système de fichiers de l'hôte. N'importe quel processus peut les modifier, y compris en dehors de Docker.
- Dans le cas d'un volume : Docker utilise le système de fichiers de la machine hôte mais gère lui même cet espace et l'utilisateur doit passer par le Docker
CLI. SurGNU/Linuxl'emplacement sera/var/lib/docker/volumes/mais il ne faut jamais y toucher directement ! - Dans le cas d'un TMPFS : Il s'agit d'un stockage temporaire en mémoire vive (
RAM).
Il faut voir un bind mount comme une liaison dans les deux sens entre conteneur et hôte pour un dossier (et son contenu) ou un fichier. Sur Windows avec Git Bash uniquement, il se peut que le montage ne fonctionne pas en mettant /data, il faut mettre //data. Pour créer ensuite un conteneur avec un bind mount, il faut utiliser la commande :
docker container run -it --name alpine1 --mount type=bind,source="$(pwd)",target=/data alpine sh
Les TMPFS ne sont pas persistés, ils permettent de garder des données en mémoire vive uniquement. Par exemple :
docker run --name tmp --mount type=tmpfs,target=/data -it alpine sh
Dans Docker, un réseau bridge utilise un pont logiciel qui permet à plusieurs conteneurs connectés à ce réseau de communiquer. Les réseaux bridge ne sont utilisables que pour les conteneurs qui sont exécutés sur le même hôte. Lorsque vous lancez Docker sur une machine, un réseau bridge par défaut est créé automatiquement.
8. Docker Compose
Docker Compose permet de faciliter la création d'application multi-conteneur. Docker Compose ne remplace pas du tout les Dockerfiles. Docker Compose s'utilise de la manière suivante :
- Votre application comporte plusieurs
Dockerfiles, un par image que vous voulez utiliser. - Votre application a un fichier
docker-compose.ymlqui définit les services que votre application a besoin pour fonctionner. Un service est par exemple une base de données, uneAPI Rest, unreverse proxy, une applicationSPA... - Vous lancez la commande
docker compose upqui va démarrer tous les services suivant les options définies.
8.1 Configurations
Il faut créer un fichier docker-compose.yml ou docker-compose.yaml pour utiliser les commande docker compose :
version: "3.9"
services:
myalpine:
image: alpine
La configuration command permet de remplacer la commande par défaut de l'image. Par exemple :
version: "3.9"
services:
myalpine:
image: alpine
command: ls
La configuration entrypoint permet de remplacer l'entrypoint par défaut de l'image. Par exemple :
version: "3.9"
services:
myalpine:
image: alpine
entrypoint: ls
8.2 Commandes
Afin de lancer mettre en place la configuration créé dans le fichier docker-compose.yml (build). Il faut utiliser la commande suivante après chaque modification de docker-compose.yml :
docker compose up
La commande qui permet d'exécuter une commande par un service est la suivante :
docker compose run
Pour voir uniquement les conteneurs lancés par Docker compose, on utilise la commande suivante :
docker compose ps
La commande qui permet de stopper tous les conteneurs lancés par Docker compose est la suivante :
docker compose down
8.3 Personnalisation
On peut utiliser Docker Compose avec des images personnalisées (Dockerfiles), pour cela il faut utiliser build qui permet de définir le chemin du contexte, ici dans le meme dossier que le Dockerfiles :
version: '3.9'
services:
a:
image: alpine
command: ['ls']
b:
build: .
La commande docker compose build permet de construire toutes les images spécifiées dans le fichier de configuration (dans les configurations build) et de les taguer pour une future utilisation.
On peut passer des arguments et des labels durant le build, pour passer des arguments à l'instruction ARG de Dockerfiles (ARG FOLDER ici), on utilise :
version: '3.9'
services:
a:
image: alpine
command: ['ls']
b:
build:
context: ./backend
dockerfile: Dockerfile
args:
FOLDER=test
labels:
email=jean@gmail.com
On peut définir quels ports doivent être publiés pour un service dans le fichier de configuration docker-compose.yml. Le format est toujours HOTE:CONTENEUR puis par défaut TCP, on peut préciser UDP avec /upd :
ports:
"80:80"
"8080:3000/udp"
Il est possible de monter des chemins de l'hôte (bind mount) ou de créer des volumes anonymes ou nommés :
build: .
volumes:
type: bind
source: ./data
target: /app/data
Pour créer un volume nommé, il faut déclarer dans une configuration au même niveau que services une clé volumes : ce sont les volumes nommés qui seront automatiquement créés par Docker Compose :
version: '3.9'
services: ...
volumes:
data3:
On peut utiliser des variables d'environnement dans un Dockerfile ou dans un fichier docker-compose.yml, par exemple :
backend:
image: "node-app:${NODE_APP_VERSION}"
Définir la valeur des variables d'environnement avec environment :
backend:
environment:
NODE_APP_VERSION=2.2.3
Tous les services définis dans le docker-compose.yml rejoignent ce réseau avec leur nom définis dans ce fichier. En plus du réseau par défaut, il est possible de définir d'autres réseaux. Par exemple :
version: '3.9'
services:
proxy:
image: nginx
networks:
frontend
app:
image: nginx
networks:
frontend
backend
networks:
frontend:
backend:
name: backend
La configuration depends_on permet de spécifier qu'un service dépend d'autres services. Cela entraîne les comportements suivants :
docker compose upva démarrer les services qui sont des dépendances d'autres services avant.docker compose up SERVICEva inclure automatiquement le démarrage de toutes les dépendances du service.docker compose downva d'abord stopper les dépendances avant les autres services.