Routage à partir de conteneurs Docker à l'aide d'une interface réseau physique et d'une passerelle par défaut différentes

13

Informations d'arrière-plan

J'ai un serveur avec deux interfaces réseau qui exécute Docker. Docker, comme certains outils de virtualisation, crée une interface de pont Linux appelée docker0. Cette interface est configurée par défaut avec une IP de 172.17.42.1et tous les conteneurs Docker communiquent avec cette interface comme passerelle et se voient attribuer des adresses IP dans la même /16plage. Si je comprends bien, tout le trafic réseau vers / depuis les conteneurs passe par un NAT, donc sortant il semble provenir 172.17.42.1et entrant il est envoyé 172.17.42.1.

Ma configuration ressemble à ceci:

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

Le problème

Je veux acheminer tout le trafic depuis / vers n'importe quel conteneur Docker de la deuxième eth1 192.168.1.2interface vers une passerelle par défaut de 192.168.1.1, tout en ayant tout le trafic depuis / vers la machine hôte sortir de l' eth0 10.1.1.2interface vers une passerelle par défaut de 10.1.1.1. J'ai essayé une variété de choses jusqu'à présent en vain, mais la seule chose que je pense être la plus proche à corriger est d'utiliser iproute2 comme ceci:

# 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

Lorsque j'apporte un conteneur, je ne peux plus en sortir après avoir fait cela. Je ne suis pas sûr que les interfaces de pont soient gérées de la même manière que les interfaces physiques pour ce type de routage, et je veux juste un contrôle d'intégrité ainsi que des conseils sur la façon dont je pourrais accomplir cette tâche apparemment simple.


