อ็อพชัน --net = host ในคำสั่ง Docker ทำอะไรได้บ้าง?


97

ฉันเพิ่งเริ่มใช้ Docker นิดหน่อย ฉันไม่พบคำอธิบายที่ชัดเจนว่าตัวเลือกนี้ทำอะไรในคำสั่ง docker run ในเชิงลึกและสับสนเล็กน้อย

เราสามารถใช้มันเพื่อเข้าถึงแอพพลิเคชั่นที่ทำงานบน Docker container โดยไม่ระบุพอร์ตได้หรือไม่? ตัวอย่างเช่นหากฉันเรียกใช้ webapp ที่ปรับใช้ผ่านอิมเมจนักเทียบท่าในพอร์ต 8080 โดยใช้ตัวเลือก-p 8080:8080ในคำสั่ง docker run ฉันรู้ว่าฉันจะต้องเข้าถึงบนพอร์ต 8080 บนคอนเทนเนอร์ Docker ip / theWebAppName แต่ฉันคิดไม่ออกจริงๆว่า--net=hostตัวเลือกทำงานอย่างไร

คำตอบ:


131

หลังจากการติดตั้งนักเทียบท่าคุณมี 3 เครือข่ายตามค่าเริ่มต้น:

docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
f3be8b1ef7ce        bridge              bridge              local
fbff927877c1        host                host                local
023bb5940080        none                null                local

ฉันพยายามทำให้มันเรียบง่าย ดังนั้นหากคุณเริ่มคอนเทนเนอร์ตามค่าเริ่มต้นระบบจะสร้างคอนเทนเนอร์ภายในเครือข่ายบริดจ์ (docker0)

$ docker run -d jenkins
1498e581cdba        jenkins             "/bin/tini -- /usr..."   3 minutes ago       Up 3 minutes        8080/tcp, 50000/tcp   friendly_bell

ใน dockerfile ของ jenkins พอร์ต8080และ50000ถูกเปิดเผย พอร์ตเหล่านั้นถูกเปิดสำหรับคอนเทนเนอร์บนเครือข่ายบริดจ์ เพื่อให้ทุกอย่างภายในเครือข่ายสะพานที่สามารถเข้าถึงภาชนะในพอร์ตและ8080 50000ทุกอย่างในเครือข่ายสะพานอยู่ในช่วงของเอกชน"Subnet": "172.17.0.0/16",หากคุณต้องการที่จะเข้าถึงได้จากภายนอกที่คุณต้อง map -p 8080:8080พอร์ตด้วย สิ่งนี้จะแมปพอร์ตของคอนเทนเนอร์ของคุณกับพอร์ตของเซิร์ฟเวอร์จริงของคุณ (เครือข่ายโฮสต์) ดังนั้นการเข้าถึงเซิร์ฟเวอร์ของคุณ8080จะกำหนดเส้นทางไปยัง bridgenetwork บนพอร์ตของ8080คุณ

ตอนนี้คุณมีเครือข่ายโฮสต์แล้ว ซึ่งไม่ได้สร้างเครือข่ายคอนเทนเนอร์ ดังนั้นหากคุณเริ่มคอนเทนเนอร์ในเครือข่ายโฮสต์จะมีลักษณะดังนี้ (เป็นคอนเทนเนอร์แรก):

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                 NAMES
1efd834949b2        jenkins             "/bin/tini -- /usr..."   6 minutes ago       Up 6 minutes                              eloquent_panini
1498e581cdba        jenkins             "/bin/tini -- /usr..."   10 minutes ago      Up 10 minutes       8080/tcp, 50000/tcp   friendly_bell

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

$ sudo iptables -I INPUT 5 -p tcp -m tcp --dport 8080 -j ACCEPT

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


4
เป็นไปได้หรือไม่ที่จะเพิ่มตัวเลือก--net=hostภายใน Dockerfile
AnirbanDebnath

6
@AnirbanDebnath ผมไม่คิดว่ามันเป็นไปได้ที่จะนำมาใส่ใน dockerfile แต่ตั้งแต่นักเทียบท่า v17 docker build --network=hostคุณสามารถใช้มันเป็นพารามิเตอร์สำหรับนักเทียบท่าสร้างของคุณ: เครือข่ายโฮสต์ที่ระบุสำหรับการสร้างนักเทียบท่ามีไว้สำหรับการดาวน์โหลดแพ็คเกจที่จำเป็นสำหรับการสร้างอิมเมจเท่านั้น เมื่อคุณต้องการเรียกใช้คอนเทนเนอร์ของคุณบนเครือข่ายโฮสต์คุณยังคงต้องกำหนดตัวเลือก --network = host
lvthillo

