Qual è la differenza tra CMD ed ENTRYPOINT in un file Docker?


1698

In Dockerfiles ci sono due comandi che mi assomigliano: CMDe ENTRYPOINT. Ma immagino che ci sia una (sottile?) Differenza tra loro - altrimenti non avrebbe senso avere due comandi per la stessa cosa.

La documentazione indica per CMD

Lo scopo principale di un CMD è fornire i valori predefiniti per un contenitore in esecuzione.

e per ENTRYPOINT:

Un ENTRYPOINT ti aiuta a configurare un contenitore che puoi eseguire come eseguibile.

Quindi, qual è la differenza tra questi due comandi?


12
Questo post sul blog contiene una buona descrizione delle differenze e di come possono essere usate insieme: crosbymichael.com/dockerfile-best-practices.html .
slm,

2
^ quello! Grazie @slm. Ecco un altro riferimento molto simile che potrebbe essere un po 'più aggiornato: docs.docker.com/reference/builder/#entrypoint
Adam Monsen,


1
Questo collegamento fornisce la differenza tra RUN, CMD ed ENTRYPOINT: goinbigdata.com/docker-run-vs-cmd-vs-entrypoint
prafi

1
@JaimeHablutzel La frase è fatevi un favore
Jonathan Komar il

Risposte:


1738

Docker ha un punto di accesso predefinito che è /bin/sh -cma non ha un comando predefinito.

Quando si esegue la finestra mobile in questo modo: docker run -i -t ubuntu bash entrypoint è l'impostazione predefinita /bin/sh -c, l'immagine è ubuntue il comando è bash.

Il comando viene eseguito tramite il punto di accesso. cioè, la cosa reale che viene eseguita è /bin/sh -c bash. Ciò ha consentito a Docker di implementareRUN rapidamente facendo affidamento sul parser della shell.

Più tardi, le persone hanno chiesto di essere in grado di personalizzare questo, ENTRYPOINTe così --entrypointsono stati introdotti.

Tutto ciò che ubuntusegue nell'esempio sopra è il comando e viene passato al punto di accesso. Quando usi l' CMDistruzione, è esattamente come se stessi facendo docker run -i -t ubuntu <cmd>. <cmd>sarà il parametro del punto di accesso.

Otterrai lo stesso risultato anche se invece digiti questo comando docker run -i -t ubuntu. Inizierai comunque una shell bash nel contenitore perché Ubuntu Dockerfile ha specificato un CMD predefinito:CMD ["bash"]

Poiché tutto viene passato al punto di accesso, puoi avere un comportamento molto piacevole dalle tue immagini. L'esempio di @Jiri è buono, mostra come usare un'immagine come "binaria". Quando si utilizza ["/bin/cat"]come punto di accesso e quindi si esegue docker run img /etc/passwd, si ottiene, /etc/passwdè il comando e viene passato al punto di accesso, quindi l'esecuzione del risultato finale è semplicemente /bin/cat /etc/passwd.

Un altro esempio potrebbe essere quello di avere un cli come punto di accesso. Per esempio, se si dispone di un'immagine Redis, invece di correre docker run redisimg redis -H something -u toto get key, si può semplicemente avere ENTRYPOINT ["redis", "-H", "something", "-u", "toto"]e poi correre come questo per lo stesso risultato: docker run redisimg get key.


3
Affatto. ENTRYPOINT imposta i metadati che possono (ma possono essere sovrascritti) in fase di esecuzione, quindi se non cambi nulla, dopo aver avviato il tuo contenitore, il risultato sarà lo stesso, tuttavia, RUN verrà eseguito al momento della compilazione e indipendentemente da ciò che fare in fase di esecuzione, sarà qui.
scricchiolio

8
Di default non c'è ENTRYPOINT; se viene usata una shell dipende dalla forma utilizzata del CMDcomando ( docs.docker.com/engine/reference/builder/#cmd ).
Blaisorblade,

19
Grazie a questo, il contesto storico mi aiuta molto, mentre stavo lottando per ricordare le regole apparentemente arcane su ciò che viene ignorato e ciò che viene aggiunto, ecc. Un punto utile per gli scrittori di documentazione tecnica ovunque: aiutare il lettore a costruire un modello mentale del sistema, non elencare solo fatti e scenari :-)
ashirley

84
Questa è una risposta favolosa Credo che la documentazione Docker dovrebbe aggiungere questo sotto una sezione chiamata CMDvs ENTRYPOINT.
Tarik,

