Apa perbedaan antara "mengekspos" dan "mempublikasikan" di Docker?

517

Saya bereksperimen dengan Dockerfiles, dan saya pikir saya mengerti sebagian besar logika. Namun, saya tidak melihat perbedaan antara "mengekspos" dan "menerbitkan" port dalam konteks ini.

Semua tutorial yang telah saya lihat pertama-tama termasuk EXPOSEperintah di Dockerfile:

...
EXPOSE 8080
...

Mereka kemudian membangun gambar dari Dockerfile ini:

$ docker build -t an_image - < Dockerfile

Dan kemudian terbitkan port yang sama seperti di atas saat menjalankan gambar:

$ docker run -d -p 8080 an_image

atau terbitkan semua port menggunakan

$ docker run -d -P an_image

Apa gunanya mengekspos port di Dockerfile, jika tetap akan dipublikasikan? Apakah akan ada kebutuhan untuk mengekspos port terlebih dahulu, dan tidak mempublikasikannya nanti? Secara efektif, saya ingin menentukan semua port yang akan saya gunakan di Dockerfile saat membuat gambar, dan kemudian tidak repot dengan mereka lagi, menjalankannya hanya dengan:

$ docker run -d an_image

Apakah ini mungkin?

pengguna1496984
sumber

Jawaban:

732

Pada dasarnya, Anda memiliki tiga opsi:

  1. Tidak menentukan EXPOSEatau-p
  2. Hanya sebutkan EXPOSE
  3. Tentukan EXPOSEdan-p

1) Jika Anda menentukan baik EXPOSEatau -p, layanan dalam wadah hanya akan dapat diakses dari dalam wadah itu sendiri.

2) Jika Anda EXPOSEport, layanan dalam wadah tidak dapat diakses dari luar Docker, tetapi dari dalam wadah Docker lainnya. Jadi ini bagus untuk komunikasi antar wadah.

3) Jika Anda EXPOSEdan -pport, layanan dalam wadah dapat diakses dari mana saja, bahkan di luar Docker.

Alasan mengapa keduanya terpisah adalah IMHO karena:

  • memilih port host tergantung pada host dan karenanya bukan milik Dockerfile (selain itu akan tergantung pada host),
  • dan seringkali itu cukup jika layanan dalam wadah dapat diakses dari wadah lain.

The dokumentasi secara eksplisit menyatakan:

The EXPOSEinstruksi mengekspos port untuk digunakan dalam link.

Ini juga mengarahkan Anda ke cara menautkan wadah , yang pada dasarnya adalah komunikasi antar-wadah yang saya bicarakan.

PS: Jika ya -p, tetapi tidak EXPOSE, Docker melakukan implisit EXPOSE. Ini karena jika port terbuka untuk umum, maka secara otomatis juga terbuka untuk kontainer Docker lainnya. Karena itu -ptermasuk EXPOSE. Itu sebabnya saya tidak menyebutkannya di atas sebagai kasus keempat.

Golo Roden
sumber
57
Saya pikir Anda tidak benar dengan EXPOSE. Dari wadah lain, Anda dapat mengakses semua port kontainer tanpa memaparkannya. Saya mencobanya. Tangkapan di sini adalah bahwa alamat IP kontainer tidak dapat diprediksi. Saya percaya bahwa tautan digunakan untuk menentukan wadah mana yang ingin Anda hubungkan (sehingga Anda menautkan ke wadah IP tertentu), bukan untuk mengaktifkan koneksi.
Jiri
7
"Jika Anda tidak menentukan salah satu dari mereka", akan berguna jika Anda menjelaskan bahwa dengan "orang-orang" yang Anda maksud EXPOSEdan -pdan bukan tiga poin-poin precedented. Membuat saya sedikit bingung.
Pithikos
4
Untuk sepenuhnya lengkap, jawaban ini juga harus membahas kemungkinan kasus keempat: Anda tidak menentukan EXPOSE, tapi Anda tidak menentukan -p. Ini pemahaman saya bahwa jika Anda selalu menggunakan -pdan menjalankan masing-masing wadah maka EXPOSEtidak masalah untuk dihilangkan, tetapi itu menjadi berguna / perlu saat menggunakan -Patau --link. (Dan karena Anda tidak tahu bagaimana orang lain akan menggunakan gambar Anda, EXPOSEharus ditentukan dalam gambar publik apa pun.)
GrandOpener
6
Dokumen tidak lagi menyatakan "Instruksi EXPOSE memperlihatkan port untuk digunakan di dalam tautan".
Lorin Hochstein
11
Turunkan suara karena ini secara substansial salah. Expose pada dasarnya adalah dokumentasi, dan tidak menggunakannya tidak membatasi akses. Ini adalah bahaya kesalahpahaman jika ada yang bergantung padanya untuk membatasi akses.
mc0e
167

