Ceci est une ancienne révision du document !
Lister les volumes :
docker volume ls
Créer un volume nommé MyVolume
:
docker volume create MyVolume
Ci-dessous pour démarrer un conteneur en utilisant le volume MyVolume
qui sera monté dans le dossier /mnt/vol_docker
du conteneur :
docker run -d --name MyContainer -v MyVolume:/mnt/vol_docker ubuntu
ou
docker run -d --name MyContainer --mount type=bind,source=MyVolume,destination=/mnt/vol_docker ubuntu
Pour identifier où sont stockées les données de MyVolume
sur la machine hôte :
docker volume inspect MyVolume
Exemple de résultat attendu :
[ { "CreatedAt": "2023-11-17T11:06:32Z", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/MyVolume/_data", "Name": "MyVolume", "Options": null, "Scope": "local" } ]
Les données des volumes sont stockées dans le répertoire
/var/lib/docker/volumes/
de la machine hôte. Les données de MyVolume
sont stockées dans le répertoire /var/lib/docker/volumes/MyVolume/_data
.
Pour identifier les conteneurs qui utilisent le volume MyVolume
:
docker ps -a --filter volume=MyVolume
Exemple de résultat attendu :
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b3f7ec23a377 httpd "httpd-foreground" 29 minutes ago Up 29 minutes 80/tcp MyContainer
Pour supprimer le volume MyVolume
:
docker volume rm MyVolume
Remarque : Les conteneurs créés en utilisant le volume, doivent être arrêté et supprimé avant :
docker stop MyContainer docker rm MyContainer docker volume rm MyVolume
On peut aussi démarrer un conteneur en montant un dossier du système hôte dans un répertoire du conteneur.
Par exemple, ci-dessous on monte le dossier /mnt
de l'hôte dans le dossier /home
du conteneur.
docker run -d --name MyC2 --mount type=bind,source=/mnt,destination=/home httpd
Pour inspecté le montage du conteneur :
docker inspect -f '{{ .Mounts }}' MyC2
Pour démarrer une instance avec le dossier /home
du conteneur en mémoire RAM de l'hôte :
docker run -d --name MyC3 --mount type=tmpfs,destination=/home httpd
A COMPLETER
Pour lancer un conteneur avec un autre utilisateur :
docker run -d --name MyC1 -u benoit httpd
Quelques commandes.
Pour lister les réseaux :
docker network ls
Exemple de résultat :
NETWORK ID NAME DRIVER SCOPE a5058156ace7 bridge bridge local 308d0f7c3659 host host local 499ff58d4934 none null local
Pour avoir les détails sur les caractéristiques d'une des réseaux (par exemple le réseau Bridge) :
docker network inspect a5058156ace7
Par défaut Docker fonctionne en mode Bridge. Ci-dessous, quelques commandes pour comprendre le comportement.
L'IP locale 172.17.0.1/16 est définie par défaut. Cette IP sera utilisé comme passerelle par défaut pour tous les conteneurs que nous démarrerons.
ip a show docker0
Exemple de résultat :
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ef:43:f6:39 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:efff:fe43:f639/64 scope link valid_lft forever preferred_lft forever
Par exemple, démarrons un conteneur httpd
:
docker run --name c1 -d httpd
Nous pouvons voir que par défaut ce conteneur écoute sur le port 80 :
docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d42852ccd99f httpd "httpd-foreground" 3 seconds ago Up 2 seconds 80/tcp c1
Ci-dessous, nous récupérons l'adresse IP de notre conteneur, son port d'exposition et sa passerelle par défaut :
docker inspect -f '{{.NetworkSettings.IPAddress}} {{.NetworkSettings.Ports}} {{.NetworkSettings.Gateway}}' c1
Résultat :
172.17.0.2 map[80/tcp:[]] 172.17.0.1
Notre conteneur c1 a les caractéristiques suivantes :
Notre hôte docker 172.17.0.1
peut donc interagir avec via le réseau sur le conteneur 172.17.0.2:80
. Exemple :
telnet 172.17.0.2 80
Trying 172.17.0.2... Connected to 172.17.0.2. Escape character is '^]'.
get /
HTTP/1.1 400 Bad Request Date: Mon, 20 Nov 2023 07:33:33 GMT Server: Apache/2.4.58 (Unix) Content-Length: 226 Connection: close Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>400 Bad Request</title> </head><body> <h1>Bad Request</h1> <p>Your browser sent a request that this server could not understand.<br /> </p> </body></html> Connection closed by foreign host.
Cependant, le port 80 du conteneur n'est accessible que par la machine hôte. Une machine externe, ne pourra pas interagir sur le port 80 de notre conteneur. Il faut donc publier le port 80 sur un port disponible de notre hôte.
Nous allons supprimer le conteneur et en créer un nouveau que nous allons publier sur le port 80 du conteneur sur le port 8080 de notre hôte :
docker rm -f c1 docker run --name c1 -p 8080:80 -d httpd
Cette fois nous pouvons voir que notre conteneur écoute sur le port 80 et que celui-ci est publié sur le port 8080 de notre machine :
docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d3bda19ffc15 httpd "httpd-foreground" 4 seconds ago Up 3 seconds 0.0.0.0:8080->80/tcp, :::8080->80/tcp c1
Pour créer un réseau Bridge nommé mynet0
autre que celui par défaut :
docker network create --driver=bridge --subnet=192.168.0.0/24 mynet0
on peut ajouter une option pour que l'interface sur l'hôte se nomme aussi mynet0
:
docker network create --driver=bridge --subnet=192.168.0.0/24 -o com.docker.network.bridge.name="mynet0" mynet0
Pour lancer un conteneur qui utilisera ce réseau :
docker run -d --name c1 --network mynet0 httpd
On peut aussi connecter un conteneur déjà en fonctionnement d'un autre réseau ou réseau par défaut.
Ci-dessous, on va démarrer un conteneur dans le réseau par défaut, puis le connecter également à notre réseau mynet0
:
docker run -d --name c2 httpd docker network connect mynet0 c2
Le conteneur c2
est donc connecté au réseau bridge
par défaut et réseau mynet0
, vérifié par :
docker inspect c2
Le mode host
bypass le port mapping du mode bridge
.
On démarre de conteneur en mode host.
docker run --name c3 -d --network host httpd
Le port 80 de la machine écoutera directement sur l'hôte.
Sauf vraiment cas spécifique, il est mieux d'éviter d'utiliser ce type de réseau.
Permet de créer des images à partir d'un conteneur. Il est recommandé de l'utiliser que dans des cas spécifiques. Par exemple dans les cas suivants :
Pour des modifications plus durable, il vaut mieux s'appuyer sur un Dockerfile.
Pour commencer démarrer un conteneur debian qui lance la commande sleep infinity
:
docker run -d --name c1 debian sleep infinity
On peut se connecter au conteneur, y apporter les modifications que l'on souhaite et le quitter, par exemple :
docker exec -ti c1 bash echo "toto" > /var/lib/toto.txt ... exit
On peut donc créer une image de l'état du conteneur ainsi :
docker commit c1 myimage-c1:v1.0
Avec la commande…
docker image ls
…On peut voir
REPOSITORY TAG IMAGE ID CREATED SIZE myimage-c1 v1.0 0b486f336e68 6 minutes ago 117MB debian latest 0ce03c8a15ec 42 minutes ago 117MB
On peut de nouveau créer un nouveau conteneur à partir de cette image ainsi :
docker run -d --name c2 myimage-c1:v1.0
En listant les processus Docker en fonctionnement…
docker ps
…On constate que les 2 conteneurs sont en fonctionnement avec la commande sleep infinity
:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a9b8064f9bcb myimage-c1:v1.0 "sleep infinity" About a minute ago Up About a minute c2 1600fa08b0a1 debian "sleep infinity" 12 minutes ago Up 12 minutes c1
Pourtant le conteneur c2 n'a pas été lancé avec la commande
sleep infinity
. Ceci montre que la création de l'image prend en compte les processus actifs. Ces mêmes processus seront actif lorsqu'un conteneur est créé à partir de l'image “commitée”.
On peut ajouter d'autres options pour créer l'image, comme un commentaire et ajouter l'auteur de l'image :
docker commit --message "mes commentaires" --author "Benoit" c1 myimage-c1:v1.1
On peut retrouver ces informations ainsi dans l'image :
docker inspect -f "{{.Author}} {{.Comment}}" myimage-c1:v1.1
On peut lister l'historique des commit d'une image ainsi :
docker history myimage-c1:v1.1
Exemple de résultat :
IMAGE CREATED CREATED BY SIZE COMMENT a1b6eff85cc8 8 minutes ago sleep infinity 76B mes commentaires 0ce03c8a15ec About an hour ago /bin/sh -c #(nop) CMD ["bash"] 0B <missing> About an hour ago /bin/sh -c #(nop) ADD file:39d17d28c5de0bd62… 117MB
On peut ajouter des modifications/instructions à lancer pour notre image. Par exemple on ajoute un variable d'environnement MYVAR=Benoit
:
docker commit --change "ENV MYVAR=Benoit" c1 myimage-c1:v1.2
Lorsque l'on créé un conteneur à partir de cette nouvelle image on constate que la variable est bien active :
docker run -d --name c3 myimage-c1:v1.2 docker exec c3 env
Résultat :
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=1f8770a8bb5b MYVAR=Benoit HOME=/root
L'objectif est de créer une image Docker qui permettra de faire fonctionner un conteneur avec notre application.
L'idée est de partir sur un système de base, d'y inclure les prérequis de notre application, installer notre application et les commandes pour exécuter notre application au lancement du conteneur.
Les bonnes pratiques pour créer une image sont les suivantes :
digest
pour cibler la version à déployerRUN
pour éviter de surcharger la taille de l'imageapt update -qq && apt install -qq -y apache2 && apt clean && rm -rf /var/lib/apt/lists/*
.telnet
, tcpdump
..dockerignore
pour exclure des fichiers de la copie. Exclure par exemple le Dockerfile
.COPY
plutôt que ADD
.ADD
uniquement pour télécharger des contenus externes au dossier dédiéCOPY . .
root
root
au lancement de l'application du conteneur.ENV
WORKDIR
En exemple, Nous allons simplement créer une image contenant un serveur Web apache basé sur une image Debian.
Pour commencer, créer un dossier de travail et aller dedans :
mkdir myapp cd myapp
Créer dans le dossier créer un fichier '.dockerignore' et on ajouter la ligne suivante pour ignorer le fichier Dockerfile
:
Dockerfile
On va créer un dossier app
et y mettre une page html.
mkdir app echo "Apache dans conteneur" > app/index.html
Créer le Dockerfile suivant :
vim Dockerfile
Contenu en exemple :
# Source pour l'image de base FROM debian:bullseye-slim # On peut également cibler l'image ainsi avec le Digest SHA256 #FROM debian@sha256:9af4db29e828a4d08c7819f9e0972e2dbdac575e73c6438630c83bd79f49c8aa # Labels pour identifier notre image LABEL version=1.0 LABEL auteur=Benoit # On défini quelque variable d'environnement au sein du conteneur ENV APP_ENV="PreProd" ENV APP_NAME="MyWEB" ENV APP_VER="1.0" # On définir des variable à utilsier dans le Dockerfile ARG APP_USER="benoit" # Création de l'utilisateur RUN adduser ${APP_USER} # Intallation des paquetages requis # A noter qu'on lance l'installation et le nettoyage d'APT pour éviter de surcharger notre image par des Layers RUN apt update && apt install -y apache2 && apt clean && rm -rf /var/lib/apt/lists/*
# On execute les prerequis pour lancer notre serveur Apache2 RUN mkdir -p /var/run/apache2 && . /etc/apache2/envvars # On lance apache2 CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"] # Répertoire de travail de l'App WORKDIR /var/www/html # Ci-dessous la directive pour faire tourner l'application autre que root #USER ${APP_USER} # On copie les fichiers locaux sur le WORKDIR du conteneur COPY app/* . # Exemple ci-dessous en spécifiant les permissions #COPY --chown=${APP_USER} app/* . # On expose le port 80 EXPOSE 80
Lancer le build de l'image
docker build -t webapp:v1 .
Pour lancer un conteneur à partir de notre image :
docker run -d --name c1 -p 8080:80 webapp:v1
Le build multistage permet de reprendre des éléments d'une autre image pour créer l'image.
# Build 0 FROM debian:latest # On crée un fichier /var/toto.1 RUN echo "toto" > /var/toto.1 # Build 1 # On peut définir un alias par exemple b1 pour la source FROM debian:latest AS b1 # On crée le fichier /var/toto.2 RUN echo "toto" > /var/toto.2 # On recopie à partir du build 0 le fichier /var/toto.1 que l'on copie dans / COPY --from=0 /var/toto.1 / # Build 2 FROM debian:latest # On crée le fichier /var/toto.3 RUN echo "toto" > /var/toto.3 # On recopie à partir du build 1 le fichier /var/toto.2 que l'on copie dans / en indiquant l'alias en source COPY --from=b1 /var/toto.2 / # On peut aussi copier un fichier depuis une image existante COPY --from=httpd:latest /usr/local/apache2/conf/httpd.conf /etc
On final dans ce build on retrouvera uniquement les fichiers suivants :
/toto.2
/var/toto.3
/etc/httpd.conf
Le Dockerfile :
# DECLARATION VARIABLE POUR LE BUILD AVEC VALEUR PAR DEFAUT ARG TYPE=development # IMAGE DE BASE FROM debian:latest AS base RUN echo "Base" > /var/info.txt # IMAGE AVEC LES ELEMENTS DE DEV FROM base AS branch-version-development # Tous les élements requis pour l'environnement de Dev RUN echo "dev" >> /var/info.txt ENV ENV=development # IMAGE AVEC LES ELEMENTS DE PROD FROM base AS branch-version-production # Tous les élements requis pour l'environnement de Prod RUN echo "production" >> /var/info.txt ENV ENV=production # IMAGE AVEC LES ELEMENTS DE DEV OU PROD EN FONCTION DE LA VARIABLE TYPE FROM branch-version-${TYPE} AS final UN echo "fin" >> /var/info.txt
Si on souhaite créer une image avec les éléments de dev :
docker build -t myapp:v1 --build-arg TYPE=development .
Et pour la prod :
docker build -t myapp:v1 --build-arg TYPE=production .
On peut aussi lancer le build de la base uniquement :
docker build -t myapp:v1 --target base