Qual è la differenza tra "esporre" e "pubblicare" in Docker?


517

Sto sperimentando Dockerfiles e penso di aver compreso la maggior parte della logica. Tuttavia, non vedo la differenza tra "esporre" e "pubblicare" una porta in questo contesto.

Tutti i tutorial che ho visto per primi includono il EXPOSEcomando nel Dockerfile:

...
EXPOSE 8080
...

Quindi creano un'immagine da questo Dockerfile:

$ docker build -t an_image - < Dockerfile

E quindi pubblica la stessa porta di cui sopra quando esegui l'immagine:

$ docker run -d -p 8080 an_image

o pubblica tutte le porte usando

$ docker run -d -P an_image

Qual è il punto di esporre una porta nel Dockerfile, se sarà comunque pubblicata? Sarebbe mai necessario esporre prima una porta e non pubblicarla in seguito? In effetti, vorrei specificare tutte le porte che userò nel Dockerfile durante la creazione dell'immagine, e quindi non preoccuparmi di nuovo, eseguendole semplicemente con:

$ docker run -d an_image

È possibile?

Risposte:


733

Fondamentalmente, hai tre opzioni:

  1. Né specificare EXPOSE-p
  2. Specificare solo EXPOSE
  3. Specificare EXPOSEe-p

1) Se si specifica né EXPOSE-p, il servizio nel contenitore sarà solo accessibile dal all'interno del contenitore stesso.

2) Se si è EXPOSEun porto, il servizio nel contenitore non è accessibile dall'esterno Docker, ma dall'interno di altri contenitori Docker. Quindi questo è buono per la comunicazione tra container.

3) Se tu EXPOSEe -puna porta, il servizio nel container è accessibile da qualsiasi luogo, anche al di fuori di Docker.

Il motivo per cui entrambi sono separati è IMHO perché:

  • la scelta di una porta host dipende dall'host e quindi non appartiene al Dockerfile (altrimenti dipende dall'host),
  • e spesso è sufficiente che un servizio in un contenitore sia accessibile da altri contenitori.

La documentazione afferma esplicitamente:

L' EXPOSEistruzione espone le porte per l'uso all'interno dei collegamenti.

Ti indica anche come collegare i container , che in sostanza è la comunicazione tra container di cui ho parlato.

PS: Se lo fai -p, ma non lo fai EXPOSE, Docker fa un implicito EXPOSE. Questo perché se una porta è aperta al pubblico, viene automaticamente aperta anche ad altri contenitori Docker. Quindi -pinclude EXPOSE. Ecco perché non l'ho elencato sopra come quarto caso.


57
Penso che non sia corretto con EXPOSE. Da altri contenitori, è possibile accedere a tutte le porte del contenitore senza esporle. Ci ho provato. Il problema qui è che l'indirizzo IP del contenitore è imprevedibile. Credo che quel collegamento sia usato per specificare quale contenitore si desidera connettere (quindi si collega a un IP contenitore specifico), non per abilitare la connessione.
Jiri

7
"Se non si specifica una di queste", sarebbe utile se si ha chiarito che con "quelli" Vuoi dire EXPOSEe -pnon i tre punti elenco precedented. Mi ha confuso un po 'lì.
Pithikos,

4
Per essere pienamente completo, questa risposta dovrebbe anche affrontare una quarta possibile caso: non è stata specificata EXPOSE, ma si ha specificato -p. Comprendo che se si utilizzano -ped eseguono sempre singoli contenitori, EXPOSEva bene omettere, ma diventa utile / necessario quando si utilizza -Po --link. (E poiché non sai come altre persone useranno la tua immagine, EXPOSEdovrebbe essere specificato in qualsiasi immagine pubblica.)
GrandOpener

6
I documenti non dichiarano più "L'istruzione EXPOSE espone le porte per l'uso all'interno dei collegamenti".
Lorin Hochstein,

11
Downvote perché questo è sostanzialmente errato. Expose è sostanzialmente una documentazione e il suo mancato utilizzo non limita l'accesso. Questo è un malinteso pericoloso se qualcuno fa affidamento su di esso per limitare l'accesso.
MC0e

167

Risposta breve:

  • EXPOSEè un modo di documentare
  • --publish(o -p) è un modo per mappare una porta host su una porta container in esecuzione

Si noti di seguito che:

  • EXPOSEè correlato a Dockerfiles( documentazione )
  • --publishè correlato a docker run ...( esecuzione / runtime )

Esporre e pubblicare i porti

Nella rete Docker esistono due diversi meccanismi che coinvolgono direttamente le porte di rete: esporre e pubblicare le porte. Ciò si applica alla rete bridge predefinita e alle reti bridge definite dall'utente.

  • EXPOSEEsporre le porte utilizzando la parola chiave nel Dockerfile o il --exposeflag per l'esecuzione della finestra mobile. L'esposizione delle porte è un modo per documentare quali porte vengono utilizzate, ma in realtà non mappa né apre alcuna porta . L'esposizione delle porte è facoltativa.

  • Pubblica le porte usando il flag --publisho --publish-allsu docker run. Questo indica a Docker quali porte aprire sull'interfaccia di rete del contenitore. Quando viene pubblicata, una porta viene mappata su una porta di ordine superiore disponibile (superiore a 30000) sul computer host, a meno che non si specifichi la porta su cui eseguire il mapping sul computer host in fase di esecuzione. Non è possibile specificare la porta su cui eseguire il mapping sul computer host quando si crea l'immagine (nel Dockerfile), poiché non è possibile garantire che la porta sia disponibile sul computer host in cui si esegue l'immagine .

