Kann nicht über Linux Bridge kommunizieren

Einführung

Als ich bei der Fehlerbehebung des Titels nachforschte, entschied ich mich, ihn zu schreiben, da es nur wenige Artikel gab, in denen diese Angelegenheit unerwartet als kritisch erwähnt wurde.

Veranstaltung

Als ich unter CentOS7 eine Linux Bridge erstellte, einen Docker-Container darunter zuordnete und die Kommunikation bestätigte, konnte keine Kommunikation durchgeführt werden. qiita-bridge-1.png

Fazit

Linux Bridge arbeitet mit einem Kernelmodul namens Bridge, aber seine Sicherheit wird von einem Kernelmodul namens br_netfilter (Abhängigkeit von Bridge) verwaltet, und br_netfilter steuert die Kommunikation anhand der iptales-Einstellungen. .. Daher kann die Kommunikation durchgeführt werden, indem eine der folgenden Aktionen ausgeführt wird.

① Deaktivieren Sie Bridge Netfilter ② Legen Sie die Berechtigung für iptables fest

Überprüfungsumgebung

OS:CentOS 7.5 Kernel Ver:3.10.0-862.14.4.el7.x86_64 docker Ver:18.06.1-ce

Überprüfung mit normalem Docker 0

Stellen Sie zunächst sicher, dass die Container über Docker0 miteinander kommunizieren können. Dies wird normalerweise zugewiesen, wenn der Docker-Container bereitgestellt wird.

Stellen Sie den Docker-Container bereit

Führen Sie Docker Run aus und stellen Sie zwei Container bereit.

 docker run -d --name cent1 centos/tools:latest /sbin/init
 docker run -d --name cent2 centos/tools:latest /sbin/init

Stellen Sie sicher, dass der Container mit dem Befehl docker ps normal gestartet wurde.

 docker ps
CONTAINER ID        IMAGE                 COMMAND             CREATED              STATUS              PORTS               NAMES
8126f9f72ee2        centos/tools:latest   "/sbin/init"        6 seconds ago        Up 3 seconds                            cent2
a957a097b6a5        centos/tools:latest   "/sbin/init"        About a minute ago   Up About a minute                       cent1

Überprüfen Sie den Zuweisungsstatus zu docker0

Überprüfen Sie zunächst die Zuordnung zwischen der Netzwerkkarte des bereitgestellten Containers und der Netzwerkkarte des Docker-Hosts. Überprüfen Sie jede Netzwerkkarte des Docker-Containers wie folgt. eth0 von cent1 ist der Index9 des Docker-Hosts eth0 von cent2 ist index11 des Docker-Hosts Sie können sehen, dass es gebunden ist.

 docker exec cent1 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

 docker exec cent2 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

Überprüfen Sie die Netzwerkkarte des Docker-Hosts wie folgt.

 ip l
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 00:0c:29:b3:b5:18 brd ff:ff:ff:ff:ff:ff
3: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 00:0c:29:b3:b5:22 brd ff:ff:ff:ff:ff:ff
4: vlan10@ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 00:0c:29:b3:b5:22 brd ff:ff:ff:ff:ff:ff
5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default 
    link/ether 02:42:1c:c2:6d:d0 brd ff:ff:ff:ff:ff:ff
9: vethc59a2d1@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default 
    link/ether f6:1a:1b:00:b9:b5 brd ff:ff:ff:ff:ff:ff link-netnsid 0
11: vethfee6857@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default 
    link/ether 86:45:ea:11:db:35 brd ff:ff:ff:ff:ff:ff link-netnsid 1

Wenn Sie die Informationen von Linux Bridge überprüfen, können Sie außerdem sehen, dass veth auf der Hostseite von cent1 und 2 docker0 zugewiesen ist, wie unten gezeigt.

 brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.02421cc26dd0	no		vethc59a2d1
							vethfee6857

Das Obige kann wie im Bild unten gezeigt zusammengefasst werden.

qiita-bridge-2.png

Bestätigung der Kommunikation über docker0

Wenn Sie den Ping über docker0 von cent1 nach cent2 überspringen und die Kommunikation überprüfen, können Sie wie folgt normal kommunizieren.

 docker exec cent2 ping -c 3 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=10.2 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.048 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.045 ms

--- 172.17.0.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 0.045/3.448/10.252/4.811 ms

Überprüfung mit neu erstellter Bridge

Hier ist das Hauptproblem. Wenn Sie als Nächstes eine neue Linux Bridge erstellen und einen Docker-Container zuweisen, prüfen Sie, ob Sie wie Docker0 kommunizieren können.

