Jaka jest różnica między „ujawnianiem” a „publikowaniem” w Dockerze?

517

Eksperymentuję z plikami Docker i myślę, że rozumiem większość logiki. Jednak w tym kontekście nie widzę różnicy między „ujawnianiem” a „publikowaniem” portu.

Wszystkie samouczki, które widziałem najpierw, zawierają EXPOSEpolecenie w Dockerfile:

...
EXPOSE 8080
...

Następnie budują obraz z tego pliku Docker:

$ docker build -t an_image - < Dockerfile

A następnie opublikuj ten sam port co powyżej podczas uruchamiania obrazu:

$ docker run -d -p 8080 an_image

lub opublikuj wszystkie porty za pomocą

$ docker run -d -P an_image

Po co ujawniać port w Dockerfile, jeśli i tak zostanie opublikowany? Czy kiedykolwiek będzie trzeba najpierw ujawnić port, a nie opublikować go później? W efekcie chciałbym określić wszystkie porty, które będą używane w Dockerfile podczas tworzenia obrazu, a następnie nie zawracać sobie nimi głowy, uruchamiając je po prostu z:

$ docker run -d an_image

czy to możliwe?

użytkownik1496984
źródło

Odpowiedzi:

731

Zasadniczo masz trzy opcje:

  1. Nie określaj EXPOSEani-p
  2. Podaj tylko EXPOSE
  3. Określ EXPOSEi-p

1) Jeżeli nie można określić EXPOSEani -pusługa w pojemniku będzie dostępna tylko od wewnątrz samego pojemnika.

2) W EXPOSEprzypadku portu usługa w kontenerze nie jest dostępna z zewnątrz Dockera, ale z wnętrza innych kontenerów Docker. Jest to dobre w przypadku komunikacji między kontenerami.

3) Jeśli Ty EXPOSEi -pport, usługa w kontenerze jest dostępna z dowolnego miejsca, nawet poza Docker.

Powodem, dla którego oba są rozdzielone, jest IMHO, ponieważ:

  • wybór portu hosta zależy od hosta, a zatem nie należy do pliku Docker (w przeciwnym razie zależałoby od hosta),
  • i często wystarczy, jeśli usługa w kontenerze jest dostępna z innych kontenerów.

Dokumentacja wyraźnie stwierdza:

EXPOSEInstrukcja naraża portów do wykorzystania w linki.

Wskazuje również, jak połączyć kontenery , co w zasadzie jest komunikacją między kontenerami, o której mówiłem.

PS: Jeśli to zrobisz -p, ale nie zrobisz EXPOSE, Docker robi to domyślnie EXPOSE. Wynika to z faktu, że jeśli port jest otwarty dla publiczności, jest on również automatycznie otwarty dla innych kontenerów Docker. Dlatego -pobejmuje EXPOSE. Dlatego nie wymieniłem tego powyżej jako czwartego przypadku.

Golo Roden
źródło
57
Myślę, że nie masz racji z EKSPOZYCJĄ. Z innych kontenerów można uzyskać dostęp do wszystkich portów kontenerów bez ich ujawniania. Próbowałem tego. Problem polega na tym, że adres IP kontenera jest nieprzewidywalny. Uważam, że link służy do określenia, z którym kontem chcesz się połączyć (więc łączysz się z konkretnym adresem IP kontenera), a nie do umożliwienia połączenia.
Jiri
7
„Jeśli nie podasz żadnej z tych”, byłoby przydatne, jeśli wyjaśnić, że z „tych” masz na myśli EXPOSEi -p, a nie trzy wypunktowania precedented. Trochę mnie to pogubiło.
Pithikos,
4
Aby być w pełni kompletny, to odpowiedź powinna również zająć czwartą ewentualny przypadek: nie określono EXPOSE, ale nie określił -p. Rozumiem, że jeśli zawsze używasz -pi uruchamiasz pojedyncze kontenery, możesz EXPOSEje pominąć, ale staje się ono użyteczne / konieczne przy użyciu -Plub --link. (A ponieważ nie wiesz, w jaki sposób inne osoby będą korzystać z Twojego obrazu, EXPOSEnależy to określić we wszystkich publicznych obrazach.)
GrandOpener,
6
Dokumenty nie mówią już „Instrukcja EXPOSE ujawnia porty do użycia w łączach”.
Lorin Hochstein
11
Oddaj głos, ponieważ jest to zasadniczo niepoprawne. Expose to w zasadzie dokumentacja, a nieużywanie go nie ogranicza dostępu. Jest to niebezpieczne nieporozumienie, jeśli ktoś polega na nim w celu ograniczenia dostępu.
mc0e
166

