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


13

ข้อมูลพื้นฐาน

ฉันมีเซิร์ฟเวอร์ที่มีอินเตอร์เฟสเครือข่ายสองตัวที่เรียกใช้ Docker หางเช่นเครื่องมือ virtualization docker0บางสร้างอินเตอร์เฟซลินุกซ์ที่เรียกว่าสะพาน อินเทอร์เฟซนี้ถูกกำหนดค่าเริ่มต้นด้วย IP ของ172.17.42.1และคอนเทนเนอร์ Docker ทั้งหมดสื่อสารกับอินเทอร์เฟซนี้เป็นเกตเวย์ของพวกเขาและได้รับการกำหนดที่อยู่ IP ใน/16ช่วงเดียวกัน ตามที่ผมเข้าใจมันทุกเครือข่ายการจราจรไปยัง / จากตู้คอนเทนเนอร์ไปผ่าน NAT ดังนั้นขาออกก็ปรากฏขึ้นมาจากและขาเข้าจะได้รับการส่งไปยัง172.17.42.1172.17.42.1

การตั้งค่าของฉันดูเหมือนว่า:

                                          +------------+        /
                                          |            |       |
                            +-------------+ Gateway 1  +-------
                            |             | 10.1.1.1   |     /
                     +------+-------+     +------------+    |
                     |     eth0     |                      /
                     |   10.1.1.2   |                      |
                     |              |                      |
                     | DOCKER HOST  |                      |
                     |              |                      | Internet
                     |   docker0    |                      |
                     |   (bridge)   |                      |
                     |  172.17.42.1 |                      |
                     |              |                      |
                     |     eth1     |                      |
                     |  192.168.1.2 |                      \
                     +------+-------+     +------------+    |
                            |             |            |     \
                            +-------------+ Gateway 2  +-------
                                          | 192.168.1.1|       |
                                          +------------+            

ปัญหา

ฉันต้องการที่จะใช้เส้นทางการจราจรทั้งหมดจาก / ไปยังภาชนะใด ๆ หางออกมาจากสองeth1 192.168.1.2อินเตอร์เฟซเกตเวย์เริ่มต้นของ192.168.1.1ในขณะที่มีการเข้าชมทั้งหมดจาก / ไปยังเครื่องโฮสต์ออกไปอินเตอร์เฟซเกตเวย์เริ่มต้นของeth0 10.1.1.2 10.1.1.1ฉันได้ลองทำสิ่งต่าง ๆ จนไม่มีประโยชน์ แต่สิ่งหนึ่งที่ฉันคิดว่าใกล้เคียงที่สุดคือการใช้ iproute2 ดังนี้:

# Create a new routing table just for docker
echo "1 docker" >> /etc/iproute2/rt_tables

# Add a rule stating any traffic from the docker0 bridge interface should use 
# the newly added docker routing table
ip rule add from 172.17.42.1 table docker

# Add a route to the newly added docker routing table that dictates all traffic
# go out the 192.168.1.2 interface on eth1
ip route add default via 192.168.1.2 dev eth1 table docker

# Flush the route cache
ip route flush cache

# Restart the Docker daemon so it uses the correct network settings
# Note, I do this as I found Docker containers often won't be able
# to connect out if any changes to the network are made while it's     
# running
/etc/init.d/docker restart

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


ความคิดเห็นของคุณเกี่ยวกับ NAT ไม่ถูกต้อง มันถูกตั้งค่าให้ทำการปลอมบนที่อยู่แหล่งที่มา 172.17.0.0/16 ซึ่งส่วนต่อประสานเอาต์พุตไม่ได้เป็นตัวเทียบท่า 0 ie -A POSTROUTING -s 172.17.0.0/16! -o docker0 -j MASQUERADE ซึ่งหมายความว่าหากแพ็กเก็ตที่มาจากตัวเทียบท่าออกจาก eth0 หรือ eth1 มันจะใช้ที่อยู่ IP ของอินเตอร์เฟสนั้นไม่ใช่ IP 172.17.xx
Matt

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