ใช่ @AnirbanDebnath อนุญาตใน Dockerfile เช่นใน v3 - network_mode: "host"(อ้างอิง - docs.docker.com/compose/compose-file/#network_mode )
Mohnish

1
นั่นคือไฟล์ Docker-Compose ซึ่งอธิบายวิธีเรียกใช้คอนเทนเนอร์ ไม่ใช่ Dockerfile แต่แท้จริงแล้วมีความเป็นไปได้และทำเช่นเดียวกับ docker run --network = host
lvthillo

31

--net=hostตัวเลือกที่จะใช้เพื่อให้โปรแกรมภายในหางดูภาชนะเช่นที่พวกเขากำลังทำงานอยู่ในพื้นที่ของตัวเองจากมุมมองของเครือข่าย ช่วยให้คอนเทนเนอร์เข้าถึงเครือข่ายได้มากกว่าปกติ

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

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

ตัวอย่างเช่นหากคุณต้องการเรียกใช้เซิร์ฟเวอร์ DHCP คุณจะต้องสามารถรับฟังการรับส่งข้อมูลบนเครือข่ายและแยกที่อยู่ MAC ออกจากแพ็กเก็ต ข้อมูลเหล่านี้จะหายไปในระหว่างขั้นตอนการส่งต่อพอร์ตดังนั้นวิธีเดียวที่จะเรียกใช้เซิร์ฟเวอร์ DHCP --net=hostภายในหางคือการใช้ภาชนะที่เป็น

โดยทั่วไปแล้ว--net=hostจำเป็นเฉพาะเมื่อคุณใช้งานโปรแกรมที่มีความต้องการเครือข่ายที่เฉพาะเจาะจงและผิดปกติเท่านั้น

สุดท้ายจากมุมมองด้านความปลอดภัยคอนเทนเนอร์ Docker สามารถรับฟังได้บนพอร์ตจำนวนมากแม้ว่าจะโฆษณาเพียงพอร์ตเดียวก็ตาม โดยปกติจะใช้ได้ดีเมื่อคุณส่งต่อพอร์ตที่คาดหวังเพียงพอร์ตเดียวอย่างไรก็ตามหากคุณใช้--net=hostคุณจะได้รับพอร์ตของคอนเทนเนอร์ทั้งหมดที่ฟังบนโฮสต์แม้กระทั่งพอร์ตที่ไม่ได้ระบุไว้ใน Dockerfile ซึ่งหมายความว่าคุณจะต้องตรวจสอบคอนเทนเนอร์อย่างใกล้ชิด (โดยเฉพาะอย่างยิ่งหากไม่ใช่ของคุณเช่นตู้ที่เป็นทางการจากโครงการซอฟต์แวร์) เพื่อให้แน่ใจว่าคุณจะไม่เปิดเผยบริการพิเศษบนเครื่องโดยไม่ได้ตั้งใจ


พฤติกรรมจะเป็นอย่างไรหากหลายคอนเทนเนอร์เริ่มต้นด้วยตัวเลือก '--net = host' คำขอจะถูกส่งต่อไปยังคอนเทนเนอร์แบบสุ่มหรือไม่
user482594

@ user482594: พวกเขาทั้งหมดจะแชร์สแต็กเครือข่ายเดียวกันเหมือนกับที่คุณรันโปรแกรมทั้งหมดภายในคอนเทนเนอร์เดียวกัน เช่นหากคุณเรียกใช้เว็บเซิร์ฟเวอร์สองเว็บคุณจะต้องตรวจสอบให้แน่ใจว่าพวกเขากำลังฟังอยู่บนพอร์ตที่แตกต่างกันมิฉะนั้นคอนเทนเนอร์ที่สองจะได้รับข้อผิดพลาดว่าพอร์ตนั้นถูกใช้งาน การรับส่งข้อมูลขาเข้าจะถูกส่งต่อไปยังคอนเทนเนอร์ใดก็ตามที่กำลังฟังอยู่ (ในทางเทคนิค--net=hostคอนเทนเนอร์ทั้งหมดจะเห็นการรับส่งข้อมูล แต่แน่นอนว่ามีเพียงโปรแกรมเดียวในแต่ละครั้งที่สามารถรับฟังพอร์ตที่กำหนดได้ไม่ว่าคุณจะเรียกใช้คอนเทนเนอร์ใดก็ตามในการตั้งค่านี้ ).
Malvineous

1
  1. คุณสามารถสร้างเครือข่ายใหม่ของคุณเองเช่น --net = "anyname"
  2. สิ่งนี้ทำเพื่อแยกบริการจากคอนเทนเนอร์ที่แตกต่างกัน
  3. สมมติว่าบริการเดียวกันกำลังทำงานในคอนเทนเนอร์ที่แตกต่างกัน แต่การแมปพอร์ตยังคงเหมือนเดิมคอนเทนเนอร์แรกเริ่มต้นได้ดี แต่บริการเดียวกันจากคอนเทนเนอร์ที่สองจะล้มเหลว ดังนั้นเพื่อหลีกเลี่ยงปัญหานี้ให้เปลี่ยนการแมปพอร์ตหรือสร้างเครือข่าย

1
ขอขอบคุณที่กล่าวถึง "2. สิ่งนี้ทำเพื่อแยกบริการ (เครือข่าย) จากคอนเทนเนอร์ที่แตกต่างกัน" ฉันเห็นคุณค่าของการใช้คอนฟิกูเรชันเครือข่ายนักเทียบท่าอื่น ๆ (นอกเหนือจากhost) อย่างแท้จริงหากมีความเป็นไปได้ที่จะเรียกใช้หลายคอนเทนเนอร์บนโฮสต์เดียวกัน ในกรณีอื่น ๆ (ที่แยกเครือข่ายไม่จำเป็นต้องใช้) --net=hostผมต้องการ
CᴴᴀZ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.