Jawaban singkat:

  • EXPOSEadalah cara mendokumentasikan
  • --publish(atau -p) adalah cara pemetaan sebuah port host untuk menjalankan pelabuhan kontainer

Perhatikan di bawah ini:

  • EXPOSEterkait dengan Dockerfiles( mendokumentasikan )
  • --publishterkait dengan docker run ...( eksekusi / run-time )

Mengekspos dan menerbitkan porta

Di jaringan Docker, ada dua mekanisme berbeda yang secara langsung melibatkan port jaringan: mengekspos dan menerbitkan port. Ini berlaku untuk jaringan jembatan default dan jaringan jembatan yang ditentukan pengguna.

  • Anda mengekspos port menggunakan EXPOSEkata kunci di Dockerfile atau --exposeflag to docker run. Mengekspos port adalah cara mendokumentasikan port mana yang digunakan, tetapi sebenarnya tidak memetakan atau membuka port apa pun . Mengekspos port adalah opsional.

  • Anda menerbitkan port menggunakan tanda --publishatau --publish-alluntuk docker run. Ini memberi tahu Docker port mana yang akan dibuka pada antarmuka jaringan wadah. Ketika port diterbitkan, port tersebut dipetakan ke port orde tinggi yang tersedia (lebih tinggi dari 30000) pada mesin host, kecuali jika Anda menentukan port untuk dipetakan ke pada mesin host saat runtime. Anda tidak dapat menentukan port untuk memetakan pada mesin host ketika Anda membangun gambar (di Dockerfile), karena tidak ada cara untuk menjamin bahwa port akan tersedia pada mesin host di mana Anda menjalankan gambar .

dari: Jaringan kontainer Docker

Pembaruan Oktober 2019 : teks di atas tidak lagi ada dalam dokumen tetapi versi yang diarsipkan ada di sini: docs.docker.com/v17.09/engine/userguide/networking/#exposing-and-publishing-ports

Mungkin dokumentasi saat ini adalah di bawah ini:

Port yang dipublikasikan

Secara default, ketika Anda membuat sebuah wadah, itu tidak mempublikasikan port-portnya ke dunia luar. Untuk membuat port tersedia untuk layanan di luar Docker, atau ke wadah Docker yang tidak terhubung ke jaringan kontainer, gunakan bendera --publishatau -p. Ini menciptakan aturan firewall yang memetakan port kontainer ke port pada host Docker.

dan dapat ditemukan di sini: docs.docker.com/config/containers/container-networking/#published-ports

Juga,

MEMBUKA

... EXPOSEInstruksi sebenarnya tidak mempublikasikan port . Fungsinya sebagai jenis dokumentasi antara orang yang membuat gambar dan orang yang menjalankan wadah, tentang port mana yang akan diterbitkan.

dari: referensi Dockerfile






Akses layanan ketika EXPOSE/ --publishtidak didefinisikan:

Pada jawaban @Golo Roden dinyatakan bahwa ::

"Jika Anda tidak menentukan salah satu dari itu, layanan dalam wadah tidak akan dapat diakses dari mana pun kecuali dari dalam wadah itu sendiri."

Mungkin itu yang terjadi pada saat jawabannya sedang ditulis, tetapi sekarang tampaknya bahkan jika Anda tidak menggunakan EXPOSEatau --publish, jaringan hostlain dan containersyang sama akan dapat mengakses layanan Anda dapat mulai di dalam wadah itu.

