ENTRYPOINT VS CMD
Un peu de théorie : la différence entre ENTRYPOINT et CMD
DONNE MOI LE RÉSUMÉDepuis le début, dans chacun de nos Dockerfile, nous utilisons deux mots clefs de manière conjointement : ENTRYPOINT
et CMD
. Cela peut être un peu compliqué de comprendre la différence entre les deux et pourquoi utiliser les deux. Je propose que l’on regarde cela ensemble avec quelques cas pratiques.
Ce qu’il faut comprendre, c’est qu’il faut voir le mot clef ENTRYPOINT
comme le point d’entrée de notre conteneur. On lui passe le chemin vers un script que l’on souhaite qu’il soit constamment exécuté, peu importe si la personne qui va démarrer notre conteneur souhaite changer la commande.
On peut voir ENTRYPOINT
comme un passage obligatoire, une sorte de douane que l’on souhaite faire passer à tous les utilisateurs de notre conteneur. Cela ne veut pas dire que l’utilisateur final ne peut pas modifier l’ENTRYPOINT
, mais juste que c’est à ses risques et périls de le faire en utilisant l’option --entrypoint
. En d’autre terme, modifier la commande (définis par CMD
)que lance un conteneur, c’est courant, changer l’ENTRYPOINT
c’est plus rare.
Ainsi, dans le script que l’on donne à ENTRYPOINT
, on y définit l’ensemble de ce qui va être nécessaire au bon fonctionnement de l’application et de la commande CMD
. C’est important aussi de savoir que l’ensemble de ce que l’on définit dans CMD
sera passé en paramètres de l’ENTRYPOINT
.
Ok assez de théorie, voyons la pratique maintenant avec quelques exemples.
Commençons par créer un nouveau dossier entrypoint-cmd
mkdir entrypoint-cmd
cd entrypoint-cmd
Dans cette partie, nous allons modifier plusieurs fois notre script et notre Dockerfile. N’oublie pas de reconstruire à chaque fois l’image si tu ne vois pas les changements dans tes conteneurs.
Écrivons un premier script entrypoint.sh
tout simple qui commence par nous dire bonjour puis affiche ces arguments.
#!/bin/bash
echo "Hello Tornade.io"
echo "Voici les arguments: $@"
On crée ensuite un Dockerfile tout simple, qui ne fait que copier ce script, le rend exécutable et le définis comme ENTRYPOINT
par défaut. On passe aussi une CMD
par défaut.
FROM debian
COPY ./entrypoint.sh /usr/bin/entrypoint.sh
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
CMD ["des parametres ", "par defaut"]
On construit notre image et lance notre conteneur dans la foulée.
docker build --tag entrypoint-vs-cmd .
docker run entrypoint-vs-cmd
> Hello Tornade.io
> Voici les arguments: des parametres par defaut
On voit bien que notre script d’entrypoint est exécuté et que ses paramètres sont ceux définis dans CMD
.
Regardons maintenant ce qu’il se passe lorsque l’on modifie la commande a exécuté au lancement d’un autre conteneur.
docker run entrypoint-vs-cmd 'des autres ' 'parametres'
> Hello Tornade.io
> Voici les arguments : des autres parametres
Comme la première fois, c’est bien notre entrypoint.sh qui est exécuté et les arguments donnés à docker run
ont pris la place de ceux du Dockerfile de CMD
.
Ok, mais admettons maintenant que je veux réellement exécuter quelque chose et pas juste passer des paramètres qui vont être répétés.
Reprenons notre Dockerfile, et modifions les paramètres dans CMD pour effectuer un ls -la
par défaut.
FROM debian
COPY ./entrypoint /usr/bin/entrypoint.sh
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ['entrypoint.sh']
CMD ["ls", "-la"]
Modifions aussi notre script entrypoint.sh
pour qu’il exécute la commande qu’il reçoit en paramètres.
#!/bin/bash
set -e # On dit à bash : si y'a la moindre erreur, tu arrete l'execution du script.
echo "Tu passeras par la dans tous les cas !"
exec "$@" # Execute ce qui est passé en paramètres
Reconstruisons notre image et lançons la
docker build --tag entrypoint-vs-cmd .
docker run entrypoint-vs-cmd
> Tu passeras par la dans tous les cas !
> total 60
drwxr-xr-x 1 root root 4096 Feb 17 13:41 .
drwxr-xr-x 1 root root 4096 Feb 17 13:41 ..
-rwxr-xr-x 1 root root 0 Feb 17 13:41 .dockerenv
lrwxrwxrwx 1 root root 7 Feb 11 00:00 bin -> usr/bin
drwxr-xr-x 2 root root 4096 Jan 28 21:20 boot
drwxr-xr-x 5 root root 340 Feb 17 13:41 dev
drwxr-xr-x 1 root root 4096 Feb 17 13:41 etc
drwxr-xr-x 2 root root 4096 Jan 28 21:20 home
lrwxrwxrwx 1 root root 7 Feb 11 00:00 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Feb 11 00:00 lib64 -> usr/lib64
drwxr-xr-x 2 root root 4096 Feb 11 00:00 media
drwxr-xr-x 2 root root 4096 Feb 11 00:00 mnt
drwxr-xr-x 2 root root 4096 Feb 11 00:00 opt
dr-xr-xr-x 225 root root 0 Feb 17 13:41 proc
drwx------ 2 root root 4096 Feb 11 00:00 root
drwxr-xr-x 3 root root 4096 Feb 11 00:00 run
lrwxrwxrwx 1 root root 8 Feb 11 00:00 sbin -> usr/sbin
drwxr-xr-x 2 root root 4096 Feb 11 00:00 srv
dr-xr-xr-x 13 root root 0 Feb 17 13:41 sys
drwxrwxrwt 2 root root 4096 Feb 11 00:00 tmp
drwxr-xr-x 1 root root 4096 Feb 11 00:00 usr
drwxr-xr-x 11 root root 4096 Feb 11 00:00 var
On voit bien que notre script entrypoint est exécuté et lance ensuite la commande ls -la
donnée en paramètre par défaut avec CMD
Si on modifie à la volée les paramètres au lancement avec docker run, on voit de nouveau que entrypoint n’est pas modifié, seulement ces arguments.
docker run entrypoint-vs-cmd echo "J'adore Tornade.io"
> Tu passeras par la dans tous les cas !
> J'adore Tornade.io
Grâce à cela, il est possible de forcer les utilisateurs de nos images a passé par un chemin et une suite de commande que nous dirigeons dans le ENTRYPOINT
. Il est tout de même possible de modifier l’entrypoint avec docker run --entrypoint <script>
, mais c’est plutôt rare.
L’intérêt de la distinction entre CMD
et ENTRYPOINT
prend tout son sens si nous conteneurisons une application ayant des dépendances avec d’autre système. Si pour démarrer, ton appli, tu dois obligatoirement te connecter à une base de donnée, il peut être judicieux d’attendre que la connexion soit possible dans le script d’entrypoint pour ensuite démarrer ton application.
Un autre exemple et si tu dois absolument télécharger ou créer des fichiers à la volée avant de lancer ton application. On peut faire ces étapes dans le script d’entrypoint, nous assurant de la création comme il faut des fichiers nécessaires avant de réellement démarrer l’application.
Dans la majorité des applications déployés par conteneur, entrypoint est utilisé comme un script de préparation de dernière minute, avant de lancer l’application en prod.
On commence à avoir pas mal de conteneur / d’image inutile. Il ne faut pas hésiter à nettoyer tout cela. Pour rappel, on regarde tous les conteneurs avec docker ps -a
et on les supprime avec docker rm ID
. Pour les images, docker image ls -a
et on les supprime avec docker rmi ID
ou docker image rm ID
.
Pro tip : il est possible de supprimer tous d’un coup
docker rm $(docker ps -aq)
docker rmi $(docker image ls -aq)
Takeaways
ENTRYPOINT
et CMD
ont deux rôles différents.
ENTRYPOINT
peut être vu comme le point d’entrée, le passage obligatoire pour l’exécution de la commande CMD
.
Lorsque l’on modifie avec docker run
la commande a exécuté, on modifie à la volée le contenu de CMD
.
Il est possible de modifier l’entrypoint avec l’option --entrypoint <script>
.