la source
Votre commentaire sur le NAT n'est pas juste. Il est configuré pour se masquer sur l'adresse source 172.17.0.0/16 où l'interface de sortie n'est pas docker0. ie -A POSTROUTING -s 172.17.0.0/16! -o docker0 -j MASQUERADE. Ce qui signifie que si le paquet provenant d'un conteneur Docker se termine via eth0 ou eth1, il prendra l'adresse IP de cette interface, pas l'adresse IP 172.17.xx.
Matt
Merci pour votre commentaire. Donc, cela changerait mon approche pour le routage à partir d'une interface spécifique, n'est-ce pas? Savez-vous comment je pourrais y arriver? En l'état, Docker semble simplement utiliser la passerelle par défaut du système hôte, et ce n'est pas le comportement souhaité. Je veux que tout ce que Docker achemine à partir d'une interface spécifique.
Je ne sais pas pourquoi ce que j'ai suggéré ne fonctionne pas. Mais une autre option pourrait être d'utiliser des canalisations. github.com/jpetazzo/pipework La section de mise en réseau avancée de l'aide de docker peut également être utile à lire. docs.docker.com/articles/networking
Matt
@Matt Je vous remercie pour vos suggestions à ce sujet. D'après ce que j'ai lu, la tuyauterie nécessite des commandes supplémentaires après le démarrage d'un conteneur pour lui donner accès à la passerelle appropriée, ce qui semble être une vulnérabilité de sécurité. Il a été créé à l'origine pour connecter des conteneurs entre plusieurs hôtes, ce qui n'est vraiment pas mon objectif ici. En ce qui concerne les documents de mise en réseau avancés de Docker, je vais y jeter un coup d'œil à nouveau, mais cela n'a pas été utile jusqu'à présent (je l'avais lu avant de poster ici). Je vais publier un lien vers ce message sur la page Docker Github Issues et voir comment cela se passe à partir de là.
Voici un lien vers le numéro Github: github.com/docker/docker/issues/13762

Réponses:

1

Vous devrez peut-être aussi regarder plus en détail la configuration d'iptables. Docker masque tout le trafic provenant du sous-réseau de conteneur, par exemple 172.17.0.0/16, à 0.0.0.0. Si vous exécutez iptables -L -n -t nat, vous pouvez voir la chaîne POSTROUTING sous la table nat qui fait cela -

Chaîne POSTROUTING (politique ACCEPTER)
destination cible de la protection opt opt
MASQUERADE all - 172.17.0.0/16 0.0.0.0/0

Maintenant, vous pouvez supprimer cette règle et la remplacer par une règle qui masque tout le trafic provenant du sous-réseau des conteneurs vers l'IP de votre deuxième interface - 192.168.1.2, car c'est ce que vous désirez. La règle de suppression sera, en supposant que c'est la première règle sous la chaîne POSTROUTING -

iptables -t nat -D POSTROUTING 1

Ensuite, vous ajoutez cette règle personnalisée -

iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -j SNAT --to-source 192.168.1.2
Daniel t.
la source
En fait, il le masque à l'interface de sortie. Cette partie destination indique simplement que tout trafic provenant du sous-réseau source vers n'importe quelle destination sera masqué.
Matt
Malheureusement, cela n'a pas fonctionné. Mon processus complet était de courir: 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. Ensuite, j'ai essayé d'exécuter un ping out et un traceroute à partir d'un conteneur, et je n'ai rien pu atteindre.
J'avais une exigence similaire, l'hôte a une configuration IP secondaire pour atteindre une adresse IP publique. Et je voulais que le conteneur Docker suive la même chose. Cela a fonctionné dans ce cas: "iptables -t nat -I POSTROUTING 1 -s 172.17.0.0/16 -d PUBIP / 32 -j SNAT --to-source SECONDARYIP"
Ram
1

Un ami et moi sommes tombés sur ce problème exact où nous voulions que Docker prenne en charge plusieurs demandes de service d'interfaces réseau. Nous travaillions spécifiquement avec le service AWS EC2 où nous attachions / configurions / montions également les interfaces supplémentaires. Dans ce projet , il y a plus que ce dont vous avez besoin, je vais donc essayer d'inclure uniquement ce dont vous avez besoin ici.

Tout d'abord, nous avons créé une table de routage distincte pour eth1:

ip route add default via 192.168.1.2 dev eth1 table 1001

Ensuite, nous avons configuré la table mangle pour définir des marques de connexion provenant de 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

Enfin, nous ajoutons cette règle pour que tous les fwmarks utilisent la nouvelle table que nous avons créée.

ip rule add from all fwmark 0x1001 lookup 1001

La iptablescommande ci-dessous rétablira la marque de connexion, puis autorisera la règle de routage à utiliser la table de routage appropriée.

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

Je crois que c'est tout ce qui est nécessaire dans notre exemple plus complexe où (comme je l'ai dit) notre projet consistait à attacher / configurer / mettre en place l' eth1interface au moment du démarrage.

Maintenant, cet exemple n'empêcherait pas les connexions de eth0répondre aux demandes, docker0mais je pense que vous pouvez ajouter une règle de routage pour empêcher cela.

williamsbdev
la source
@stuntmachine juste curieux de savoir si vous avez eu l'occasion de l'essayer? Si vous avez déjà trouvé quelque chose par vous-même, pourriez-vous partager votre solution?
williamsbdev
Salut @williamsbdev - ancien poste et un long plan, mais pensez-vous que cette solution fonctionnerait également pour mon problème sur SO? stackoverflow.com/questions/51312310/…
Jolly Roger
2
Jolly Roger - Je crois que cela résoudra votre problème. J'ai récemment demandé à une autre équipe de me poser des questions sur cet article de blog (essentiellement la même solution qu'ici) et ils ont dit que cela fonctionnait très bien. williamsbdev.com/posts/docker-connection-marking
williamsbdev
0

La mascarade n'est pas de 172.17.42.1 mais plutôt

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

Ce qui signifie que cette règle ne fonctionnera pas correctement.

ip rule add from 172.17.42.1 table docker

Essayez plutôt

ip rule add from 172.17.0.0/16 table docker
Mat
la source
Malheureusement, cela n'a pas fonctionné. Mes conteneurs étaient toujours acheminés vers la même passerelle par défaut que l'hôte. Voici ce que j'ai exécuté: à 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 partir du conteneur, j'ai exécuté un traceroute et le premier saut était 10.1.1.1 alors qu'il aurait dû être 192.168.1.1