Routing basato su port nel contenitore docker

Ho un contenitore di applicazioni docker ( node:latest image) che dispone di due interfacce di networking:

  • eth1: Quale è un'interface predefinita ed è la networking ponte tra tutti i contenitori da un servizio. (Gestito da pipework , ma non posso cambiare nulla a quel livello)
  • eth0: Quale è un'interface normale docker0 e ha accesso a ovunque tranne quelli di eth1 .

Ecco la tabella di routing predefinita:

 Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 10.25.88.254 0.0.0.0 UG 0 0 0 eth1 10.25.88.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0 

Come si vede è necessario avere eth1 come interface predefinita, ma mi causa un problema: la mia applicazione richiede l'accesso di ssh ad altri server remoti che non sono accessibili tramite eth1 ma eth0 ha l'accesso. Quindi devo cambiare il path per queste richieste. La mia prima soluzione è stata:

 route add -net 10.20.33.0/24 gw 172.17.42.1 

Questo approccio funziona bene e avrò accesso a quegli indirizzi nell'intervallo 10.20.33.0/24 . Ma bloccherà l'accesso da tali host all'applicazione stessa. L'applicazione è in servizio nella port 80 e dopo aver aggiunto questo itinerario, tutte le richieste che gli utenti ospitano nell'intervallo 10.20.33.0/24 non saranno 10.20.33.0/24 .

Quindi suppongo che il path sia così globale e che effettua tutte le richieste di input / output a quella gamma di IP. Ho cercato un modo per percorrere solo l'output di ssh richiesto in tutto lo stackoverflow e finora è quello che ho:

 # Initialize route table echo 1 p.ssh > /etc/iproute2/rt_tables ip route add table p.ssh default via 172.17.42.1 # Mark Packet with matching D.Port iptables -A PREROUTING -t mangle -p tcp --dport 22 -j MARK --set-mark 1 iptables -A POSTROUTING -t nat -o eth0 -p tcp --dport 22 -j SNAT --to 172.17.42.1 #IP Route ip rule add fwmark 1 table p.ssh ip route flush cache #IP Stack #This is the missing part from the guide echo 1 > /proc/sys/net/ipv4/ip_forward for f in /proc/sys/net/ipv4/conf/*/rp_filter ; do echo 0 > $f ; done echo 0 > /proc/sys/net/ipv4/route/flush 

Ma non sta funzionando. Ho cercato di registrare il pacchetto contrassegnato da iptables quindi forse potrei trovare un problema nel process, ma il syslog non è in esecuzione all'interno del contenitore, quindi l'ho installato apt-get install rsyslog e apt-get install rsyslog aggiunto questa regola:

 iptables -A PREROUTING -t mangle -p tcp --dport 22 -j LOG --log-level 4 --log-prefix "fwmark 1: " 

Ma non sta registrando niente.

Dopo un paio di giorni ho potuto risolvere questo problema. Ho usato tcpdump come segue per scoprire se il traffico è in routing attraverso l'interface eth0 o no:

 tcpdump -i eth0 port ssh 

E si è scoperto che il primo problema è dal command di marcatura iptables . Così, invece di contrassegnare le richieste sulla catena PREROUTING , le ho segnate sulla catena OUTPUT come segue:

 iptables -t mangle -A OUTPUT -p tcp --dport 22 -j MARK --set-mark 1 

Ora sono stato in grado di vedere le richieste di ssh su eth0 ma ancora non potrei connettere. Si è scoperto che queste richieste devono essere mascherate per funzionare correttamente:

 iptables --table nat --append POSTROUTING -o eth0 -p tcp --dport 22 -j MASQUERADE 

Lo script finale è ora come:

 REMOTE_HOSTS=10.20.33.0/24 HOSTS_ADDR=172.17.42.1 # Add table echo 1 p.ssh >> /etc/iproute2/rt_tables # Add route ip rule add fwmark 1 table p.ssh ip route add $REMOTE_HOSTS via $HOSTS_ADDR dev eth0 table p.ssh # Sets mark correctly iptables -t mangle -A OUTPUT -p tcp --dport 22 -j MARK --set-mark 1 iptables --table nat --append POSTROUTING -o eth0 -p tcp --dport 22 -j MASQUERADE #IP Stack echo 1 > /proc/sys/net/ipv4/ip_forward # Default in debian/ubuntu for f in /proc/sys/net/ipv4/conf/*/rp_filter ; do echo 0 > $f ; done