ความแตกต่างระหว่าง "เปิดเผย" และ "เผยแพร่" ใน Docker คืออะไร


517

ฉันกำลังทดลองกับ Dockerfiles และฉันคิดว่าฉันเข้าใจเหตุผลส่วนใหญ่ อย่างไรก็ตามฉันไม่เห็นความแตกต่างระหว่าง "การเปิดเผย" และ "การเผยแพร่" พอร์ตในบริบทนี้

บทเรียนทั้งหมดที่ฉันได้เห็นก่อนรวมถึงEXPOSEคำสั่งใน Dockerfile:

...
EXPOSE 8080
...

จากนั้นพวกเขาสร้างภาพจาก Dockerfile นี้:

$ docker build -t an_image - < Dockerfile

จากนั้นเผยแพร่พอร์ตเดียวกันกับด้านบนเมื่อเรียกใช้รูปภาพ:

$ docker run -d -p 8080 an_image

หรือเผยแพร่พอร์ตทั้งหมดโดยใช้

$ docker run -d -P an_image

จุดประสงค์ของการเปิดเผยพอร์ตใน Dockerfile คืออะไรถ้ามันจะถูกเผยแพร่ต่อไป เคยมีความจำเป็นต้องเปิดเผยพอร์ตก่อนหรือไม่และจะไม่เผยแพร่ในภายหลัง อย่างมีประสิทธิภาพฉันต้องการระบุพอร์ตทั้งหมดที่ฉันจะใช้ใน Dockerfile เมื่อสร้างภาพแล้วไม่ต้องยุ่งกับพวกเขาอีกครั้งโดยใช้พวกเขาเพียงแค่:

$ docker run -d an_image

เป็นไปได้ไหม

คำตอบ:


731

โดยทั่วไปคุณมีสามตัวเลือก:

  1. ไม่ระบุEXPOSEหรือ-p
  2. ระบุเท่านั้น EXPOSE
  3. ระบุEXPOSEและ-p

1) ถ้าคุณระบุค่าEXPOSEมิได้-pบริการในภาชนะที่เท่านั้นที่จะสามารถเข้าถึงได้จากภายในภาชนะของตัวเอง

2) ถ้าคุณEXPOSEเป็นพอร์ตบริการในคอนเทนเนอร์จะไม่สามารถเข้าถึงได้จากนักเทียบท่าภายนอก แต่จากด้านในคอนเทนเนอร์นักเทียบท่าอื่น ๆ ดังนั้นนี่เป็นสิ่งที่ดีสำหรับการสื่อสารระหว่างคอนเทนเนอร์

3) หากคุณEXPOSEและ-pพอร์ตการบริการในคอนเทนเนอร์สามารถเข้าถึงได้จากทุกที่แม้แต่นอก Docker

สาเหตุที่ทั้งสองแยกจากกันคือ IMHO เพราะ:

  • การเลือกพอร์ตโฮสต์ขึ้นอยู่กับโฮสต์และด้วยเหตุนี้จึงไม่ได้อยู่ใน Dockerfile (มิฉะนั้นจะขึ้นอยู่กับโฮสต์)
  • และบ่อยครั้งก็เพียงพอหากบริการในคอนเทนเนอร์สามารถเข้าถึงได้จากคอนเทนเนอร์อื่น

เอกสารอย่างชัดเจน:

EXPOSEคำแนะนำ exposes พอร์ตสำหรับการเชื่อมโยงการใช้งานภายใน

นอกจากนี้ยังชี้ให้คุณเห็นถึงวิธีเชื่อมโยงคอนเทนเนอร์ซึ่งโดยพื้นฐานแล้วเป็นการสื่อสารระหว่างคอนเทนเนอร์ที่ฉันพูดถึง

PS: ถ้าคุณทำ-pแต่ทำไม่ได้EXPOSE, EXPOSEหางไม่นัย นี่คือเนื่องจากถ้าพอร์ตเปิดให้สาธารณะมันจะเปิดโดยอัตโนมัติไปยังคอนเทนเนอร์นักเทียบท่าอื่น ๆ ดังนั้นรวม-p EXPOSEนั่นเป็นเหตุผลที่ฉันไม่ได้ระบุไว้ข้างต้นเป็นกรณีที่สี่