5
@Webman No. Sono due diverse istruzioni. Se entrambi esistono, CMD verrebbe trattato come parametro di ENTRYPOINT.
Light.G

628

Le ENTRYPOINTSpecifica un comando che sarà sempre eseguito quando il contenitore si avvia.

Gli CMDargomenti specifica che saranno alimentati al ENTRYPOINT.

Se si desidera creare un'immagine dedicata a un comando specifico che verrà utilizzato ENTRYPOINT ["/path/dedicated_command"]

Altrimenti, se si desidera creare un'immagine per scopi generali, è possibile lasciare ENTRYPOINTnon specificato e utilizzare CMD ["/path/dedicated_command"]poiché sarà possibile ignorare l'impostazione fornendo argomenti a docker run.

Ad esempio, se il Dockerfile è:

FROM debian:wheezy
ENTRYPOINT ["/bin/ping"]
CMD ["localhost"]

L'esecuzione dell'immagine senza alcun argomento eseguirà il ping dell'host locale:

$ docker run -it test
PING localhost (127.0.0.1): 48 data bytes
56 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.096 ms
56 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.088 ms
56 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.088 ms
^C--- localhost ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.088/0.091/0.096/0.000 ms

Ora, l'esecuzione dell'immagine con un argomento eseguirà il ping dell'argomento:

$ docker run -it test google.com
PING google.com (173.194.45.70): 48 data bytes
56 bytes from 173.194.45.70: icmp_seq=0 ttl=55 time=32.583 ms
56 bytes from 173.194.45.70: icmp_seq=2 ttl=55 time=30.327 ms
56 bytes from 173.194.45.70: icmp_seq=4 ttl=55 time=46.379 ms
^C--- google.com ping statistics ---
5 packets transmitted, 3 packets received, 40% packet loss
round-trip min/avg/max/stddev = 30.327/36.430/46.379/7.095 ms

Per fare un confronto, se il Dockerfile è:

FROM debian:wheezy
CMD ["/bin/ping", "localhost"]

L'esecuzione dell'immagine senza alcun argomento eseguirà il ping dell'host locale:

$ docker run -it test
PING localhost (127.0.0.1): 48 data bytes
56 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.076 ms
56 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.087 ms
56 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.090 ms
^C--- localhost ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.076/0.084/0.090/0.000 ms

Ma eseguendo l'immagine con un argomento verrà eseguito l'argomento:

docker run -it test bash
root@e8bb7249b843:/#

Vedi questo articolo di Brian DeHamer per ulteriori dettagli: https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/


219
The ENTRYPOINT specifies a command that will always be executed when the container starts. The CMD specifies arguments that will be fed to the ENTRYPOINT.è un buon riassunto puntuale.
Jingguo Yao,

1
ENTRYPOINT può anche essere sovrascritto usando il flag --entrypoint. per es. docker run -it --entrypoint bash test
seenimurugan

2
Mi piacciono i tuoi esempi, è davvero utile!
Chau Giang,

2
@Jingguo Yao: Cosa succede se CMD contiene un comando come - CMD ["nginx", "- g", "daemon", "off"]? Sarebbe incatenato?
KMC

@KMC CMD è l'argomento predefinito di ENTRYPOINT, lo sostituisci passando un nuovo argomento durante l'esecuzione dell'immagine.
MGP

237

Secondo i documenti docker ,

Entrambe le istruzioni CMD ed ENTRYPOINT definiscono quale comando viene eseguito quando si esegue un contenitore. Ci sono alcune regole che descrivono la loro cooperazione.

  1. Dockerfile deve specificare almeno uno CMDo ENTRYPOINTcomandi.
  2. ENTRYPOINT dovrebbe essere definito quando si utilizza il contenitore come eseguibile.
  3. CMDdovrebbe essere usato come un modo per definire argomenti predefiniti per un ENTRYPOINTcomando o per eseguire un comando ad-hoc in un contenitore.
  4. CMD verrà sovrascritto quando si esegue il contenitore con argomenti alternativi.

Le tabelle seguenti mostrano quale comando viene eseguito per differenti ENTRYPOINT/ CMDcombinazioni :

- No ENTRYPOINT

╔════════════════════════════╦═════════════════════════════╗
║ No CMD                     ║ error, not allowed          ║
╟────────────────────────────╫─────────────────────────────╢
║ CMD [“exec_cmd”, “p1_cmd”] ║ exec_cmd p1_cmd             ║
╟────────────────────────────╫─────────────────────────────╢
║ CMD [“p1_cmd”, “p2_cmd”]   ║ p1_cmd p2_cmd               ║
╟────────────────────────────╫─────────────────────────────╢
║ CMD exec_cmd p1_cmd        ║ /bin/sh -c exec_cmd p1_cmd  ║
╚════════════════════════════╩═════════════════════════════╝

