Instradamento dai contenitori della finestra mobile utilizzando un'interfaccia di rete fisica e un gateway predefiniti diversi


13

Informazioni di base

Ho un server con due interfacce di rete che esegue Docker. Docker, come alcuni strumenti di virtualizzazione, crea un'interfaccia bridge Linux chiamata docker0. Questa interfaccia è configurata per impostazione predefinita con un IP di 172.17.42.1e tutti i contenitori Docker comunicano con questa interfaccia come gateway e vengono assegnati indirizzi IP nello stesso /16intervallo. A quanto ho capito, tutto il traffico di rete da / verso i container passa attraverso un NAT, quindi sembra in uscita da cui proviene 172.17.42.1e in entrata viene inviato a 172.17.42.1.

La mia configurazione è simile al seguente:

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

Il problema

Voglio instradare tutto il traffico da / verso qualsiasi contenitore Docker dalla seconda eth1 192.168.1.2interfaccia a un gateway predefinito di 192.168.1.1, mentre tutto il traffico da / verso la macchina host esce eth0 10.1.1.2dall'interfaccia verso un gateway predefinito di 10.1.1.1. Finora ho provato una varietà di cose senza risultati, ma l'unica cosa che penso sia la più vicina da correggere è usare iproute2 in questo modo:

# 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

Quando apro un contenitore non riesco più a eseguire il ping da esso dopo averlo fatto. Non sono sicuro che le interfacce bridge siano gestite allo stesso modo delle interfacce fisiche per questo tipo di instradamento, e voglio solo un controllo di integrità e qualsiasi suggerimento su come potrei realizzare questo compito apparentemente semplice.


Il tuo commento sul NAT non è corretto. È impostato per mascherarsi sull'indirizzo di origine 172.17.0.0/16 in cui l'interfaccia di output non è docker0. cioè -A POSTROUTING -s 172.17.0.0/16! -o docker0 -j MASQUERADE. Ciò significa che se il pacchetto originato da un contenitore docker esce tramite eth0 o eth1, assumerà l'indirizzo IP dell'interfaccia, non l'IP 172.17.xx.
Matt,

Grazie per il tuo commento. Quindi cambierebbe il mio approccio per il routing da un'interfaccia specifica, giusto? Sai come potrei fare per raggiungere questo obiettivo? Allo stato attuale Docker sembra utilizzare solo il gateway predefinito del sistema host e questo non è il comportamento desiderato. Voglio che Docker esca da un'interfaccia specifica.

Non sono sicuro del motivo per cui ciò che ho suggerito non funziona. Ma un'altra opzione potrebbe essere quella di utilizzare le tubazioni. github.com/jpetazzo/pipework Anche la sezione di rete avanzata dell'help docker potrebbe essere utile da leggere. docs.docker.com/articles/networking
Matt

@Matt ti ringrazio per i tuoi suggerimenti su questo. Da quello che ho letto pipework richiede ulteriori comandi dopo l'avvio di un container per ottenere l'accesso al gateway corretto che sembra una vulnerabilità di sicurezza. È stato originariamente creato per connettere i container tra più host, il che non è il mio obiettivo qui. Per quanto riguarda i documenti di rete avanzati Docker, darò di nuovo un'occhiata, ma finora non è stato utile in questa situazione (l'avevo letto prima di pubblicare qui). Pubblicherò un link a questo post nella pagina Problemi di Github docker e vedrò come va da lì.

Ecco un link al numero di Github: github.com/docker/docker/issues/13762

Risposte:


1

Potrebbe essere necessario cercare di più anche sulla configurazione di iptables. Docker maschera tutto il traffico proveniente dalla sottorete del contenitore, ad esempio 172.17.0.0/16, su 0.0.0.0. Se corri iptables -L -n -t nat, puoi vedere la catena POSTROUTING sotto la tabella nat che fa questo -

Catena POSTROUTING (politica ACCETTA)
destinazione di destinazione opt opt ​​prot
Tutti MASQUERADE - 172.17.0.0/16 0.0.0.0/0