57
ฉันคิดว่าคุณไม่ถูกต้องกับ EXPOSE จากคอนเทนเนอร์อื่นคุณสามารถเข้าถึงพอร์ตคอนเทนเนอร์ทั้งหมดโดยไม่ต้องเปิดเผย ฉันลองมัน สิ่งที่จับที่นี่คือที่อยู่ IP ของคอนเทนเนอร์ไม่แน่นอน ฉันเชื่อว่าลิงก์จะใช้เพื่อระบุว่าคอนเทนเนอร์ใดที่คุณต้องการเชื่อมต่อ (เพื่อให้คุณเชื่อมโยงไปยัง IP คอนเทนเนอร์เฉพาะ) เพื่อไม่ให้เปิดใช้งานการเชื่อมต่อ
Jiri

7
"ถ้าคุณไม่ได้ระบุใด ๆ ของบรรดา" จะเป็นประโยชน์ถ้าคุณชี้แจงว่าด้วย "บรรดา" คุณหมายถึงEXPOSEและ-pและไม่สามจุด bullet precedented ทำให้ฉันสับสนเล็กน้อย
Pithikos

4
จะเสร็จสมบูรณ์อย่างเต็มที่คำตอบนี้ยังควรจะอยู่เป็นกรณีที่เป็นไปได้ที่สี่: คุณไม่ได้ระบุEXPOSEแต่คุณไม่-pระบุ มันเป็นความเข้าใจของฉันว่าถ้าคุณมักจะใช้-pและเรียกใช้ภาชนะบรรจุของแต่ละบุคคลแล้วEXPOSEจะปรับให้งด แต่มันจะกลายเป็นประโยชน์ / ความจำเป็นเมื่อใช้หรือ-P --link(และเนื่องจากคุณไม่รู้ว่าคนอื่นจะใช้รูปภาพของคุณอย่างไรEXPOSEจึงควรระบุในภาพสาธารณะใด ๆ )
GrandOpener

6
เอกสารไม่ได้ระบุไว้อีกต่อไป "คำสั่ง EXPOSE จะเปิดเผยพอร์ตสำหรับใช้ภายในลิงก์"
Lorin Hochstein

11
ลงคะแนนเพราะสิ่งนี้ไม่ถูกต้องอย่างมีนัยสำคัญ เปิดเผยเป็นเอกสารโดยทั่วไปและไม่ได้ใช้ไม่ จำกัด การเข้าถึง นี่คือความเข้าใจผิด harmos หากใครอาศัยเพื่อ จำกัด การเข้าถึง
mc0e

166

คำตอบสั้น ๆ :

  • EXPOSEเป็นวิธีการจัดทำเอกสาร
  • --publish(หรือ-p) เป็นวิธีการทำแผนที่พอร์ตของโฮสต์ที่จะวิ่งพอร์ตภาชนะ

แจ้งให้ทราบด้านล่างว่า:

  • EXPOSEเกี่ยวข้องกับDockerfiles( เอกสาร )
  • --publishเกี่ยวข้องกับdocker run ...( การกระทำ / เวลาทำงาน )

การเปิดเผยและเผยแพร่พอร์ต

ในระบบเครือข่ายนักเทียบท่ามีสองกลไกที่แตกต่างกันที่เกี่ยวข้องกับพอร์ตเครือข่ายโดยตรง: การเปิดเผยและการเผยแพร่พอร์ต สิ่งนี้ใช้กับเครือข่ายบริดจ์เริ่มต้นและเครือข่ายบริดจ์ที่ผู้ใช้กำหนด

  • คุณเปิดเผยพอร์ตโดยใช้EXPOSEคีย์เวิร์ดใน Dockerfile หรือแฟล็ก--exposeเพื่อเรียกใช้นักเทียบท่า เปิดเผยพอร์ตเป็นวิธีของการจัดเก็บเอกสารที่พอร์ตที่ใช้แต่ไม่ได้จริง map หรือเปิดพอร์ตใด การเปิดเผยพอร์ตเป็นตัวเลือก

  • คุณเผยแพร่พอร์ตใช้--publishหรือธง--publish-all docker runสิ่งนี้บอกนักเทียบท่าว่าจะเปิดพอร์ตใดบนอินเตอร์เฟซเครือข่ายของคอนเทนเนอร์ เมื่อพอร์ตถูกเผยแพร่พอร์ตนั้นจะถูกแมปกับพอร์ตลำดับสูงที่มีอยู่ (สูงกว่า30000) บนเครื่องโฮสต์ยกเว้นว่าคุณจะระบุพอร์ตที่จะแมปไปยังบนเครื่องโฮสต์เมื่อรันไทม์ คุณไม่สามารถระบุพอร์ตไปยังแผนที่บนเครื่องโฮสต์เมื่อคุณสร้างภาพ (ใน Dockerfile) เพราะมีวิธีที่จะรับประกันว่าพอร์ตที่จะมีอยู่บนเครื่องโฮสต์ที่คุณเรียกใช้ภาพ

