Định tuyến từ các container docker bằng giao diện mạng vật lý khác và cổng mặc định


13

Thông tin lai lịch

Tôi có một máy chủ với hai giao diện mạng đang chạy Docker. Docker, giống như một số công cụ ảo hóa, tạo ra một giao diện cầu nối Linux được gọi là docker0. Giao diện này được cấu hình theo mặc định với IP 172.17.42.1và tất cả các container Docker giao tiếp với giao diện này là cổng của chúng và được gán địa chỉ IP trong cùng /16phạm vi. Theo tôi hiểu, tất cả lưu lượng truy cập mạng đến / từ các container đều đi qua NAT, do đó, nó xuất hiện từ bên ngoài 172.17.42.1và đến trong đó nó được gửi đến 172.17.42.1.

Thiết lập của tôi trông như vậy:

                                          +------------+        /
                                          |            |       |
                            +-------------+ 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|       |
                                          +------------+            

Vấn đề

Tôi muốn định tuyến tất cả lưu lượng truy cập từ / đến bất kỳ bộ chứa Docker nào từ eth1 192.168.1.2giao diện thứ hai đến một cổng mặc định của 192.168.1.1, trong khi tất cả lưu lượng truy cập từ / đến máy chủ đi ra ngoài eth0 10.1.1.2giao diện đến một cổng mặc định của 10.1.1.1. Tôi đã thử rất nhiều thứ cho đến nay nhưng không có kết quả, nhưng một điều mà tôi nghĩ là gần nhất để sửa là sử dụng iproute2 như vậy:

# 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

Khi tôi mang lên một container tôi không thể ping ra khỏi nó sau khi làm điều này. Tôi không chắc chắn nếu các giao diện cầu được xử lý giống như các giao diện vật lý dành cho loại định tuyến này và chỉ muốn kiểm tra độ tỉnh táo cũng như bất kỳ mẹo nào về cách tôi có thể thực hiện nhiệm vụ có vẻ đơn giản này.


Nhận xét của bạn về NAT không đúng. Nó được đặt thành giả trang trên địa chỉ nguồn 172.17.0.0/16 trong đó giao diện đầu ra không phải là docker0. tức là -A ĐIỂM -s 172,17.0.0 / 16! -o docker0 -j MẶT NẠ. Điều đó có nghĩa là nếu gói có nguồn gốc từ một container docker thoát qua eth0 hoặc eth1 thì nó sẽ nhận địa chỉ IP giao diện đó, chứ không phải IP 172,17.xx.
Matt

Cám ơn bạn đã góp ý. Vì vậy, điều đó sẽ thay đổi cách tiếp cận của tôi để định tuyến ra khỏi một giao diện cụ thể sau đó, đúng không? Bạn có biết làm thế nào tôi có thể hoàn thành việc này không? Vì thế, Docker dường như chỉ sử dụng cổng mặc định của hệ thống máy chủ và đây không phải là hành vi mong muốn. Tôi muốn tất cả mọi thứ Docker định tuyến ra khỏi một giao diện cụ thể.

Tôi không chắc tại sao những gì tôi đề nghị không hoạt động. Nhưng một lựa chọn khác có thể là sử dụng pipework. github.com/jpetazzo/pipework Ngoài ra phần mạng nâng cao của trợ giúp docker có thể hữu ích để đọc. docs.docker.com/articles/networking
Matt

@Matt Tôi cảm ơn bạn đã góp ý về điều này. Từ những gì tôi đã đọc pipework yêu cầu các lệnh bổ sung sau khi một container được bắt đầu để có quyền truy cập vào cổng chính xác có vẻ như là một lỗ hổng bảo mật. Ban đầu nó được tạo ra để kết nối các container với nhau trên nhiều máy chủ, đây thực sự không phải là mục tiêu của tôi ở đây. Đối với các tài liệu mạng nâng cao Docker, tôi sẽ xem lại, nhưng nó không hữu ích trong tình huống này cho đến nay (tôi đã đọc nó trước khi đăng ở đây). Tôi sẽ đăng một liên kết đến bài đăng này trên trang Các vấn đề Github của docker và xem nó đi từ đó như thế nào.

Đây là đường dẫn quay lại vấn đề Github: github.com/docker/docker/issues/13762

Câu trả lời:


1

Bạn cũng có thể phải xem thêm về thiết lập iptables. Docker giả mạo tất cả lưu lượng truy cập có nguồn gốc từ mạng con container, giả sử là 172.17.0.0/16, đến 0.0.0.0. Nếu bạn chạy iptables -L -n -t nat, bạn có thể thấy chuỗi POSTROUTING bên dưới bảng nat thực hiện điều này -

XÁC NHẬN Chuỗi (CHẤP NHẬN chính sách)
đích đích chọn nguồn tham gia
Tất cả mọi thứ - 172.17.0.0/16 0.0.0.0/0

