一尘不染

为什么Dockerized Hadoop数据节点注册了错误的IP地址?

java

我为Hadoop(2.7.1)名称节点和数据节点分别设置了Docker(1.9.1)映像。我可以从这些容器中创建容器,并使它们通过用户定义的Docker网络进行通信。但是,datanode似乎报告自己具有网络网关的IP地址,而不是其自己的IP地址。虽然这不会对单个数据节点造成任何问题,但是在添加其他数据节点时,仍然会引起混乱。它们都使用相同的IP地址注册,并且名称节点在它们之间翻转,仅报告单个数据节点处于活动状态。

在用户定义的Docker网络上运行时,为什么服务器(名称节点)从客户端(数据节点)套接字连接中读取错误的IP地址,我该如何解决?

更新:此问题似乎在Docker方面

运行两个容器--net=bridge并执行一个netcat服务器:

nc -v -l 9000

在一个容器中,在另一个容器中,一个netcat客户端:

nc 172.17.0.2 9000

使第一个容器正确打印:

接受来自 **172.17.0.3** 端口9000 [tcp / 9000]的连接

但是创建一个用户定义的网络:

sudo docker network create --driver bridge test

并在以--net=test错误开头的容器中执行相同的命令会错误打印网关/用户定义的网络接口的IP地址:

接受来自 **172.18.0.1** 端口9000 [tcp / 9000]的连接

HDFS / Docker详细信息

dfs.datanode.address每个数据节点hdfs-site.xml文件中的属性均设置为其主机名(例如hdfs- datanode-1)。

网络是这样创建的:

sudo docker network create --driver bridge hadoop-network

namenode像这样开始:

sudo docker run -d \
                --name hdfs-namenode \
                -v /hdfs/name:/hdfs-name \
                --net=hadoop-network \
                --hostname hdfs-namenode \
                -p 50070:50070 \
                hadoop:namenode

并且datanode像这样开始:

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

两个节点连接良好,当查询(使用sudo docker exec hdfs-namenode hdfs dfsadmin -report)时,连接性报告为:

...
实时数据节点(1):

名称: **172.18.0.1** :50010(172.18.0.1)
主机名: **hdfs-datanode-1**
...

但是,正在运行的输出:

 sudo docker exec hdfs-namenode cat /etc/hosts

表示namenode认为它正在运行,172.18.0.2而datanode在以下运行172.18.0.3

**172.18.0.2 hdfs-namenode**
127.0.0.1本地主机
:: 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

并且datanode上的等效项显示相同:

**172.18.0.3 hdfs-datanode-1**
127.0.0.1本地主机
:: 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

ip route两者都运行可以确认:

sudo docker exec hdfs-namenode ip route



默认通过172.18.0.1 dev eth0
172.18.0.0/16 dev eth0原始内核作用域链接   **src 172.18.0.2**



sudo docker exec hdfs-datanode-1 ip route



默认通过172.18.0.1 dev eth0
172.18.0.0/16 dev eth0原始内核作用域链接src **172.18.0.3**

然而,当数据节点启动时,名称节点将数据节点的IP地址报告为172.18.0.1

... INFO hdfs.StateChange:BLOCK * registerDatanode:来自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)存储3abaf40c-4ce6-47e7-be2b-fbb4a7eba0e3
... INFO blockmanagement.DatanodeDescriptor:失败的存储数量从0更改为0
... INFO net.NetworkTopology:添加新节点:/默认机架/ **172.18.0.1** :50010
... INFO blockmanagement.DatanodeDescriptor:失败的存储数量从0更改为0
... INFO blockmanagement.DatanodeDescriptor:为DN **172.18.0.1:50010** 添加新的存储ID DS-4ba1a710-a4ca-4cad-8222- cc5f16c213fb
... INFO BlockStateChange:BLOCK *过程报告:来自存储DS-4ba1a710-a4ca-4cad-8222-cc5f16c213fb节点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),块:1,hasStaleStorage:false,处理时间:3毫秒

并且使用tcpdump捕获两者之间的流量(在连接到主机网络的Docker容器中运行-使用docker run --net=host)似乎表明发生了错误(br-b59d498905c5是Docker为Docker创建的网络接口的名称hadoop- 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)"

IP地址似乎在registerDatanode呼叫中正确发送:

...
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 atanode协议。
    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 **6ode** 3430   **1。** $ 3abaf40c-
    ...

但是在随后的通话中这是不正确的。例如,在sendHeartbeat通话之后一秒钟的时间:

...
172.18.0.3.33987> 172.18.0.2.9000:...
    ...
    0x0050:f828 004a 0a0d 7365 6e64 4865 6172 7462 .... 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
    ...

通过datanode代码进行的调试清楚地显示了根据namenode返回的信息更新datanode注册详细信息BPServiceActor.register()时发生的错误:

bpRegistration = bpNamenode.registerDatanode(bpRegistration);

调试namenode 表示它从datanode套接字连接中读取了
错误的 IP地址,并更新了datanode注册详细信息。

补充笔记

我可以在用户定义的Docker网络上运行以下代码来重现该问题:

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());
    }
}

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);
    }
}

与这两个ServerClient运行在172.18.0.2这个正确的输出172.18.0.2,但与Client上运行172.18.0.3它错误地输出172.18.0.1

在不使用用户定义的网络的情况下运行相同的代码(在默认的bridge网络/ docker0接口上并公开port 9000)可以提供正确的输出。

我在namenode的文件中将dfs.namenode.datanode.registration.ip-hostname- check属性设置为falsehdfs- site.xml以防止反向DNS查找错误。如果我可以使用DNS,那么将来可能不需要这样做,但是现在,由于数据节点报告了错误的IP地址,我怀疑使用DNS会有所帮助。

我相信相关的有线协议registerDatanodesendHeartbeat并且blockReport都是RegisterDatanodeRequestProtoHeartbeatRequestProto而且BlockReportRequestProto他们的定义可以在这里找到。这些都包含DatanodeRegistrationProto为其第一个数据成员。此消息在此处定义,如下所示:

/**
 * Identifies a Datanode
 */
message DatanodeIDProto {
  required string ipAddr = 1;    // IP address
  required string hostName = 2;  // hostname
  ...
}

阅读 284

收藏
2020-12-03

共1个答案

一尘不染

这是由一个已知的docker问题引起的(我也提出了并关闭了此重复描述了问题中所述步骤的副本)。

有一个合并的拉取请求可以解决此问题,并已计划将其包含在Docker
1.10.0中。但是与此同时,可以使用以下解决方法:

  1. 使用以下命令删除所有用户创建的网络 sudo docker network rm
  2. 使用以下命令停止docker守护进程 sudo service docker stop
  3. 用清理iptables sudo iptables -F && sudo iptables -F -t nat
  4. 重新启动docker守护进程 sudo service docker start
  5. 重新创建用户定义的网络
  6. 运行容器
2020-12-03