จาก: เครือข่ายคอนเทนเนอร์ Docker

อัปเดตตุลาคม 2562 : ข้อความข้างต้นไม่อยู่ในเอกสารอีกต่อไป แต่เวอร์ชันที่เก็บถาวรอยู่ที่นี่: docs.docker.com/v17.09/engine/userguide/networking/#exposing-and-publishing-ports

อาจเป็นเอกสารปัจจุบันด้านล่าง:

พอร์ตที่เผยแพร่

ตามค่าเริ่มต้นเมื่อคุณสร้างคอนเทนเนอร์มันจะไม่เผยแพร่พอร์ตใด ๆ ไปยังโลกภายนอก ในการทำให้พอร์ตพร้อมใช้งานกับบริการที่อยู่นอก Docker หรือไปยังคอนเทนเนอร์ Docker ที่ไม่ได้เชื่อมต่อกับเครือข่ายของคอนเทนเนอร์ให้ใช้--publishหรือ-pตั้งค่าสถานะ สิ่งนี้สร้างกฎไฟร์วอลล์ซึ่งแมปพอร์ตคอนเทนเนอร์กับพอร์ตบนโฮสต์ Docker

และสามารถพบได้ที่นี่: docs.docker.com/config/containers/container-networking/#published-ports

นอกจากนี้

โดน

... EXPOSEคำสั่งไม่ได้เผยแพร่พอร์ตจริง มันทำหน้าที่เป็นประเภทของเอกสารระหว่างบุคคลที่สร้างอิมเมจและบุคคลที่รันคอนเทนเนอร์ซึ่งมีจุดประสงค์ในการเผยแพร่พอร์ต

จาก: การอ้างอิง Dockerfile






การเข้าถึงบริการเมื่อEXPOSE/ --publishไม่ได้ถูกกำหนด:

ที่คำตอบของ @Golo Rodenมีการระบุว่า ::

"ถ้าคุณไม่ได้ระบุสิ่งเหล่านี้บริการในคอนเทนเนอร์จะไม่สามารถเข้าถึงได้จากทุกที่ยกเว้นจากภายในคอนเทนเนอร์เอง"

บางทีนั่นอาจจะเป็นกรณีที่ในเวลานั้นคำตอบที่ถูกเขียน แต่ตอนนี้มันดูเหมือนว่าแม้ว่าคุณจะไม่ได้ใช้EXPOSEหรือ--publishที่hostอื่น ๆcontainersของเครือข่ายเดียวกันจะสามารถเข้าถึงบริการที่คุณอาจจะเริ่มต้นในภาชนะที่

วิธีทดสอบสิ่งนี้:

Dockerfileผมเคยใช้ต่อไปนี้ โดยทั่วไปฉันเริ่มด้วย ubuntu และติดตั้งเว็บเซิร์ฟเวอร์เล็ก ๆ :

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

ฉันbuildเป็นภาพ "ทดสอบ" และrunภาชนะใหม่ด้วย:

docker run --rm -it testexpose bash

ภายในคอนเทนเนอร์ฉันเปิดใช้งานอินสแตนซ์ของmini-httpd:

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

ผมก็สามารถที่จะใช้curlจากโฮสต์หรือภาชนะอื่น ๆ mini-httpdที่จะสามารถดึงข้อมูลหน้าแรกของ


16
นี่เป็นคำตอบที่ถูกต้องแล้ว คำตอบที่ยอมรับจะขึ้นอยู่กับรุ่นก่อนหน้านี้ดูเหมือนว่า
ลุค W

พอร์ตโฮสต์ใดที่คุณใช้สำหรับ curl
พายุสมอง