- ENTRYPOINT exec_entry p1_entry

╔════════════════════════════╦══════════════════════════════════╗
║ No CMD                     ║ /bin/sh -c exec_entry p1_entry   ║
╟────────────────────────────╫──────────────────────────────────╢
║ CMD [“exec_cmd”, “p1_cmd”] ║ /bin/sh -c exec_entry p1_entry   ║
╟────────────────────────────╫──────────────────────────────────╢
║ CMD [“p1_cmd”, “p2_cmd”]   ║ /bin/sh -c exec_entry p1_entry   ║
╟────────────────────────────╫──────────────────────────────────╢
║ CMD exec_cmd p1_cmd        ║ /bin/sh -c exec_entry p1_entry   ║
╚════════════════════════════╩══════════════════════════════════╝

- ENTRYPOINT [“exec_entry”, “p1_entry”]

╔════════════════════════════╦═════════════════════════════════════════════════╗
║ No CMD                     ║ exec_entry p1_entry                             ║
╟────────────────────────────╫─────────────────────────────────────────────────╢
║ CMD [“exec_cmd”, “p1_cmd”] ║ exec_entry p1_entry exec_cmd p1_cmd             ║
╟────────────────────────────╫─────────────────────────────────────────────────╢
║ CMD [“p1_cmd”, “p2_cmd”]   ║ exec_entry p1_entry p1_cmd p2_cmd               ║
╟────────────────────────────╫─────────────────────────────────────────────────╢
║ CMD exec_cmd p1_cmd        ║ exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd  ║
╚════════════════════════════╩═════════════════════════════════════════════════╝

Cosa sono px_cmd e exec_entry? Cosa significa quando si trovano sulla stessa linea di esecuzione? Sono passati come argomento l'uno all'altro? Anche quando /bin/sh -cè coinvolto?
Danielo515,