da: Docker container networking

Aggiornamento ottobre 2019 : il testo sopra riportato non è più nei documenti ma una versione archiviata è qui: docs.docker.com/v17.09/engine/userguide/networking/#exposing-and-publishing-ports

Forse la documentazione attuale è la seguente:

Porti pubblicati

Per impostazione predefinita, quando si crea un contenitore, non pubblica nessuna delle sue porte nel mondo esterno. Per rendere disponibile una porta per servizi esterni a Docker o per contenitori Docker che non sono collegati alla rete del contenitore, utilizzare il flag --publisho -p. Questo crea una regola firewall che mappa una porta del contenitore su una porta sull'host Docker.

e può essere trovato qui: docs.docker.com/config/containers/container-networking/#published-ports

Anche,

ESPORRE

... L' EXPOSEistruzione in realtà non pubblica la porta . Funziona come un tipo di documentazione tra la persona che crea l'immagine e la persona che gestisce il contenitore, su quali porte sono destinate a essere pubblicate.

da: riferimento Dockerfile






Accesso al servizio quando EXPOSE/ --publishnon sono definiti:

Alla risposta di @Golo Roden si afferma che:

"Se non si specifica nessuno di questi, il servizio nel contenitore non sarà accessibile da nessuna parte se non dall'interno del contenitore stesso."

Forse era il caso al momento in cui veniva scritta la risposta, ma ora sembra che anche se non lo usi EXPOSE o --publish, hoste l'altra containersdella stessa rete sarà in grado di accedere a un servizio, è possibile iniziare all'interno di quel contenitore.

Come testarlo:

Ho usato il seguente Dockerfile. Fondamentalmente, inizio con Ubuntu e installo un piccolo web-server:

FROM ubuntu
RUN apt-get update && apt-get install -y mini-httpd

Ho buildl'immagine come "testexpose" e runun nuovo contenitore con:

docker run --rm -it testexpose bash

All'interno del contenitore, lancio alcune istanze di mini-httpd:

root@fb8f7dd1322d:/# mini_httpd -p 80
root@fb8f7dd1322d:/# mini_httpd -p 8080
root@fb8f7dd1322d:/# mini_httpd -p 8090

Sono quindi in grado di utilizzare curldall'host o altri contenitori per recuperare la home page di mini-httpd.


16
questa è ora la risposta corretta. la risposta accettata si basa su versioni precedenti, a quanto pare.
Luke W,

qual è la porta host che hai usato per l'arricciatura?
tempesta di cervello il

Ho usato l'IP del contenitore (qualcosa del genere 172.17.0.2) e tutte le porte che sto citando. Se si utilizza Docker per Mac / Windows, la rete è diversa. Non c'è un docker0ponte.
tgogos,

durante la pubblicazione di tutte le porte EXPOSEd con flag "-P", come posso sapere quale porta viene utilizzata sull'host ??
sixty4bit

1
@ sixty4bit dai un'occhiata a questa domanda: come faccio a sapere quale porta casuale Docker ha scelto? .
tgogos,

9

Vedere la documentazione di riferimento ufficiale: https://docs.docker.com/engine/reference/builder/#expose

La EXPOSEconsentono di definire privati (contenitore) e porti pubblici (host) per esporre al tempo di costruzione di immagine quando il contenitore è in esecuzione , se si esegue il contenitore con -P.

$ docker help run
...
  -P, --publish-all                    Publish all exposed ports to random ports
...

La porta pubblica e il protocollo sono opzionali, se non viene specificata una porta pubblica, verrà selezionata una porta casuale sull'host dalla finestra mobile per esporre la porta contenitore specificata su Dockerfile.

Una buona pratica è non specificare la porta pubblica, perché limita solo un contenitore per host (un secondo contenitore lancerà una porta già in uso).

È possibile utilizzare -pin docker runper controllare ciò che porta pubblica i porti container esposti saranno collegabili.

In ogni caso, se non si utilizza EXPOSE(con la -Pfinestra mobile in esecuzione) né -p, nessuna porta verrà esposta.

Se si usa sempre -pa docker runche non è necessario EXPOSE, ma se si utilizza EXPOSEil vostro docker runcomando può essere più semplice, EXPOSEpuò essere utile se non si cura di ciò che porta sarà esporre su host o se si è sicuri di solo contenitore verrà caricato.


questo è corretto. Quando si dispone di EXPOSE portNumber in Dockerfile, ricordare di richiamare la finestra mobile eseguita con -P.
KunYu Tsai,

6

Si espongono le porte utilizzando la parola chiave EXPOSE nel Dockerfile o il flag --expose per l'esecuzione della finestra mobile. L'esposizione delle porte è un modo per documentare quali porte vengono utilizzate, ma in realtà non mappa né apre alcuna porta. L'esposizione delle porte è facoltativa.

Fonte: commit github


3

La maggior parte delle persone usa la finestra mobile comporre con le reti. La documentazione afferma:

La funzione di rete Docker supporta la creazione di reti senza la necessità di esporre porte all'interno della rete, per informazioni dettagliate consultare la panoramica di questa funzione).

Ciò significa che se si utilizzano reti per la comunicazione tra container non è necessario preoccuparsi di esporre le porte.


-5

EXPOSE viene utilizzato per mappare la porta del contenitore della porta locale, ovvero: se si specifica esporre nel file docker come

EXPOSE 8090

Ciò che farà mapperà la porta 8090 di localhost alla porta 8090 del contenitore

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.