Bây giờ, bạn có thể xóa quy tắc này và thay thế quy tắc này bằng cách che giấu tất cả lưu lượng truy cập bắt nguồn từ mạng con của bộ chứa sang IP của giao diện thứ hai của bạn - 192.168.1.2, vì đó là điều bạn mong muốn. Quy tắc xóa sẽ là, giả sử rằng đó là quy tắc đầu tiên trong chuỗi POSTROUTING -

iptables -t nat -D ĐIỂM 1

Sau đó, bạn thêm quy tắc tùy chỉnh này -

iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -j SNAT - đến nguồn 192.168.1.2

Trên thực tế, nó giả mạo nó đến giao diện đầu ra. Phần đích đó chỉ nói rằng bất kỳ lưu lượng truy cập nào có nguồn gốc từ mạng con nguồn đến bất kỳ đích nào sẽ bị giả mạo.
Matt

Thật không may, điều này đã không làm việc. Quá trình hoàn thành của tôi là chạy : 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. Sau đó, tôi đã cố chạy ping và traceroute từ một container, và không thể với tới bất cứ thứ gì.

Tôi có một yêu cầu tương tự, máy chủ có thiết lập ip thứ cấp để tiếp cận với IP công cộng. Và tôi muốn container docker theo cùng. Điều này làm việc trong trường hợp đó: "iptables -t nat -Tôi POSTROUTING 1 -s 172.17.0.0/16 -d PUBIP / 32 -j SNAT --Để nguồn SECONDARYIP"
Ram

1

Một người bạn và tôi gặp phải vấn đề chính xác này, nơi chúng tôi muốn có docker hỗ trợ nhiều yêu cầu phục vụ giao diện mạng. Chúng tôi đặc biệt làm việc với dịch vụ AWS EC2 nơi chúng tôi cũng đang đính kèm / định cấu hình / hiển thị các giao diện bổ sung. Trong dự án này , có nhiều hơn những gì bạn cần vì vậy tôi sẽ cố gắng chỉ bao gồm những gì bạn cần ở đây.

Đầu tiên, những gì chúng tôi đã làm là tạo một bảng lộ trình riêng cho eth1:

ip route add default via 192.168.1.2 dev eth1 table 1001

Tiếp theo, chúng tôi đã cấu hình bảng mangle để đặt một số dấu kết nối đến từ 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

Cuối cùng, chúng tôi thêm quy tắc này cho tất cả các fwmarks để sử dụng bảng mới mà chúng tôi đã tạo.

ip rule add from all fwmark 0x1001 lookup 1001

Lệnh dưới đây iptablessẽ khôi phục dấu kết nối và sau đó cho phép quy tắc định tuyến sử dụng bảng định tuyến chính xác.

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

Tôi tin rằng đây là tất cả những gì cần thiết từ ví dụ phức tạp hơn của chúng tôi trong đó (như tôi đã nói) dự án của chúng tôi đã đính kèm / định cấu hình / hiển thị eth1giao diện khi khởi động.

Bây giờ ví dụ này sẽ không ngăn các kết nối từ eth0phục vụ các yêu cầu đến docker0nhưng tôi tin rằng bạn có thể thêm quy tắc định tuyến để ngăn chặn điều đó.


@stuntmachine chỉ tò mò nếu bạn có cơ hội dùng thử? Nếu bạn đã tự mình tìm ra điều gì đó, bạn có thể chia sẻ giải pháp của mình không?
williamsbdev

Xin chào @williamsbdev - bài cũ và một cú sút xa, nhưng bạn có nghĩ giải pháp này cũng sẽ hiệu quả cho vấn đề của tôi về SO không? stackoverflow.com/questions/51312310/ từ
Jolly Roger

2
Jolly Roger - Tôi tin rằng điều này sẽ giải quyết vấn đề của bạn. Gần đây tôi đã có một nhóm khác hỏi tôi về bài đăng trên blog này (về cơ bản là giải pháp tương tự như ở đây) và họ nói rằng nó hoạt động rất tốt. williamsbdev.com/posts/docker-connection-marking
williamsbdev

0

Việc giả trang không phải từ 172.17.42.1 mà là

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

Điều đó có nghĩa là quy tắc này sẽ không hoạt động đúng.

ip rule add from 172.17.42.1 table docker

Thay vào đó hãy thử

ip rule add from 172.17.0.0/16 table docker

Thật không may, điều này đã không làm việc. Các container của tôi vẫn đang định tuyến đến cùng một cổng mặc định như máy chủ lưu trữ. Đây là những gì tôi đã chạy: 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 Từ trong container tôi đã chạy một traceroute và bước nhảy đầu tiên là 10.1.1.1 khi nó phải là 192.168.1.1
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.