ฉันใช้ IP ของคอนเทนเนอร์ (คล้าย172.17.0.2) และพอร์ตทั้งหมดที่ฉันพูดถึง หากคุณใช้ Docker สำหรับ Mac / Windows ระบบเครือข่ายจะแตกต่างกัน ไม่มีdocker0สะพาน
tgogos

เมื่อเผยแพร่พอร์ต EXPOSEd ทั้งหมดด้วยแฟล็ก "-P" ฉันจะบอกได้อย่างไรว่าพอร์ตใดที่ใช้ในโฮสต์?
sixty4bit


9

ดูเอกสารอ้างอิงอย่างเป็นทางการ: https://docs.docker.com/engine/reference/builder/#expose

EXPOSEช่วยให้คุณสามารถกำหนดเอกชน (คอนเทนเนอร์) และประชาชน (เจ้าภาพ) พอร์ตที่จะเปิดเผยภาพเวลาในการสร้างเมื่อภาชนะที่กำลังทำงานถ้า-Pคุณเรียกใช้ภาชนะที่มี

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

พอร์ตสาธารณะและโปรโตคอลเป็นตัวเลือกหากไม่ได้ระบุพอร์ตสาธารณะพอร์ตแบบสุ่มจะถูกเลือกบนโฮสต์โดยนักเทียบท่าเพื่อแสดงพอร์ตคอนเทนเนอร์ที่ระบุใน Dockerfile

pratice ที่ดีไม่ได้ระบุพอร์ตสาธารณะเนื่องจากจะ จำกัด เพียงหนึ่งคอนเทนเนอร์ต่อโฮสต์ (คอนเทนเนอร์ที่สองจะโยนพอร์ตที่ใช้งานไปแล้ว)

คุณสามารถใช้-pในdocker runการควบคุมสิ่งที่พอร์ตประชาชนสัมผัสพอร์ตภาชนะที่จะเชื่อมต่อ

อย่างไรก็ตามหากคุณไม่ได้ใช้งานEXPOSE( -Pเมื่อใช้งานนักเทียบท่า) และจะ-pไม่มีพอร์ตใดถูกเปิดเผย

หากคุณมักจะใช้-pที่docker runคุณไม่จำเป็นต้องEXPOSEแต่ถ้าคุณใช้EXPOSEของคุณdocker runคำสั่งอาจจะง่ายมากขึ้นEXPOSEจะมีประโยชน์ถ้าคุณไม่สนใจสิ่งที่พอร์ตจะเปิดเผยบนโฮสต์หรือถ้าคุณแน่ใจว่าเพียงหนึ่งคอนเทนเนอร์จะถูกโหลด


สิ่งนี้ถูกต้อง เมื่อคุณมีพอร์ต EXPOSE หมายเลขใน Dockerfile อย่าลืมเรียกใช้ตัวเรียกใช้ด้วย -P
KunYu Tsai

6

คุณเปิดเผยพอร์ตโดยใช้คีย์เวิร์ด EXPOSE ใน Dockerfile หรือ - ตั้งค่าสถานะเพื่อเรียกใช้นักเทียบท่า การเปิดเผยพอร์ตเป็นวิธีการจัดทำเอกสารที่ใช้พอร์ต แต่ไม่ได้แมปหรือเปิดพอร์ตใด ๆ การเปิดเผยพอร์ตเป็นตัวเลือก

ที่มา: GitHub กระทำ


3

คนส่วนใหญ่ใช้นักเทียบท่าประกอบกับเครือข่าย เอกสารฯ :

คุณสมบัติเครือข่ายนักเทียบท่ารองรับการสร้างเครือข่ายโดยไม่จำเป็นต้องเปิดเผยพอร์ตภายในเครือข่ายสำหรับข้อมูลรายละเอียดดูภาพรวมของคุณสมบัตินี้)

ซึ่งหมายความว่าหากคุณใช้เครือข่ายสำหรับการสื่อสารระหว่างคอนเทนเนอร์คุณไม่จำเป็นต้องกังวลเกี่ยวกับการเปิดเผยพอร์ต


-5

EXPOSE ใช้ในการแมปพอร์ตพอร์ตในตัวเครื่องเช่น: หากคุณระบุ expose ในไฟล์ docker like

EXPOSE 8090

สิ่งที่จะทำจะแมปพอร์ต localhost 8090 กับพอร์ตคอนเทนเนอร์ 8090

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.