Krótka odpowiedź:

  • EXPOSEjest sposobem dokumentowania
  • --publish(a -p) jest sposobem odwzorowywania do portu hosta z systemem portu kontenera

Zauważ, że poniżej:

  • EXPOSEjest związany z Dockerfiles( dokumentowanie )
  • --publishjest związany docker run ...( wykonanie / czas działania )

Ujawnianie i publikowanie portów

W sieci Docker istnieją dwa różne mechanizmy, które bezpośrednio dotyczą portów sieciowych: ujawnianie i publikowanie portów. Dotyczy to domyślnej sieci mostów i sieci mostów zdefiniowanych przez użytkownika.

  • EXPOSEUdostępniasz porty za pomocą słowa kluczowego w pliku Docker lub --exposeflagi do uruchomienia dokera . Ujawnianie portów to sposób na udokumentowanie używanych portów, ale w rzeczywistości nie mapuje ani nie otwiera żadnych portów . Udostępnianie portów jest opcjonalne.

  • Porty publikujesz za pomocą flagi --publishlub --publish-alldo docker run. To informuje Dockera, które porty należy otworzyć w interfejsie sieciowym kontenera. Kiedy port jest publikowany, jest mapowany na dostępny port wyższego rzędu (wyższy niż 30000) na maszynie hosta, chyba że określisz port do mapowania na maszynie hosta w czasie wykonywania. Nie można określić portu do mapowania na komputerze hosta podczas tworzenia obrazu (w pliku Docker), ponieważ nie ma sposobu, aby zagwarantować, że port będzie dostępny na komputerze hosta, na którym uruchomiono obraz .

from: Docker networking networking

Aktualizacja z października 2019 r . : powyższego tekstu nie ma już w dokumentach, ale dostępna jest jego zarchiwizowana wersja: docs.docker.com/v17.09/engine/userguide/networking/#exposing-and-publishing-ports

Być może aktualna dokumentacja jest następująca:

Opublikowane porty

Domyślnie podczas tworzenia kontenera nie publikuje on żadnych swoich portów w świecie zewnętrznym. Aby udostępnić port usługom poza Docker lub kontenerom Docker, które nie są podłączone do sieci kontenera, użyj flagi --publishlub -p. Spowoduje to utworzenie reguły zapory, która mapuje port kontenera na port na hoście Docker.

i można je znaleźć tutaj: docs.docker.com/config/containers/container-networking/#published-ports

Również,

EXPOSE

... EXPOSEInstrukcja faktycznie nie publikuje portu . Działa jako rodzaj dokumentacji między osobą, która buduje obraz, a osobą, która zarządza kontenerem, o których portach ma zostać opublikowana.

from: Odwołanie do pliku Dockerfile






Dostęp do usługi, gdy EXPOSE/ --publishnie są zdefiniowane:

W odpowiedzi @Golo Roden stwierdzono, że:

„Jeśli nie określisz żadnego z nich, usługa w kontenerze będzie niedostępna z dowolnego miejsca, z wyjątkiem samego kontenera”.

Być może tak było w czasie, gdy pisano odpowiedź, ale teraz wydaje się, że nawet jeśli nie używasz EXPOSElub --publish, hosti inne containersz tej samej sieci będą mogły uzyskać dostęp do usługi, którą możesz uruchomić w tym kontenerze.

