Mots-clés du Dockerfile
Ceux que nous connaissons déjà
Nous avons vu les mots-clés du Dockerfile FROM
et RUN
.
FROM
Le mot-clé FROM
permet d'indiquer sur quelle image de base nous construirons notre propre image personnalisée.
RUN
RUN
lance une ou plusieurs commandes Linux pendant la phase de construction de notre image.
ENTRYPOINT et CMD
Nous allons essayer de comprendre les mécanismes et les différences de ENTRYPOINT
et de CMD
.
Lancer des commandes
Pour faire simple ces deux mots-clés exécutent une commande lorsque que le conteneur est lancé. Nous devons absolument nous servir d'un tableau (par exemple : ["ps", "-a"]) pour décrire ce que nous souhaitons.
Pour bien comprendre, nous allons utiliser un exemple. Réutilisons le Dockerfile précédent et ajoutons ce que nous avons appris.
ENTRYPOINT
Commençons par ENTRYPOINT
.
FROM celtak/ubuntu-ping-ip
RUN apt-get update
RUN apt-get install -y nodejs
ENTRYPOINT ["node", "-v"]
# Équivalent de la commande "node -v"
Construisons notre image.
Pour les images, je vous propose le format de nom suivant ubuntu_nodejs_test_<nombre>
. Faire ainsi, nous permettra de nous y retrouver, car nous allons construire beaucoup d'images.
docker build -t ubuntu_nodejs_test_1 .
Maintenant, lançons le conteneur (sans l'option -it
).
docker run --rm ubuntu_nodejs_test_1
Quel résultat notre machine affiche-t-il ?
v8.10.0
# La version de Node.js installé. Le numéro de la version est peut-être différent.
Pourquoi?
Parce qu'ajouter ENTRYPOINT ["node", "-v"]
équivaut à demander à Docker de lancer la commande node -v
après la création de notre conteneur. Et le résultat de cette commande est le numéro de la version.
CMD
Modifions le Dockerfile et remplaçons ENTRYPOINT
par CMD
.
FROM celtak/ubuntu-ping-ip
RUN apt-get update
RUN apt-get install -y nodejs
CMD ["node", "-v"]
Construisons l'image correspondante.
docker build -t ubuntu_nodejs_test_2 .
Enfin lançons un conteneur.
docker run --rm ubuntu_nodejs_test_2
Que se passe-t-il ?
v8.10.0
La même chose ! Est-ce que cela signifie que ces deux mot-clés sont identiques ? Pas tout à fait.
Différence entre ENTRYPOINT et CMD
Il y a une principale différence entre les deux.
Tapez la commande qui suit. Le résultat apparaître juste après.
docker run --rm ubuntu_nodejs_test_1 node -h
# ENTRYPOINT
v8.10.0
Dans notre commande, nous avons ajouté node -h
. Pourtant, rien n'a changé au niveau du résultat.
Maintenant essayons ceci.
docker run --rm ubuntu_nodejs_test_2 node -h
# CMD
...
NODE_NO_WARNINGS set to 1 to silence process warnings
NODE_NO_HTTP2 set to 1 to suppress the http2 module
NODE_OPTIONS set CLI options in the environment
via a space-separated list
NODE_PATH ':'-separated list of directories
prefixed to the module search path
NODE_PENDING_DEPRECATION set to 1 to emit pending deprecation
warnings
NODE_REPL_HISTORY path to the persistent REPL history
file
NODE_REDIRECT_WARNINGS write warnings to path instead of
stderr
OPENSSL_CONF load OpenSSL configuration from file
Documentation can be found at https://nodejs.org/
Cette fois-ci, nous voyons la documentation de Node.js (résultat de node -h
) qui apparaît.
Intéressant 🤔 ! Cela signifie que l'on ne peut pas modifier la commande node -v
, lors du lancement du conteneur, avec un ENTRYPOINT
. Mais c'est possible avec CMD
.
Utiliser les deux mot-clés
Il est possible d'utiliser les deux mots-clés dans certains cas. Par exemple, imaginons qu'au démarrage du conteneur, nous souhaitons exécuter la commande node -v
. Mais nous voulons également donner la possibilité à l'utilisateur de modifier l'option -v
. Nous pourrions créer un Dockerfile comme suit.
FROM celtak/ubuntu-ping-ip
RUN apt-get update
RUN apt-get install -y nodejs
ENTRYPOINT ["node"]
CMD ["-v"]
Testons les choses.
docker build -t ubuntu_nodejs_test_3 .
docker run --rm ubuntu_nodejs_test_3
# Résultat : Version de Node.js
docker run --rm ubuntu_nodejs_test_3 -h
# Résultat : Documentation de Node.js
Nous utilisons CMD
pour donner la possibilité à l'utilisateur de modifier l'option -v
par autre chose.
LABEL
Le LABEL
ajoute des métadonnées à notre image.
ℹ️ Une métadonnée est une information.
L'utilisation est simple. Il suffit d'utiliser une clé et une valeur.
Nous allons modifier notre Dockefile. Commençons par effacer les lignes correspondantes au ENTRYPOINT
et au CMD
. Ajoutons deux LABEL
.
FROM celtak/ubuntu-ping-ip
RUN apt-get update
RUN apt-get install -y nodejs
LABEL description="Une image pour tester"
LABEL version="1.0.0"
Comment un utilisateur peut-il afficher les métadonnées ?
Grâce à la commande docker inspect
. Pas la peine de créer un conteneur. Cette commande est utilisable directement sur une image.
Par contre, avant, il nous faudra construire l'image que nous appellerons ubuntu_nodejs_test_4
.
docker build -t ubuntu_nodejs_test_4 .
Ensuite taper le commande qui suit.
docker inspect ubuntu_nodejs_test_4
Beaucoup d'informations nous sont projetées. Mais si vous cherchez bien (en scrollant), vous tomberez sur les métadonnées que nous avons créées.
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"description": "Une image pour tester",
"version": "1.0.0"
}
ENV
L'instruction ENV
permet de gérer des variables d'environnement.
Qu'est-ce qu'une variable d'environnement ? C'est une variable accessible depuis n'importe quel endroit de notre machine.
Pour configurer une variable d'environnement dans Docker, il faut utiliser une clé et une valeur.
Nous allons pratiquer pour bien comprendre. Dans notre Dockerfile, commençons par supprimer les LABEL
.
Ajoutons une variable d'environnement.
FROM celtak/ubuntu-ping-ip
RUN apt-get update
RUN apt-get install -y nodejs
ENV PRENOM="Henrique"
Le nom de la variable est PRENOM
et son contenu est Henrique
.
Construisons notre image.
docker build -t ubuntu_nodejs_test_5 .
Maintenant, on va lancer un conteneur. Il faudra interagir avec celui-ci.
docker run --rm -it ubuntu_nodejs_test_5
Nous sommes désormais dans le conteneur. Pour vérifier que notre variable est bien présente, utilisez la commande printenv
.
printenv PRENOM
Le résultat est le suivant.
Henrique
Cela prouve que notre système reconnaît bien notre variable d'environnement 👌.
ADD et COPY
ADD
et COPY
permettent de copier un dossier et/ou des fichiers qui se trouvent dans notre machine locale vers le conteneur.
J'utiliserai ADD
pour les exemples, mais le principe est identique pour COPY
.
La principale différence entre les deux, est que ADD
nous permet également de copier des fichiers via une URL.
Pour l'exemple nous allons créer un dossier qui portera le nom test
et on y mettra à l'intérieur à fichier index.html
. On pourra les placer à côté du fichier Dockerfile, pour plus de facilité.
mkdir test && touch test/index.html
Nous allons modifier les fichiers index.html
. Ajoutons le mot coucou
echo "coucou" > test/index.html
Voilà, nous sommes prêts 😐.
Pour la prochaine étape, nous allons supprimer la variable d'environnement que nous avons précédemment créé et ajouter la commande ADD
.
FROM celtak/ubuntu-ping-ip
RUN apt-get update
RUN apt-get install -y nodejs
ADD /test /test_local
Dans ce Dockerfile, nous allons copier le dossier test
de notre machine locale vers le dossier test_local
de notre conteneur.
Pour vérifier que tout fonctionne bien, comme d'habitude, nous allons créer notre image et ensuite créer notre conteneur.
docker build -t ubuntu_nodejs_test_6 .
docker run --rm -it ubuntu_nodejs_test_6
Vérifions que notre dossier apparaît bien dans notre conteneur.
ls
bin dev home lib64 mnt proc run srv test_local usr
boot etc lib media opt root sbin sys tmp var
Nous voyons bien test_local
.
Maintenant vérifions que notre fichier index.html existe et qu'il contient le mot coucou
.
cat test_local/index.html
coucou
Ça fonctionne 😃.
VOLUME
L'instruction VOLUME
permet de créer automatiquement un répertoire dans la machine locale et le conteneur qui seront liés. Celui-ci sera automatiquement supprimé à la destruction du conteneur.
Faisons un test et modifions notre Dockerfile.
FROM celtak/ubuntu-ping-ip
RUN apt-get update
RUN apt-get install -y nodejs
VOLUME /volume_test
Construisons notre image.
docker build -t ubuntu_nodejs_test_7 .
Construisons un conteneur.
docker run --rm -it ubuntu_nodejs_test_7
Dans notre conteneur si nous tapons la commande ls
, nous tombons sur notre volume créé (volume_test
).
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr volume_test
Mais qu'en est-il coté machine locale ?
Sans sortir du conteneur (pour ne pas le supprimer), ouvrez une fenêtre de votre terminal et tapez la commande docker volume ls
.
Vous allez tomber sur le volume créé, coté machine locale.
local 0e04fc8176c263ca1bf73580770c1b4e2d118027f4acbd6047db81410ff36744
Bien entendu, de votre côté, l'id sera différent.
Si vous supprimez le conteneur en le quittant, les volumes seront supprimés des deux cotés.
WORKDIR
Nous allons maintenant découvrir une nouvelle instruction : WORKDIR
.
Pour bien comprendre son fonctionnement, modifions le Dockerfile et ajoutons WORKDIR
. Au préalable, nous supprimerons la ligne avec VOLUME
.
FROM celtak/ubuntu-ping-ip
RUN apt-get update
RUN apt-get install -y nodejs
WORKDIR /bin
Expliquons ce que WORKDIR
va produire. En quelque sorte cette instruction est un équivalent de la commande cd
qui nous permet d'accéder à un dossier.
Par conséquent, au lancement du conteneur, nous serons positionnés dans le dossier /bin
. Pareillement les instructions RUN
, ENTRYPOINT
, COPY
, ADD
et CMD
seront exécutées à partir de répertoire sélectionné dans WORKDIR
.
Maintenant qu'elle est prête, nous allons pouvoir créer l'image.
docker build -t ubuntu_nodejs_test_8 .
Ensuite nous allons lancer un conteneur basé sur cette image.
docker run --rm -it ubuntu_nodejs_test_8
Après, tapez la commande pwd
qui permet de connaître notre position.
Normalement le résultat est le suivant.
/bin
Cela signifie qu'au lancement de notre conteneur, celui-ci nous positionne automatiquement au dossier /bin
et non à la racine /
. C'est ainsi, car nous avons ajouté la commande WORKDIR /bin
.
EXPOSE
Le mot-clé EXPOSE
permet d'indiquer dans quel port le conteneur écoute. Mais ce n'est qu'une indication sous forme de documentation. Pour mapper réellement un ou plusieurs ports, il faut utiliser l'option -p
.
Nous allons modifier notre Dockerfile.
FROM celtak/ubuntu-ping-ip
RUN apt-get update
RUN apt-get install -y nodejs
EXPOSE 8000
Dans ce fichier, nous indiquons que le port d'écoute est le 8000. C'est une information utile pour l'utilisateur.
⚠️ L'exemple ci-dessus n'est pas réel. Le conteneur n'émet pas réellement d'informations sur le port 8000. L'objectif était juste d'utiliser l'instruction EXPOSE
.
ARG
On va effacer la ligne EXPOSE
et utiliser l'instruction ARG
.
FROM celtak/ubuntu-ping-ip
RUN apt-get update
RUN apt-get install -y nodejs
ARG prenom=henrique
RUN echo $prenom
Le mot-clé ARG
dans ce Dockerfile, n'est pas utile. Mais cet exemple permet de bien comprendre son fonctionnement.
Pour faire simple, ARG
est une variable disponible dans le Dockerfile (elle ne le sera pas dans le conteneur).
Elle est utilisée lors de la création de l'image. À ce moment plusieurs choses seront exécutés. La ligne RUN echo $prenom
affichera le contenu de la variable prenom
grâce à l'instruction ARG prenom=henrique
.
Testons ce qui a été écrit.
On va créer l'image et copier ce que le terminal affiche.
docker build -t ubuntu_nodejs_test_9 .
[+] Building 0.4s (8/8) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 294B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/celtak/ubuntu-ping-ip:latest 0.0s
=> [1/4] FROM docker.io/celtak/ubuntu-ping-ip 0.0s
=> CACHED [2/4] RUN apt-get update 0.0s
=> CACHED [3/4] RUN apt-get install -y nodejs 0.0s
=> [4/4] RUN echo henrique 0.3s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:f6710c927511611a66b2b96bf4ede2556318a4318670a 0.0s
=> => naming to docker.io/library/ubuntu_nodejs_test_9 0.0s
Dans les informations exposées on peut voir dans la dixième ligne en partant du haut, on peut apercevoir RUN echo henrique
, ce qui confirme ce que nous avons dit précédemment.
Nous pouvons changer le contenu de la variable lors de la création de l'image.
docker build --build-arg prenom=melanie -t ubuntu_nodejs_test_10 .
[+] Building 0.4s (8/8) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 176B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/celtak/ubuntu-ping-ip:latest 0.0s
=> [1/4] FROM docker.io/celtak/ubuntu-ping-ip 0.0s
=> CACHED [2/4] RUN apt-get update 0.0s
=> CACHED [3/4] RUN apt-get install -y nodejs 0.0s
=> [4/4] RUN echo melanie 0.3s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:cf149e31809b8027a551f54c4cd9b3246ed7482f0674a 0.0s
=> => naming to docker.io/library/ubuntu_nodejs_test_10 0.0s
Ce n'est plus RUN echo henrique
qui est affiché mais RUN echo melanie
.
⚠️ La documentation de Docker nous encourage à ne pas à utiliser ARG
pour y insérer des données sensibles comme des mots de passes dans des variables. Car ces données seront récupérables avec un docker history <image>
.
D'autres instructions
Il existe d'autres instructions utiles pour concevoir un Dockerfile. N'hésitez à aller consulter la documentation pour les découvrir.
🗑 Supprimer toutes les images
Après avoir fait tous ces exercices, nous nous retrouvons avec beaucoup d'images générées. Supprimons-les tous avec la commande qui suit.
docker image rm ubuntu_nodejs_test_1 ubuntu_nodejs_test_2 ubuntu_nodejs_test_3 ubuntu_nodejs_test_4 ubuntu_nodejs_test_5 ubuntu_nodejs_test_6 ubuntu_nodejs_test_7 ubuntu_nodejs_test_8 ubuntu_nodejs_test_9 ubuntu_nodejs_test_10