Erstellen Sie eine neue Brücke

Erstellen Sie eine Brücke mit dem Namen new-bridge1 als neue Brücke.

 brctl addbr new-bridge1
 brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.02421cc26dd0	no		vethc59a2d1
							vethfee6857
new-bridge1		8000.000000000000	no		

Starten Sie Bridge nach dem Erstellen wie folgt.

 ip l set dev new-bridge1 up
 ip l
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 00:0c:29:b3:b5:18 brd ff:ff:ff:ff:ff:ff
3: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 00:0c:29:b3:b5:22 brd ff:ff:ff:ff:ff:ff
4: vlan10@ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 00:0c:29:b3:b5:22 brd ff:ff:ff:ff:ff:ff
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default 
    link/ether 02:42:1c:c2:6d:d0 brd ff:ff:ff:ff:ff:ff
9: vethc59a2d1@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master new-bridge1 state UP mode DEFAULT group default 
    link/ether f6:1a:1b:00:b9:b5 brd ff:ff:ff:ff:ff:ff link-netnsid 0
11: vethfee6857@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master new-bridge1 state UP mode DEFAULT group default 
    link/ether 86:45:ea:11:db:35 brd ff:ff:ff:ff:ff:ff link-netnsid 1
12: new-bridge1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 86:45:ea:11:db:35 brd ff:ff:ff:ff:ff:ff

Container-NIC von Docker0 ausschließen

Die Netzwerkkarte des vom Docker bereitgestellten Containers (genauer gesagt die veth, die der Container-Netzwerkkarte auf der Docker-Hostseite entspricht) befindet sich in dem Status, der Docker0 zugewiesen ist. Schließen Sie diese Container-NICs zur Überprüfung von Docker 0 aus.

 brctl delif docker0 vethc59a2d1
 brctl delif docker0 vethfee6857
 brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.02421cc26dd0	no		
new-bridge1		8000.000000000000	no		

Weisen Sie der erstellten Bridge eine Container-Netzwerkkarte zu

Weisen Sie die Container-NIC der neu erstellten new-bridge1 zu.

 brctl addif new-bridge1 vethc59a2d1
 brctl addif new-bridge1 vethfee6857

 brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.02421cc26dd0	no		
new-bridge1		8000.8645ea11db35	no		vethc59a2d1
							vethfee6857

Wenn Sie die Operationen bis zu diesem Punkt ausführen, wird der Status wie in der Abbildung unten gezeigt angezeigt.

qiita-bridge-3.png

Bestätigung der Kommunikation über die neu erstellte Brücke

Versuchen Sie über die neu erstellte new-bridge1, wie zuvor docker0, von cent1 nach cent2 zu pingen, um die Kommunikation zu überprüfen.

 docker exec cent1 ping -c 3 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.

--- 172.17.0.3 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 1999ms

Im Gegensatz zu Docker0 können Sie dann feststellen, dass zwischen cent1 und cent2 keine Kommunikation besteht.

Ereignisuntersuchung

Paketerfassung

Versuchen Sie zunächst, tcpdump auf jeder Netzwerkkarte abzurufen. Zwei Dinge können aus den Ergebnissen unten gesehen werden. (1) Die ARP-Anfrage ist normalerweise von Cent1 bis Cent2 eingegangen, und Cent1 hat die Antwort erhalten. ② Der Ping hat die Linux Bridge (new-bridge1) erreicht, nicht aber den cent2

qiita-bridge-4.png

NIC von cent1

 tcpdump -i vethc59a2d1 
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on vethc59a2d1, link-type EN10MB (Ethernet), capture size 262144 bytes
23:20:39.379638 IP 172.17.0.2 > 172.17.0.3: ICMP echo request, id 45, seq 1, length 64
23:20:40.378780 IP 172.17.0.2 > 172.17.0.3: ICMP echo request, id 45, seq 2, length 64
23:20:41.378785 IP 172.17.0.2 > 172.17.0.3: ICMP echo request, id 45, seq 3, length 64
23:20:44.383711 ARP, Request who-has 172.17.0.3 tell 172.17.0.2, length 28
23:20:44.383744 ARP, Reply 172.17.0.3 is-at 02:42:ac:11:00:03 (oui Unknown), length 28

NIC von cent2

 tcpdump -i vethfee6857
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on vethfee6857, link-type EN10MB (Ethernet), capture size 262144 bytes
23:20:44.383726 ARP, Request who-has 172.17.0.3 tell 172.17.0.2, length 28
23:20:44.383741 ARP, Reply 172.17.0.3 is-at 02:42:ac:11:00:03 (oui Unknown), length 28