1
@ Danielo515 Sia 'px_cmd' che 'exec_entry' sono solo stringhe fittizie qui. Potresti semplicemente notare che /bin/sh -cverrebbe aggiunto a CMD come prefisso mentre CMD è scritto nella sintassi eseguibile (non nella sintassi dell'elenco).
Light.G

1
@royki Se l'utente specifica gli argomenti da eseguire nella finestra mobile , sostituiranno l'impostazione predefinita specificata in CMD.
donrondadon,

2
ENTRYPOINT exec_entry p1_entè stato erroneamente spiegato. Il modulo shell impedisce l'utilizzo di qualsiasi argomento CMD o esecuzione degli argomenti della riga di comando - docs.docker.com/engine/reference/builder/#entrypoint
Mariusz Miesiak

1
@MariuszMiesiak è ora aggiornato. Grazie per il tuo feedback
Rafaf Tahsin,

170

Sì, questa è una buona domanda. Non lo capisco ancora del tutto, ma:

Capisco che ENTRYPOINTè il binario che viene eseguito. Puoi sostituire entrypoint con --entrypoint = "".

docker run -t -i --entrypoint="/bin/bash" ubuntu

CMD è l'argomento predefinito per il contenitore. Senza entrypoint, l'argomento predefinito è il comando che viene eseguito. Con entrypoint, cmd viene passato a entrypoint come argomento. È possibile emulare un comando con entrypoint.

# no entrypoint
docker run ubuntu /bin/cat /etc/passwd

# with entry point, emulating cat command
docker run --entrypoint="/bin/cat" ubuntu /etc/passwd

Quindi, il vantaggio principale è che con entrypoint puoi passare argomenti (cmd) al tuo contenitore. A tale scopo, è necessario utilizzare entrambi:

# Dockerfile
FROM ubuntu
ENTRYPOINT ["/bin/cat"]

e

docker build -t=cat .

allora puoi usare:

docker run cat /etc/passwd
#              ^^^^^^^^^^^
#                   CMD
#          ^^^      
#          image (tag)- using the default ENTRYPOINT

@Blauhirn Nel tuo caso, devi aggiungere argomenti a CMD nella sintassi dell'elenco e assicurarti che il punto di accesso che hai indicato potrebbe analizzare i tuoi argomenti in CMD. Di solito, aggiungo un argomento '-h' a entrypoint. Quindi posso eseguire docker run image_name -hper mostrare alcune informazioni di aiuto di questa immagine.
Light.G

1
Questa è la risposta più semplice e chiara.
Eric Wang,

44

Differenza tra CMD ed ENTRYPOINT per intuizione :

  • ENTRYPOINT: comando da eseguire all'avvio del contenitore.
  • CMD: comando da eseguire all'avvio del contenitore o argomenti su ENTRYPOINT se specificato.

Sì, si sta mescolando.

È possibile ignorare uno di essi quando si esegue la finestra mobile.

Differenza tra CMD ed ENTRYPOINT per esempio :

docker run -it --rm yourcontainer /bin/bash            <-- /bin/bash overrides CMD
                                                       <-- /bin/bash does not override ENTRYPOINT
docker run -it --rm --entrypoint ls yourcontainer      <-- overrides ENTRYPOINT with ls
docker run -it --rm --entrypoint ls yourcontainer  -la  <-- overrides ENTRYPOINT with ls and overrides CMD with -la

Maggiori informazioni sulla differenza tra CMDe ENTRYPOINT:

Argomenti docker runcome / bin / bash hanno la precedenza su qualsiasi comando CMD che abbiamo scritto in Dockerfile.

ENTRYPOINT non può essere ignorato in fase di esecuzione con comandi normali come docker run [args]. Alla argsfine di docker run [args]vengono forniti come argomenti a ENTRYPOINT. In questo modo possiamo creare un containerche è come un normale binario come ls.

Quindi CMD può agire come parametro predefinito su ENTRYPOINT e quindi possiamo sovrascrivere gli argomenti CMD da [args].

ENTRYPOINT può essere sostituito con --entrypoint.


38

In breve:

  • CMD imposta i comandi e / o i parametri predefiniti, che possono essere sovrascritti dalla riga di comando quando viene eseguito il contenitore docker.
  • Il comando ENTRYPOINT e i parametri non verranno sovrascritti dalla riga di comando. Invece, tutti gli argomenti della riga di comando verranno aggiunti dopo i parametri ENTRYPOINT.

Se hai bisogno di maggiori dettagli o vuoi vedere la differenza sull'esempio, c'è un post sul blog che confronta in modo completo CMD ed ENTRYPOINT con molti esempi - http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/


21

Aggiungerò la mia risposta come esempio 1 che potrebbe aiutarti a capire meglio la differenza.

Supponiamo di voler creare un'immagine che esegua sempre un comando di sospensione all'avvio. Creeremo la nostra immagine e specificheremo un nuovo comando:

FROM ubuntu
CMD sleep 10

Ora costruiamo l'immagine:

docker build -t custom_sleep .
docker run custom_sleep
# sleeps for 10 seconds and exits

E se volessimo cambiare il numero di secondi? Dovremmo cambiare Dockerfilecome il valore è hardcoded lì, o sovrascrivere il comando fornendone uno diverso:

docker run custom_sleep sleep 20

Mentre funziona, non è una buona soluzione, dato che abbiamo un comando "sleep" ridondante (lo scopo del contenitore è di dormire , quindi dover specificare esplicitamente il sleepcomando non è una buona pratica).

Ora proviamo a usare l' ENTRYPOINTistruzione:

FROM ubuntu
ENTRYPOINT sleep

Questa istruzione specifica il programma che verrà eseguito all'avvio del contenitore .

Ora possiamo eseguire:

docker run custom_sleep 20

Che dire di un valore predefinito? Bene, hai indovinato bene:

FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["10"]

Il ENTRYPOINTè il programma che verrà eseguito, e il valore passato al contenitore saranno allegati.

È ENTRYPOINTpossibile ignorare specificando un --entrypointflag, seguito dal nuovo punto di ingresso che si desidera utilizzare.

Non mio, una volta ho visto un tutorial che ha fornito questo esempio


1
Ecco un link al tutorial: youtu.be/OYbEWUbmk90 . Potrebbe essere utile per i futuri utenti.
ChiPlusPlus


7

Commenti sulla funzione EntryPoint nel codice

// ENTRYPOINT / usr / sbin / nginx.

// Imposta il punto di accesso (il cui valore predefinito è sh -c) su / usr / sbin / nginx.

// Accetterà il CMD come argomento per / usr / sbin / nginx.

Un altro riferimento dai documenti

È possibile utilizzare il modulo exec di ENTRYPOINT per impostare comandi e argomenti predefiniti abbastanza stabili e quindi utilizzare CMD per impostare valori predefiniti aggiuntivi che hanno maggiori probabilità di essere modificati.

Esempio:

FROM ubuntu:14.04.3
ENTRYPOINT ["/bin/ping"]
CMD ["localhost", "-c", "2"]

Build : sudo docker build -t ent_cmd.

CMD arguments are easy to override.

NO argument (sudo docker -it ent_cmd)                :  ping localhost 
argument    (sudo docker run -it ent_cmd google.com) :  ping google.com

.

To override EntryPoint argument, you need to supply entrypoint
sudo docker run -it --entrypoint="/bin/bash" ent_cmdd

ps: in presenza di EntryPoint, CMD conterrà argomenti da alimentare a EntryPoint. In assenza di EntryPoint, CMD sarà il comando che verrà eseguito.


3

CMDcomando menzionato all'interno del Dockerfilefile può essere sovrascritto tramite docker runcomando mentre ENTRYPOINTnon può essere.


4
docker run --helpil comando dice diversamente:--entrypoint string Overwrite the default ENTRYPOINT of the image
iomv

3

Ho letto tutte le risposte e voglio riassumere per una migliore comprensione a prima vista come segue:

Innanzitutto, l'intero comando che viene eseguito nel contenitore comprende due parti: il comando e gli argomenti

  • ENTRYPOINT definisce l'eseguibile richiamato all'avvio del contenitore (per comando)

  • CMD specifica gli argomenti che vengono passati a ENTRYPOINT (per argomenti)

Nel libro Kubernetes In Action indica una nota importante al riguardo. (capitolo 7)

Sebbene sia possibile utilizzare l' istruzione CMD per specificare il comando che si desidera eseguire quando l'immagine viene eseguita, il modo corretto è farlo tramite l' istruzione ENTRYPOINT e specificare la CMD solo se si desidera definire gli argomenti predefiniti.

Puoi anche leggere questo articolo per una grande spiegazione in modo semplice


2

CMD:

  • CMD ["executable","param1","param2"]: ["executable","param1","param2"]è il primo processo.
  • CMD command param1 param2: /bin/sh -c CMD command param1 param2è il primo processo. CMD command param1 param2viene biforcuta dal primo processo.
  • CMD ["param1","param2"]: Questo modulo viene utilizzato per fornire argomenti predefiniti per ENTRYPOINT.

ENTRYPOINT (il seguente elenco non considera il caso in cui CMD ed ENTRYPOINT sono usati insieme):

  • ENTRYPOINT ["executable", "param1", "param2"]: ["executable", "param1", "param2"]è il primo processo.
  • ENTRYPOINT command param1 param2: /bin/sh -c command param1 param2è il primo processo. command param1 param2viene biforcuta dal primo processo.

Come diceva Creack , CMD è stato sviluppato per primo. Quindi ENTRYPOINT è stato sviluppato per una maggiore personalizzazione. Dal momento che non sono progettati insieme, ci sono alcune sovrapposizioni di funzionalità tra CMD ed ENTRYPOINT, che spesso confondono le persone.


2

Molte persone lo spiegano perfettamente qui, quindi non ripeterò tutte le risposte. Ma per avere una buona sensazione suggerirei di testarlo tu stesso guardando i processi nel contenitore.

Crea un piccolo Dockerfile del modulo:

FROM ubuntu:latest
CMD /bin/bash

Costruiscilo, eseguilo con docker run -it theimageed eseguilo ps -eo ppid,pid,argsnel contenitore. Confronta questo output con quello che ricevi da ps quando usi:

  • docker run -it theimage bash
  • Ricostruire l'immagine ma con ENTRYPOINT /bin/bashed eseguirla in entrambi i modi
  • utilizzando CMD ["/bin/bash"]
  • ...

In questo modo vedrai facilmente le differenze tra tutti i possibili metodi per te stesso.


0

La documentazione ufficiale delle migliori pratiche Dockerfile fa un ottimo lavoro spiegando le differenze. Best practice per Dockerfile

CMD:

Le istruzioni CMD devono essere utilizzate per eseguire il software contenuto nell'immagine, insieme a qualsiasi argomento. CMD dovrebbe quasi sempre essere utilizzato sotto forma di CMD ["executable", "param1", "param2"…]. Pertanto, se l'immagine è per un servizio, come Apache e Rails, eseguiresti qualcosa di simileCMD ["apache2","-DFOREGROUND"] . In effetti, questa forma di istruzione è consigliata per qualsiasi immagine basata sul servizio.

PUNTO D'ENTRATA:

Il miglior uso di ENTRYPOINT è impostare il comando principale dell'immagine, permettendo a quell'immagine di essere eseguita come se fosse quel comando (e quindi usare CMD come flag predefiniti).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.