Jak to przetestować:

Użyłem następujących Dockerfile. Zasadniczo, zaczynam od Ubuntu i instaluję mały serwer WWW:

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

I buildobraz jako „testexpose” i runnowy pojemnik z:

docker run --rm -it testexpose bash

Wewnątrz kontenera uruchamiam kilka przypadków mini-httpd:

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

Jestem w stanie użyć curlz hosta lub innych kontenerów, aby pobrać stronę główną mini-httpd.

tgogos
źródło
16
to jest teraz poprawna odpowiedź. wydaje się, że zaakceptowana odpowiedź opiera się na wcześniejszych wersjach.
Luke W
jakiego portu hosta użyłeś do zwijania?
burza mózgów
Użyłem adresu IP kontenera (coś podobnego 172.17.0.2) i wszystkich portów, o których mówię. Jeśli korzystasz z Docker na Maca / Windows, sieć jest inna. Nie ma docker0mostu.
tgogos
kiedy publikuję wszystkie porty EXPOSEd z flagą „-P”, jak mogę ustalić, który port jest używany na hoście?
sixty4bit
1
@ sixty4bit spójrz na to pytanie: Jak sprawdzić, który losowy port wybrał Docker? .
tgogos
9

Zobacz oficjalne odniesienie do dokumentacji: https://docs.docker.com/engine/reference/builder/#expose

EXPOSEUmożliwiają zdefiniowanie prywatnej (pojemnik) oraz publiczne porty (Host), aby odsłonić obraz w czasie kompilacji, gdy pojemnik jest uruchomiony , jeśli uruchomisz pojemnik -P.

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

Port publiczny i protokół są opcjonalne, jeśli nie określono portu publicznego, port losowy zostanie wybrany na hoście przez dokera, aby odsłonić określony port kontenera na Dockerfile.

Dobrą praktyką nie jest określanie portu publicznego, ponieważ ogranicza on tylko jeden kontener na host (drugi kontener wyrzuci port już używany).

Możesz użyć -pw docker runcelu kontrolowania, który port publiczny będą dostępne dla odsłoniętych portów kontenerów.

W każdym razie, jeśli nie użyjesz EXPOSE(z -Puruchomionym dokerem) ani -pżadne porty nie zostaną ujawnione.

Jeśli zawsze używać -pco docker runnie trzeba EXPOSE, ale jeśli użyć EXPOSETwojego docker runpolecenia może być bardziej proste, EXPOSEmoże być przydatna, jeśli nie obchodzi, co port będzie wystawiać na gospodarza, lub jeśli jesteś pewny tylko jednego pojemnika zostanie załadowany.

tona
źródło
to jest poprawne. Gdy masz EXPOSE portNumber w Dockerfile, pamiętaj, aby wywołać uruchamiane okno dokowane z -P.
KunYu Tsai
6

Ujawniasz porty za pomocą słowa kluczowego EXPOSE w pliku Docker lub flagi --expose, aby uruchomić okno dokowane. Ujawnianie portów to sposób na udokumentowanie, które porty są używane, ale w rzeczywistości nie mapują ani nie otwierają żadnych portów. Udostępnianie portów jest opcjonalne.

Źródło: github commit

mzalazar
źródło
3

Większość ludzi korzysta z dokera komponującego w sieci. W dokumentacji czytamy:

Funkcja sieci Docker obsługuje tworzenie sieci bez potrzeby ujawniania portów w sieci, szczegółowe informacje można znaleźć w omówieniu tej funkcji).

Co oznacza, że ​​jeśli używasz sieci do komunikacji między kontenerami, nie musisz się martwić o ujawnienie portów.

herm
źródło
-5

EKSPOZYCJA służy do mapowania portu kontenera portu lokalnego, tj .: jeśli określisz ekspozycję w pliku dokera, takim jak

EXPOSE 8090

Co to zrobi, mapuje port 8090 hosta lokalnego na port kontenera 8090

Mansur Ali
źródło