new-bridge1

 tcpdump -i new-bridge1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on new-bridge1, link-type EN10MB (Ethernet), capture size 262144 bytes
23:20:39.379638 IP 172.17.0.2 > 172.17.0.3: ICMP echo request, id 45, seq 1, length 64
23:20:40.378780 IP 172.17.0.2 > 172.17.0.3: ICMP echo request, id 45, seq 2, length 64
23:20:41.378785 IP 172.17.0.2 > 172.17.0.3: ICMP echo request, id 45, seq 3, length 64
23:20:44.383711 ARP, Request who-has 172.17.0.3 tell 172.17.0.2, length 28
23:20:44.383741 ARP, Reply 172.17.0.3 is-at 02:42:ac:11:00:03 (oui Unknown), length 28

In Bezug auf ① werde ich den ARP-Cache in jedem Container für alle Fälle überprüfen. Sie können sehen, dass die MAC-Adresse des Kommunikationspartners normal geschrieben ist.

 docker exec cent1 arp -e
Address                  HWtype  HWaddress           Flags Mask            Iface
172.17.0.3               ether   02:42:ac:11:00:03   C                     eth0
gateway                          (incomplete)                              eth0

 docker exec cent2 arp -e
Address                  HWtype  HWaddress           Flags Mask            Iface
172.17.0.2               ether   02:42:ac:11:00:02   C                     eth0
gateway                          (incomplete)                              eth0

Warum passiert das?

Linux Bridge arbeitet mit einem Kernelmodul namens Bridge, aber seine Sicherheit wird von einem Kernelmodul namens br_netfilter (Abhängigkeit von Bridge) verwaltet, und br_netfilter steuert die Kommunikation anhand der iptables-Einstellungen. Es scheint, dass. Daher ist die Kommunikation über Bridge standardmäßig nicht zulässig, und dies geschieht.

$ lsmod | grep br_netfilter
br_netfilter           24576  0
bridge                155648  1 br_netfilter

Lösungen

Die Kommunikation zwischen Containern wird durch eine der folgenden Maßnahmen möglich.

Teil 1 Deaktivieren Sie Bridge Netfilter

Netfilter, das normalerweise die Linux Bridge-Kommunikation steuert, ist aktiviert. Die Kommunikation kann erreicht werden, indem dies absichtlich deaktiviert wird. Das Aktivieren / Deaktivieren von Bridge Netfilter ist der Kernelparameter net.bridge.bridge-nf-call-iptables. Kann von eingestellt werden.

Überprüfen Sie den Status des Bridge Net-Filters Derzeit ist 1 gesetzt und befindet sich in einem gültigen Zustand.

 sysctl net.bridge.bridge-nf-call-iptables
net.bridge.bridge-nf-call-iptables = 1

Einstellungsänderung Setzen Sie net.bridge.bridge-nf-call-iptables = 0 in /etc/sysctl.conf und Reflektieren Sie die Einstellungen.

 cat /etc/sysctl.conf
 sysctl settings are defined through files in
 /usr/lib/sysctl.d/, /run/sysctl.d/, and /etc/sysctl.d/.

 Vendors settings live in /usr/lib/sysctl.d/.
 To override a whole file, create a new file with the same in
 /etc/sysctl.d/ and put new settings there. To override
 only specific settings, add a file with a lexically later
 name in /etc/sysctl.d/ and put new settings there.

 For more information, see sysctl.conf(5) and sysctl.d(5).
net.bridge.bridge-nf-call-iptables = 0

 sysctl -p 
net.bridge.bridge-nf-call-iptables = 0

 sysctl net.bridge.bridge-nf-call-iptables
net.bridge.bridge-nf-call-iptables = 0

Teil 2 Nehmen Sie Berechtigungseinstellungen für iptables vor

Bridge Netfilter bezieht sich auf iptables zur Steuerung der Kommunikation. Fügen Sie daher die Berechtigungsregel wie folgt zu iptables hinzu Sie können über die Linux Bridge kommunizieren. Wenn Sie mit dem Befehl iptables eine Regel hinzufügen, indem Sie ein Paketvergleichsmodul namens physdev angeben, das die Eingabe und Ausgabe der Bridge mit -m verwaltet, wird die gesamte Kommunikation über Brige zugelassen.

iptables - Beschreibung der Systemverwaltungsbefehle - Liste der Linux-Befehle https://kazmax.zpp.jp/cmd/i/iptables.8.html

 iptables -I FORWARD -m physdev --physdev-is-bridged -j ACCEPT

 iptables -nvL --line-number