Ora puoi rimuovere questa regola e sostituirla con una regola che maschera tutto il traffico proveniente dalla sottorete dei container verso l'IP della tua seconda interfaccia - 192.168.1.2, poiché è quello che desideri. La regola di eliminazione sarà, supponendo che sia la prima regola nella catena POSTROUTING -

iptables -t nat -D POSTROUTING 1

Quindi aggiungi questa regola personalizzata:

iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -j SNAT - to-source 192.168.1.2

In realtà lo collega all'interfaccia di output. Quella parte di destinazione sta solo dicendo che qualsiasi traffico proveniente dalla sottorete di origine verso qualsiasi destinazione verrà mascherato.
Matt

Purtroppo questo non ha funzionato. Il mio processo completo è stato quello di eseguire: 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. Quindi ho provato a eseguire un ping out e un traceroute da un container e non sono riuscito a raggiungere nulla.

Avevo un requisito simile, l'host ha una configurazione ip secondaria per raggiungere un IP pubblico. E volevo che il container docker seguisse lo stesso. In questo caso ha funzionato: "iptables -t nat -I POSTROUTING 1 -s 172.17.0.0/16 -d PUBIP / 32 -j SNAT - to-source SECONDARYIP"
Ram

1

Un amico e io ci siamo imbattuti in questo esatto problema in cui volevamo che la docker supportasse più interfacce di rete per soddisfare le richieste. In particolare, stavamo lavorando con il servizio AWS EC2 in cui stavamo anche collegando / configurando / mettendo in evidenza le interfacce aggiuntive. In questo progetto , c'è molto di più di quello che ti serve, quindi cercherò di includere solo ciò di cui hai bisogno qui.

Innanzitutto, abbiamo creato una tabella di route separata per eth1:

ip route add default via 192.168.1.2 dev eth1 table 1001

Successivamente abbiamo configurato la tabella mangle per impostare alcuni segni di connessione provenienti da 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

Infine aggiungiamo questa regola per tutti fwmarks di utilizzare la nuova tabella che abbiamo creato.

ip rule add from all fwmark 0x1001 lookup 1001

Il iptablescomando seguente ripristina il segno di connessione e quindi consente alla regola di routing di utilizzare la tabella di routing corretta.

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

Credo che questo sia tutto ciò che è necessario dal nostro esempio più complesso in cui (come ho detto) il nostro progetto stava collegando / configurando / aprendo l' eth1interfaccia all'avvio.

Ora questo esempio non impedirebbe alle connessioni di eth0gestire le richieste fino a, docker0ma credo che tu possa aggiungere una regola di routing per impedirlo.


@stuntmachine sei solo curioso di sapere se hai avuto la possibilità di provarlo? Se hai già capito qualcosa da solo, saresti in grado di condividere la tua soluzione?
williamsbdev il

Ciao @williamsbdev - vecchio post e una lunga occasione, ma pensi che questa soluzione funzionerebbe anche per il mio problema su SO? stackoverflow.com/questions/51312310/…
Jolly Roger,

2
Jolly Roger - Credo che questo risolverà il tuo problema. Recentemente un altro team mi ha chiesto di questo post sul blog (essenzialmente la stessa soluzione qui) e hanno detto che ha funzionato alla grande. williamsbdev.com/posts/docker-connection-marking
williamsbdev

0

La mascherata non è del 172.17.42.1 ma piuttosto

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

Ciò significa che questa regola non funzionerà correttamente.

ip rule add from 172.17.42.1 table docker

Prova invece

ip rule add from 172.17.0.0/16 table docker

Purtroppo questo non ha funzionato. I miei contenitori stavano ancora instradando allo stesso gateway predefinito dell'host. Ecco cosa ho eseguito: 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 Dal contenitore ho eseguito un traceroute e il primo hop era 10.1.1.1 quando avrebbe dovuto essere 192.168.1.1
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.