Warum registriert sich der Dockerized Hadoop-Datenknoten mit der falschen IP-Adresse?
Ich habe separate Docker (1.9.1) Images für Hadoop (2.7.1) -Namen- und -Datenknoten. Ich kann daraus Container erstellen und diese über ein benutzerdefiniertes Docker-Netzwerk kommunizieren lassen. Der Datenknoten scheint sich jedoch als IP-Adresse des Netzwerk-Gateways und nicht als eigene IP-Adresse zu melden. Während dies keine Probleme mit einem einzelnen Datenknoten verursacht, herrscht Verwirrung, wenn zusätzliche Datenknoten hinzugefügt werden. Sie alle registrieren sich mit derselben IP-Adresse, und der Namensknoten wechselt zwischen ihnen und meldet immer nur, dass ein einzelner Datenknoten aktiv ist.
Warum liest der Server (namenode) die falsche IP-Adresse von der Client-Socket-Verbindung (datanode), wenn er über ein benutzerdefiniertes Docker-Netzwerk ausgeführt wird, und wie kann ich dies beheben?
Update: Dieses Problem scheint auf der Docker-Seite zu liegen
Running zwei Container mit--net=bridge
und Ausführen eines Netcat-Servers:
nc -v -l 9000
in einem Container und einem Netcat-Client im anderen:
nc 172.17.0.2 9000
bewirkt, dass der erste Container korrekt gedruckt wird:
Connection from 172.17.0.3 port 9000 [tcp/9000] accepted
Aber ein benutzerdefiniertes Netzwerk erstellen:
sudo docker network create --driver bridge test
und Ausführen der gleichen Befehle in Containern, die mit @ gestartet wurd--net=test
druckt die IP-Adresse des Gateways / der benutzerdefinierten Netzwerkschnittstelle falsch aus:
Connection from 172.18.0.1 port 9000 [tcp/9000] accepted
HDFS / Docker Details
Dasdfs.datanode.address
Eigenschaft in jedem @ des Datenknotehdfs-site.xml
ie Datei @ wird auf ihren Hostnamen gesetzt (z. B.hdfs-datanode-1
).
Das Netzwerk wird folgendermaßen erstellt:
sudo docker network create --driver bridge hadoop-network
Der namenode hat so angefangen:
sudo docker run -d \
--name hdfs-namenode \
-v /hdfs/name:/hdfs-name \
--net=hadoop-network \
--hostname hdfs-namenode \
-p 50070:50070 \
hadoop:namenode
Und der Datenknoten begann folgendermaßen:
sudo docker run -d \
--name hdfs-datanode-1 \
-v /hdfs/data_1:/hdfs-data \
--net=hadoop-network \
--hostname=hdfs-datanode-1 \
--restart=always \
hadoop:datanode
Die beiden Knoten verbinden sich gut und wenn abgefragt wird (mitsudo docker exec hdfs-namenode hdfs dfsadmin -report
) Die Konnektivität wird gemeldet als:
... Live datanodes (1): Name: 172.18.0.1:50010 (172.18.0.1) Hostname: hdfs-datanode-1 ...
Die Ausgabe von running:
sudo docker exec hdfs-namenode cat /etc/hosts
Zeigt an, dass dieser namenode denkt, dass er auf @ läu172.18.0.2
und der Datenknoten läuft auf172.18.0.3
:
172.18.0.2 hdfs-namenode 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.18.0.3 hdfs-datanode-1 172.18.0.3 hdfs-datanode-1.hadoop-network
Und das Äquivalent auf dem Datenknoten zeigt dasselbe:
172.18.0.3 hdfs-datanode-1 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.18.0.2 hdfs-namenode 172.18.0.2 hdfs-namenode.hadoop-network
Laufenip route
an beiden bestätigt dies:
sudo docker exec hdfs-namenode ip route
default via 172.18.0.1 dev eth0 172.18.0.0/16 dev eth0 proto kernel scope link src 172.18.0.2
sudo docker exec hdfs-datanode-1 ip route
default via 172.18.0.1 dev eth0 172.18.0.0/16 dev eth0 proto kernel scope link src 172.18.0.3
Und dennoch meldet der Namensknoten beim Start des Datenknotens die IP-Adresse des Datenknotens als172.18.0.1
:
... INFO hdfs.StateChange: BLOCK* registerDatanode: from DatanodeRegistration(172.18.0.1:50010, datanodeUuid=3abaf40c-4ce6-47e7-be2b-fbb4a7eba0e3, infoPort=50075, infoSecurePort=0, ipcPort=50020, storageInfo=lv=-56;cid=CID-60401abd-4793-4acf-94dc-e8db02b27d59;nsid=1824008146;c=0) storage 3abaf40c-4ce6-47e7-be2b-fbb4a7eba0e3 ... INFO blockmanagement.DatanodeDescriptor: Number of failed storage changes from 0 to 0 ... INFO net.NetworkTopology: Adding a new node: /default-rack/172.18.0.1:50010 ... INFO blockmanagement.DatanodeDescriptor: Number of failed storage changes from 0 to 0 ... INFO blockmanagement.DatanodeDescriptor: Adding new storage ID DS-4ba1a710-a4ca-4cad-8222-cc5f16c213fb for DN 172.18.0.1:50010 ... INFO BlockStateChange: BLOCK* processReport: from storage DS-4ba1a710-a4ca-4cad-8222-cc5f16c213fb node DatanodeRegistration(172.18.0.1:50010, datanodeUuid=3abaf40c-4ce6-47e7-be2b-fbb4a7eba0e3, infoPort=50075, infoSecurePort=0, ipcPort=50020, storageInfo=lv=-56;cid=CID-60401abd-4793-4acf-94dc-e8db02b27d59;nsid=1824008146;c=0), blocks: 1, hasStaleStorage: false, processing time: 3 msecs
Und mittcpdump
, um den Datenverkehr zwischen den beiden zu erfassen (wird in einem Docker-Container ausgeführt, der mit dem Host-Netzwerk verbunden ist - mitdocker run --net=host
) scheint den aufgetretenen Fehler anzuzeigen br-b59d498905c5
ist der Name der Netzwerkschnittstelle, die Docker für das @ erstellt hahadoop-network
):
tcpdump -nnvvXS -s0 -i br-b59d498905c5 \
"(src host 172.18.0.3 or src host 172.18.0.2) and \
(dst host 172.18.0.3 or dst host 172.18.0.2)"
Die IP-Adresse scheint innerhalb des @ korrekt gesendet zu werdregisterDatanode
Anruf
... 172.18.0.3.33987 > 172.18.0.2.9000: ... ... 0x0050: f828 004d 0a10 7265 6769 7374 6572 4461 .(.M..registerDa 0x0060: 7461 6e6f 6465 1237 6f72 672e 6170 6163 tanode.7org.apac 0x0070: 6865 2e68 6164 6f6f 702e 6864 6673 2e73 he.hadoop.hdfs.s 0x0080: 6572 7665 722e 7072 6f74 6f63 6f6c 2e44 erver.protocol.D 0x0090: 6174 616e 6f64 6550 726f 746f 636f 6c18 atanodeProtocol. 0x00a0: 01a7 010a a401 0a51 0a0a 3137 322e 3138 .......Q..172.18 0x00b0: 2e30 2e33 120f 6864 6673 2d64 6174 616e .0.3..hdfs-datan 0x00c0: 6f64 652d 311a 2433 6162 6166 3430 632d ode-1.$3abaf40c- ...
Aber in nachfolgenden Aufrufen ist es falsch. Zum Beispiel imsendHeartbeat
rufe danach einen Sekundenbruchteil an:
... 172.18.0.3.33987 > 172.18.0.2.9000: ... ... 0x0050: f828 004a 0a0d 7365 6e64 4865 6172 7462 .(.J..sendHeartb 0x0060: 6561 7412 376f 7267 2e61 7061 6368 652e eat.7org.apache. 0x0070: 6861 646f 6f70 2e68 6466 732e 7365 7276 hadoop.hdfs.serv 0x0080: 6572 2e70 726f 746f 636f 6c2e 4461 7461 er.protocol.Data 0x0090: 6e6f 6465 5072 6f74 6f63 6f6c 1801 9d02 nodeProtocol.... 0x00a0: 0aa4 010a 510a 0a31 3732 2e31 382e 302e ....Q..172.18.0. 0x00b0: 3112 0f68 6466 732d 6461 7461 6e6f 6465 1..hdfs-datanode 0x00c0: 2d31 1a24 3361 6261 6634 3063 2d34 6365 -1.$3abaf40c-4ce ...
Debugging durch den Datencode zeigt deutlich den Fehler, der auftritt, wenn dasdatanode Registrierungsdetails werden in @ aktualisierBPServiceActor.register()
basierend auf den vom namenode zurückgegebenen Informationen:
bpRegistration = bpNamenode.registerDatanode(bpRegistration);
Debugging the namenodezeigt a dass es das @ liefalsc IP-Adresse von der Datenknoten-Socket-Verbindung und aktualisiert die Datenknoten-Registrierungsdetails.
Zusätzliche Bemerkunge
Ich kann das Problem mit diesem Code reproduzieren, der über ein benutzerdefiniertes Docker-Netzwerk ausgeführt wird:
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws Exception {
// 9000 is the namenode port
ServerSocket server = new ServerSocket(9000);
Socket socket = server.accept();
System.out.println(socket.getInetAddress().getHostAddress());
}
}
un
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception {
// 172.18.0.2 is the namenode IP address
Socket socket = new Socket("172.18.0.2", 9000);
}
}
Mit beidenServer
undClient
Laufen auf172.18.0.2
dies gibt richtig @ a172.18.0.2
aber mitClient
Laufen auf172.18.0.3
es gibt falsch172.18.0.1
.
Den gleichen Code ausführen, ohne ein benutzerdefiniertes Netzwerk zu verwenden (standardmäßigbridge
network /docker0
interface und Port freigeben9000
) gibt die richtige Ausgabe aus.
Ich habedfs.namenode.datanode.registration.ip-hostname-check
Eigenschaft auf @ gesetfalse
im @ des namenodhdfs-site.xml
-Datei, um Reverse-DNS-Lookup-Fehler zu vermeiden. Dies könnte in Zukunft unnötig sein, wenn ich DNS zum Laufen bringe, aber im Moment, wenn die Datenknoten die falsche IP-Adresse melden, würde es wahrscheinlich nicht helfen, DNS zum Laufen zu bringen.
Ich glaube, die relevanten Kabelprotokolle fürregisterDatanode
, sendHeartbeat
undblockReport
sindRegisterDatanodeRequestProto
, HeartbeatRequestProto
undBlockReportRequestProto
undihre Definitionen finden Sie hier. Diese enthalten alleDatanodeRegistrationProto
als erstes Datenelement. Diese Nachricht ist hier definiert und sieht so aus:
/**
* Identifies a Datanode
*/
message DatanodeIDProto {
required string ipAddr = 1; // IP address
required string hostName = 2; // hostname
...
}