Docker ENTRYPOINT vs CMD — Votre conteneur vous a menti
Vous avez combiné ENTRYPOINT et CMD dans votre Dockerfile, le conteneur a démarré avec la mauvaise application, et vous êtes ici. Voici l'analyse complète — toutes les combinaisons possibles, le piège entre shell et forme exec, et les modèles qui fonctionnent réellement.
L'erreur se produit à 2h. Vous lancez votre conteneur, et au lieu de votre serveur API, vous obtenez un prompt de shell. Ou rien du tout. Ou votre processus s'exécute emballé dans un fantôme sh qui mange SIGTERM comme de la confisération — une arrêt gracieux dure 10 secondes de Docker avant de céder et d'envoyer SIGKILL.
L'origine, presque chaque fois : vous avez confondu ENTRYPOINT et CMD. Ou vous les avez combinées de manière que Docker les accepte silencieusement — juste pas comme vous l'attendiez.
CMD : Le Par défaut que vous pouvez remplacer
CMD définit ce qui s'exécute lors du lancement d'un conteneur — mais ce n'est qu'une suggestion, pas une règle. Tout ce qui suit le nom de l'image est remplacé entièrement :
FROM ubuntu
CMD ["echo", "hello from CMD"]
$ docker run myimage
hello from CMD
$ docker run myimage echo goodbye
goodbye
Cela echo goodbye n'a pas été ajouté — il a remplacé. Votre ensemble entier CMD est disparu. C'est par design : CMD est le comportement par défaut, pas le comportement imposé. Tout argument en temps de fonctionnement l'emporte.
ENTRYPOINT : La partie qui s'exécute toujours
ENTRYPOINT définit l'exécutable qui s'exécute quel que soit le cas. Les arguments en temps de fonctionnement ne le remplacent pas — ils sont passés à l'exécutable au lieu :
FROM ubuntu
ENTRYPOINT ["echo"]
CMD ["hello"]
$ docker run myimage
hello
$ docker run myimage goodbye
goodbye
$ docker run --entrypoint cat myimage /etc/hostname
mycontainer-abc123
Quand les deux sont définis, ENTRYPOINT est l'exécutable et CMD devient ses arguments par défaut. Vous pouvez surcharger CMD librement. Vous pouvez surcharger ENTRYPOINT seulement si vous passez explicitement --entrypoint.
Toutes les combinaisons ENTRYPOINT + CMD, expliquées
Les documents Docker incluent ce tableau, mais ne s'attardent pas sur les lignes qui détruisent votre journée :
| Optionnel. Utilisé lorsque CMD ne fournit que des arguments. | Processus par défaut lors du lancement du conteneur. | Ce qui s'exécute réellement |
|---|---|---|
| Non défini | Non défini | Erreur — le conteneur a besoin d'une commande à partir de quelque part |
| Non défini | ["cmd", "arg"] forme exec | cmd arg |
| Non défini | cmd arg forme shell | /bin/sh -c "cmd arg" |
["entry"] forme exec | Non défini | entry |
["entry"] forme exec | ["arg1", "arg2"] forme exec | entry arg1 arg2 ✓ |
["entry"] forme exec | cmd arg forme shell | entry /bin/sh -c "cmd arg" — presque certainement erroné |
entry forme shell | ["arg1"] forme exec | /bin/sh -c "entry" — CMD ignorée silencieusement |
entry forme shell | cmd arg forme shell | /bin/sh -c "entry" — CMD ignorée silencieusement |
Les deux lignes marquées « CMD ignorée silencieusement » sont responsables d'une grande partie des sessions de débogage Docker. Forme shell ENTRYPOINT ne se fusionne pas avec CMD — elle l'ignore entièrement. Docker ne vous prévient pas de cela.
Forme shell vs Forme exec : Le piège de la gestion des signaux
Les deux instructions acceptent deux formes, et le choix en compte plus que la plupart des tutoriels Dockerfile.
Forme exec (syntaxe tableau) :
ENTRYPOINT ["nginx", "-g", "daemon off;"]
Votre exécutable s'exécute directement. Il devient le PID 1. Quand Docker envoie SIGTERM pour arrêter le conteneur, votre processus reçoit ce signal. L'arrêt gracieux fonctionne. Les logs sont vides. Les connexions se ferment proprement.
CMD (chaîne simple) :
ENTRYPOINT nginx -g "daemon off;"
Docker exécute cela comme /bin/sh -c "nginx -g daemon off;". Le shell devient le PID 1. Quand SIGTERM arrive, sh le reçoit — et sh ne le transmet pas aux processus enfants. Votre conteneur reste bloqué pendant 10 secondes, reçoit SIGKILLet meurt sans nettoyage. Chaque fois.
Utilisez la forme exec. Toujours. Pour les deux ENTRYPOINT et CMD.
Trois modèles qui fonctionnent réellement
Modèle 1 : Exécutable fixe, paramètres interchangeables
Le bon modèle pour la plupart des conteneurs en production. L'exécutable est fixe ; les paramètres sont interchangeables en temps de fonctionnement :
ENTRYPOINT ["/app/server"]
CMD ["--port", "8080", "--env", "production"]
# Use defaults
docker run myimage
# Override at deploy time
docker run myimage --port 9090 --env staging
Modèle 2 : Script d'enveloppe avec exec
Quand vous avez besoin de logique d'initialisation avant votre processus principal (migrations, injection des secrets, interception des signaux), utilisez un script d'enveloppe. La ligne critique est exec "$@" à la fin — elle remplace le processus de shell par votre CMD, donc votre exécutable devient le PID 1 :
#!/bin/sh
set -e
echo "Running migrations..."
/app/migrate
# Hand off to CMD — exec replaces shell, so /app/server becomes PID 1
exec "$@"
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["/app/server", "--port", "8080"]
Si vous omettez exec "$@", le shell reste le PID 1 et vous retournez aux problèmes de gestion des signaux.
Modèle 3 : CMD uniquement, sans ENTRYPOINT
Adapté aux images de développement ou aux conteneurs d'outils où vous souhaitez exécuter des commandes arbitraires dans le même environnement :
FROM python:3.12-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
En production, le modèle 1 ou 2 est plus sûr — vous ne voulez pas qu'un script mal configuré déployé accidentellement exécute docker run myimage bash et remplace votre serveur par une session de shell.
Ce que docker exec a à faire avec cela
Rien. docker exec exécute une commande dans un conteneur déjà lancé. Il passe complètement par ENTRYPOINT . Vous n'avez pas besoin de penser à ENTRYPOINT lorsque vous exécutez docker exec mycontainer bash pour explorer — vous parlez à l'environnement actif du conteneur, pas à la configuration de démarrage.
L'ambiguïté vient généralement des personnes qui déboguent avec docker exec et confirment que tout fonctionne, puis se demandent pourquoi docker run comportent différemment. Ce sont deux chemins de code totalement distincts.
Liste de vérification avant le lancement
- Les deux
ENTRYPOINTetCMDutilisent la forme exec (syntaxe tableau, pas de chaînes simples) - Si vous avez un script d'enveloppe, il se termine par
exec "$@" - Vous avez testé
docker run myimageetdocker run myimage --your-flagpour confirmer que les deux chemins fonctionnent docker stop mycontainerse termine en moins de 2 secondes (pas 10 — si c'est 10, vous avez un problème de signal)
Si vous souhaitez un retour automatique avant que votre Dockerfile ne soit envoyé vers un registre, IO Tools’ Dockerfile Linter capture l'utilisation de la forme shell, l'absence de exec dans les scripts d'entrée, et d'autres modèles causant un comportement silencieux en temps de fonctionnement.
Installez nos extensions
Ajoutez des outils IO à votre navigateur préféré pour un accès instantané et une recherche plus rapide
恵 Le Tableau de Bord Est Arrivé !
Tableau de Bord est une façon amusante de suivre vos jeux, toutes les données sont stockées dans votre navigateur. D'autres fonctionnalités arrivent bientôt !
Outils essentiels
Tout voir Nouveautés
Tout voirMise à jour: Notre dernier outil a été ajouté le 6 juin 2026