ฉันไม่แน่ใจว่าทำไมสิ่งที่ฉันแนะนำไม่ทำงาน แต่อีกทางเลือกหนึ่งคือใช้งานท่อ github.com/jpetazzo/pipework ส่วนการเชื่อมต่อเครือข่ายขั้นสูงของตัวช่วยเหลือนักเทียบท่าอาจเป็นประโยชน์ในการอ่าน docs.docker.com/articles/networking
Matt

@ Matt ฉันขอขอบคุณสำหรับคำแนะนำของคุณเกี่ยวกับเรื่องนี้ จากสิ่งที่ฉันอ่านไปป์ไลน์ต้องใช้คำสั่งเพิ่มเติมหลังจากที่คอนเทนเนอร์เริ่มต้นเพื่อให้สามารถเข้าถึงเกตเวย์ที่ถูกต้องซึ่งดูเหมือนว่ามีความเสี่ยงด้านความปลอดภัย เดิมทีมันถูกสร้างขึ้นเพื่อเชื่อมต่อคอนเทนเนอร์เข้าด้วยกันในหลาย ๆ โฮสต์ซึ่งไม่ใช่เป้าหมายของฉันที่นี่ สำหรับเอกสารเครือข่ายขั้นสูงของ Docker ฉันจะดูอีกครั้ง แต่มันก็ยังไม่เป็นประโยชน์ในสถานการณ์นี้ (ฉันได้อ่านก่อนที่จะโพสต์ที่นี่) ฉันจะโพสต์ลิงก์ไปยังโพสต์นี้ในหน้านักเทียบเรือปัญหา Github และดูว่ามันไปจากที่นั่นได้อย่างไร

นี่คือลิงค์กลับไปที่ Github Issue: github.com/docker/docker/issues/13762

คำตอบ:


1

คุณอาจต้องดูเพิ่มเติมเกี่ยวกับการตั้งค่า iptables ด้วย นักเทียบท่าปลอมตัวการรับส่งข้อมูลทั้งหมดที่มาจากซับเน็ตคอนเทนเนอร์พูด 172.17.0.0/16 ถึง 0.0.0.0 หากคุณเรียกใช้iptables -L -n -t natคุณสามารถดูโพสต์โซ่ภายใต้ตาราง nat ซึ่งทำสิ่งนี้ -

การโพสต์เครือข่าย (ยอมรับนโยบาย)
ปลายทางต้นทางเลือกเป้าหมายได้
สวมหน้ากากทั้งหมด - 172.17.0.0/16 0.0.0.0/0

ตอนนี้คุณสามารถลบกฎนี้และแทนที่ด้วยกฎที่ปลอมแปลงการรับส่งข้อมูลทั้งหมดที่มาจากซับเน็ตของคอนเทนเนอร์ไปยัง IP อินเทอร์เฟซที่สองของคุณ - 192.168.1.2 ตามที่คุณต้องการ กฎการลบจะเป็นสมมติว่ามันเป็นกฎแรกภายใต้ห่วงโซ่ POSTROUTING -

iptables -t nat -D การโพสต์ 1

จากนั้นคุณเพิ่มกฎที่กำหนดเองนี้ -

iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -j SNAT - ไปยังแหล่ง 192.168.1.2

จริงๆแล้วมันจะ masquarades มันไปยังอินเตอร์เฟซเอาท์พุท ส่วนปลายทางนั้นเพิ่งบอกว่าการรับส่งข้อมูลใด ๆ ที่มาจากซับเน็ตต้นทางไปยังปลายทางใด ๆ จะถูก masquaraded
Matt

น่าเสียดายที่นี่ไม่ได้ผล กระบวนการทั้งหมดของฉันคือการทำงาน: ip rule add from 172.17.0.0/16 table docker ip route add default via 192.168.1.2 dev eth1 table docker ip route flush cache iptables -t nat -D POSTROUTING 1 iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -j SNAT --to-source 192.168.1.2 /etc/init.d/docker restart. จากนั้นฉันพยายามเรียก ping out และ traceroute ออกจากตู้คอนเทนเนอร์และไม่สามารถเข้าถึงอะไรได้