Cara menguji ini:

Saya telah menggunakan yang berikut ini Dockerfile. Pada dasarnya, saya mulai dengan ubuntu dan menginstal server web kecil:

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

Saya buildgambar sebagai "testexpose" dan runwadah baru dengan:

docker run --rm -it testexpose bash

Di dalam wadah, saya meluncurkan beberapa contoh mini-httpd:

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

Saya kemudian dapat menggunakan curldari host atau wadah lain untuk mengambil halaman beranda mini-httpd.

tgogo
sumber
16
ini sekarang jawaban yang benar. jawaban yang diterima didasarkan pada versi sebelumnya, tampaknya.
Luke W
apa port host yang Anda gunakan untuk curl?
badai otak
Saya menggunakan IP kontainer (seperti 172.17.0.2) dan semua port yang saya sebutkan. Jika Anda menggunakan Docker untuk Mac / Windows, jaringannya berbeda. Tidak ada docker0jembatan.
tgogos
saat menerbitkan semua port EXPOSEd dengan flag "-P", bagaimana saya bisa tahu port apa yang digunakan pada host ??
sixty4bit
1
@ sixty4bit lihat pertanyaan ini: Bagaimana cara mengetahui port acak yang dipilih Docker? .
tgogos
9

Lihat referensi dokumentasi resmi: https://docs.docker.com/engine/reference/builder/#expose

The EXPOSEmemungkinkan Anda untuk menentukan swasta (container) dan publik (host) port untuk mengekspos pada gambar waktu membangun ketika wadah berjalan jika Anda menjalankan wadah dengan -P.

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

Port publik dan protokol bersifat opsional, jika bukan port publik yang ditentukan, port acak akan dipilih pada host oleh buruh pelabuhan untuk mengekspos pelabuhan kontainer yang ditentukan pada Dockerfile.

Praktik yang baik adalah jangan menentukan port publik, karena membatasi hanya satu kontainer per host (kontainer kedua akan membuang port yang sudah digunakan).

Anda dapat menggunakan -pdi docker runmengontrol apa pelabuhan umum pelabuhan kontainer terkena akan dihubungkan.

Bagaimanapun, Jika Anda tidak menggunakan EXPOSE(dengan -Pon docker run) juga -p, tidak ada port yang akan terbuka.

Jika Anda selalu menggunakan -ppada docker runAnda tidak perlu EXPOSEtetapi jika Anda menggunakan EXPOSEAnda docker runperintah mungkin lebih sederhana, EXPOSEdapat berguna jika Anda tidak peduli apa pelabuhan akan mengekspos pada host, atau jika Anda yakin hanya satu kontainer akan dimuat.

ton
sumber
ini benar. Ketika Anda memiliki EXPOSE portNumber di Dockerfile, ingatlah untuk memanggil docker yang dijalankan dengan -P.
KunYu Tsai
6

Anda mengekspos port menggunakan kata kunci EXPOSE di Dockerfile atau flag --expose ke run docker. Mengekspos port adalah cara mendokumentasikan port mana yang digunakan, tetapi sebenarnya tidak memetakan atau membuka port apa pun. Mengekspos port adalah opsional.

Sumber: github commit

mzalazar
sumber
3

Kebanyakan orang menggunakan buruh pelabuhan menulis dengan jaringan. The dokumentasi menyatakan:

Fitur jaringan Docker mendukung pembuatan jaringan tanpa perlu membuka port di dalam jaringan, untuk informasi terperinci lihat gambaran umum fitur ini).

Yang berarti bahwa jika Anda menggunakan jaringan untuk komunikasi antar wadah, Anda tidak perlu khawatir untuk mengekspos port.

dia
sumber
-5

EXPOSE digunakan untuk memetakan port container port lokal yaitu: jika Anda menentukan expose dalam file docker like

EXPOSE 8090

Apa yang akan dilakukan itu akan memetakan localhost port 8090 ke container port 8090

Mansur Ali
sumber