Chain INPUT (policy ACCEPT 52 packets, 3250 bytes)
num   pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy DROP 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            PHYSDEV match --physdev-is-bridged
2     2006 2508K DOCKER-USER  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
3     2006 2508K DOCKER-ISOLATION-STAGE-1  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
4     1126 2451K ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
5       46  5840 DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0           
6      834 51247 ACCEPT     all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0           
7       46  5840 ACCEPT     all  --  docker0 docker0  0.0.0.0/0            0.0.0.0/0           

 (Weggelassen)

In kubernetes wird angegeben, dass net.bridge.bridge-nf-call-iptables = 1 ist. Weil ich bei der folgenden Validierung mit Kubernetes auf dieses Problem gestoßen bin Unterstützung für iptables-Regeln hinzugefügt.

Spielen Sie mit Multus https://rheb.hatenablog.com/entry/multus_introduction

Warum kann Kommunikation über docker0 möglich sein?

An dieser Stelle stellt sich eine Frage: "Warum kann Docker0 kommunizieren, obwohl es sich tatsächlich um dieselbe Linux Bridge handelt?" Die Antwort liegt in den Einstellungen von iptables. Docker scheint die Regeln beschrieben zu haben, die für die Installation und die Erstellung des Docker-Netzwerks in iptables erforderlich sind. Wenn Sie die Einstellungsinformationen von iptables überprüfen, können Sie sehen, dass die Kommunikation von Docker0 nach außen und die Kommunikation über Docker0 in den FRWARD-Ketten Nr. 5 und 6 AKZEPTIERT sind. Darüber hinaus legt Docker auch NAT für iptables fest.

 iptables -nvL --line-number
Chain INPUT (policy ACCEPT 228K packets, 579M bytes)
num   pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy DROP 12 packets, 1008 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1     9003   12M DOCKER-USER  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
2     9003   12M DOCKER-ISOLATION-STAGE-1  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
3     5650   12M ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
4        0     0 DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0           
5     3341  191K ACCEPT     all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0           
6        0     0 ACCEPT     all  --  docker0 docker0  0.0.0.0/0            0.0.0.0/0           

Chain OUTPUT (policy ACCEPT 130K packets, 7700K bytes)
num   pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER (1 references)
num   pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER-ISOLATION-STAGE-1 (1 references)
num   pkts bytes target     prot opt in     out     source               destination         
1     3341  191K DOCKER-ISOLATION-STAGE-2  all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0           
2     9003   12M RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain DOCKER-ISOLATION-STAGE-2 (1 references)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 DROP       all  --  *      docker0  0.0.0.0/0            0.0.0.0/0           
2     3341  191K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain DOCKER-USER (1 references)
num   pkts bytes target     prot opt in     out     source               destination         
1     9003   12M RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0  

Zusammenfassung

Wenn Sie Linux Bridge verwenden, sollte es nur auf der L2-Ebene funktionieren, daher dachte ich, dass ich in der Lage sein sollte, zu kommunizieren, ohne mir um irgendetwas Sorgen zu machen, aber es war ein Fehler. Linux Bridge funktioniert auch wie L3, einschließlich der Möglichkeit, IP zuzuweisen. Dieses Mal habe ich mit einem Container experimentiert, aber ich gehe davon aus, dass dieses Beispiel das gleiche Problem beim Zuweisen einer virtuellen KVM-Maschine lösen kann. (Nicht verifiziert)

Vielen Dank

Bei der Durchführung dieser Umfrage erhielten wir verschiedene Umfragekooperationen und Konsultationen von den Menschen um uns herum. Ich möchte diesen Fall annehmen und mich bei Ihnen bedanken.

Referenz

KVM-Bridge-Netzwerkeinstellungen https://qiita.com/TsutomuNakamura/items/e15d2c8c02586a7ae572#bridge-%E3%83%88%E3%83%A9%E3%83%95%E3%82%A3%E3%83%83%E3%82%AF%E3%81%AEnetfilter-%E3%82%92%E7%84%A1%E5%8A%B9%E5%8C%96%E3%81%99%E3%82%8B

11.2. Brückennetzwerk mit libvirt https://docs.fedoraproject.org/ja-JP/Fedora/13/html/Virtualization_Guide/sect-Virtualization-Network_Configuration-Bridged_networking_with_libvirt.html

Recommended Posts

Kann nicht über Linux Bridge kommunizieren
[Windows] RDP zu Windows über Linux