ฉันมีข้อกำหนดที่คล้ายกันโฮสต์มีการตั้งค่า IP รองเพื่อเข้าถึง IP สาธารณะ และฉันต้องการให้นักเทียบท่าคอนเทนเนอร์ทำตามสิ่งเดียวกัน สิ่งนี้ทำงานได้ในกรณีนั้น: "iptables -t nat -I POSTROUTING 1 -s 172.17.0.0/16 -d PUBIP / 32 -j SNAT - ไปยังแหล่งข้อมูลวินาที"
Ram

1

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

อันดับแรกสิ่งที่เราทำคือสร้างตารางเส้นทางแยกสำหรับeth1:

ip route add default via 192.168.1.2 dev eth1 table 1001

ต่อไปเรากำหนดค่าตาราง mangle เพื่อตั้งเครื่องหมายการเชื่อมต่อบางอย่างที่มาจากeth1:

iptables -t mangle -A PREROUTING -i eth1 -j MARK --set-xmark 0x1001/0xffffffff
iptables -t mangle -A PREROUTING -i eth1 -j CONNMARK --save-mark --nfmask 0xffffffff --ctmask 0xffffffff

ในที่สุดเราก็เพิ่มกฎนี้เพื่อให้ทุกคนfwmarkใช้ตารางใหม่ที่เราสร้างขึ้น

ip rule add from all fwmark 0x1001 lookup 1001

iptablesคำสั่งด้านล่างจะเรียกคืนเครื่องหมายการเชื่อมต่อแล้วอนุญาตให้กฎการกำหนดเส้นทางใช้ตารางเส้นทางที่ถูกต้อง

iptables -w -t mangle -A PREROUTING -i docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff

ฉันเชื่อว่านี่คือทั้งหมดที่ต้องการจากตัวอย่างที่ซับซ้อนมากขึ้นของเราที่โครงการของเรากำลังเชื่อมต่อ / กำหนดค่า / เปิดeth1อินเทอร์เฟซเมื่อเริ่มระบบ

ตอนนี้ตัวอย่างนี้จะไม่หยุดการเชื่อมต่อจากการeth0ให้บริการผ่านไปยังdocker0แต่ฉันเชื่อว่าคุณสามารถเพิ่มกฎการกำหนดเส้นทางเพื่อป้องกัน


@stuntmachine แค่อยากรู้อยากเห็นถ้าคุณมีโอกาสลองดู? หากคุณค้นพบบางสิ่งด้วยตัวคุณเองคุณจะสามารถแบ่งปันโซลูชันของคุณได้หรือไม่?
williamsbdev

สวัสดี @williamsbdev - โพสต์เก่าและเป็นเวลานาน แต่คุณคิดว่าวิธีนี้จะช่วยแก้ปัญหาของฉันใน SO ได้หรือไม่ stackoverflow.com/questions/51312310/…
Jolly Roger

2
Jolly Roger - ฉันเชื่อว่านี่จะช่วยแก้ปัญหาของคุณ ฉันเพิ่งมีทีมอื่นถามฉันเกี่ยวกับการโพสต์บล็อกนี้ (โดยพื้นฐานแล้วเป็นวิธีเดียวกับที่นี่) และพวกเขาบอกว่ามันใช้งานได้ดี williamsbdev.com/posts/docker-connection-marking
williamsbdev

0

หน้ากากไม่ได้มาจาก 172.17.42.1

 -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE

ซึ่งหมายความว่ากฎนี้ใช้งานไม่ได้

ip rule add from 172.17.42.1 table docker

ลองแทน

ip rule add from 172.17.0.0/16 table docker

น่าเสียดายที่นี่ไม่ได้ผล คอนเทนเนอร์ของฉันยังคงกำหนดเส้นทางไปยังเกตเวย์เริ่มต้นเดียวกันกับโฮสต์ นี่คือสิ่งที่ฉันวิ่ง: ip rule add from 172.17.0.0/16 table docker ip route add default via 192.168.1.2 dev eth1 table docker ip route flush cache /etc/init.d/docker restart จากในภาชนะฉันวิ่ง traceroute และกระโดดครั้งแรกคือ 10.1.1.1 เมื่อมันควรจะเป็น 192.168.1.1
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.