Les pubs vous déplaisent ? Aller Sans pub Auj.

Docker ENTRYPOINT vs CMD — Votre conteneur vous a menti

Mis à jour le

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.

Docker ENTRYPOINT vs CMD — Votre conteneur vous a menti 1
ANNONCE · Supprimer ?

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éfiniNon définiErreur — le conteneur a besoin d'une commande à partir de quelque part
Non défini["cmd", "arg"] forme execcmd arg
Non définicmd arg forme shell/bin/sh -c "cmd arg"
["entry"] forme execNon définientry
["entry"] forme exec["arg1", "arg2"] forme execentry arg1 arg2
["entry"] forme execcmd arg forme shellentry /bin/sh -c "cmd arg" — presque certainement erroné
entry forme shell["arg1"] forme exec/bin/sh -c "entry"CMD ignorée silencieusement
entry forme shellcmd 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 ENTRYPOINT et CMD utilisent 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 myimage et docker run myimage --your-flag pour confirmer que les deux chemins fonctionnent
  • docker stop mycontainer se 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.

Envie d'une expérience sans pub ? Passez à la version sans pub

Installez nos extensions

Ajoutez des outils IO à votre navigateur préféré pour un accès instantané et une recherche plus rapide

Sur Extension Chrome Sur Extension de bord Sur Extension Firefox Sur Extension de l'opéra

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 !

ANNONCE · Supprimer ?
ANNONCE · Supprimer ?
ANNONCE · Supprimer ?

Coin des nouvelles avec points forts techniques

Impliquez-vous

Aidez-nous à continuer à fournir des outils gratuits et précieux

Offre-moi un café
ANNONCE · Supprimer ?