在内部和外部IP地址正在运行时连接Erlang节点

时间:2014-10-20 20:44:10

标签: erlang

我有两台虚拟机使用内部IP地址互相交谈,而外界只通过外部IP地址了解这些虚拟机。

我有一个使用两个VM的分布式缓存 - 每个都有一个必须与另一个进行通信的Erlang节点。我在其他机器上拥有现金的Erlang客户端,需要与VM上的一个(或两个)Erlang缓存节点进行通信。

因此,如果我使用内部IP地址命名的缓存节点,那么它们可以相互通信,但没有其他Erlang节点可以与它们交互。但是,如果我使用VM的外部IP地址命名缓存节点,那么外部Erlang节点可以与缓存节点通信,但缓存节点不能相互通信。

除了使用不依赖于将节点连接到网格的基于http或套接字的接口之外,我能做些什么吗?

2 个答案:

答案 0 :(得分:10)

你想要达到的目标是绝对可行

预赛

Erlang的分发地址分为两部分:节点名称和主机名。它们由@符号分隔。

主机名可以是数字IPv4地址。它们也可以是域名。有两种不同的模式,其中主机名很短(单个词,例如vm1),它们很长(几个词,例如vm1.domain.com)。 IP地址是长名称。以一种模式(短或长)启动的节点只能与以相同模式启动的节点通信。节点也受cookie保护:节点只接受带有匹配cookie的传入连接。最简单的方法是使用相同的cookie启动给定集群的所有节点。

当Erlang节点尝试连接到另一个Erlang节点时,它需要找到远程节点的IP地址。如果它与它自己相同,它将只是尝试连接本地主机。如果不同,它将尝试将此主机名解析为IP地址。

然后它将连接到该主机上的epmd守护进程,以告知Erlang正在运行哪个端口。 epmd以及Erlang节点监听所有接口(默认情况下)。

解决方案和示例

基于此机制,您可以使用短名称或长名称,但可以利用解析机制。 Unix上最简单的方法是在你机器的每个/etc/hosts上配置不同的IP(特别是在两台虚拟机上),这样它们就可以通过私有地址相互连接,同时通过公共地址访问。

假设虚拟机A(VM A)具有私有IP地址10.0.0.2,公共IP地址123.4.5.2,VM B具有私有IP地址10.0.0.3和公共IP地址123.4.5.3。我们也说你决定选择短名。

您可以在/etc/hosts

中输入此条目的VM A.
10.0.0.3 vmb

您可以将匹配条目放在VM B的/etc/hosts

10.0.0.2 vma

在所有外部客户端上,您可以输入:

123.4.5.2 vma
123.4.5.3 vmb

您可以按如下方式启动节点:

# Node foo on VM A:
erl -sname foo@vma -cookie RANDOMCOOKIE
# Node foo on VM B:
erl -sname foo@vmb -cookie RANDOMCOOKIE
# Client nodes:
erl -sname client -cookie RANDOMCOOKIE

如果您拥有域名(例如/etc/hosts),则可以避免在客户端节点上进行yourdomain.com编辑,并且可以让vma.yourdomain.com解析为123.4.5.2。您还可以使用特定的Erlang Inet configuration file

安全

Erlang分发机制并不意味着面向公众。此外,所有通信都是未加密的。我强烈建议在每台主机上配置防火墙,只允许来自其他群集服务器的连接和使用SSL分发

对于防火墙:Erlang发行版为epmd使用端口4369以及每个节点使用随机端口。您可以使用Erlang内核应用程序环境设置inet_dist_listen_mininet_dist_listen_max来限制这些随机端口的范围。您将需要允许这些端口上的传入TCP连接,但仅允许来自群集的其他主机。

SSL分发设置非常复杂,但well documented。您的主要缺点是所有连接都应该通过SSL,包括其专用网络上的两个虚拟机之间的连接,以及打开远程shell的本地连接。

答案 1 :(得分:3)

在回答问题之前,我想指出,Distributed Erlang不安全,您不应在受信任的局域网之外使用它。 (在我看到"外部IP地址"后,我不得不离开那个评论,我认为它并不意味着公开)。下面列出了4个重要的事项,你应该知道:

  1. IP地址是节点名称的一部分。
  2. 当你启动一个节点时,最好给它一个这样的名字:

    erl -name myname@192.168.0.1
    

    当您尝试从其他计算机连接到该节点时,您可以在erlang shell中使用类似的内容:

    net_kernel:connect('myname@192.168.0.1').
    

    重要的部分是节点名称:'myname@192.168.0.1'是一个原子。它不是" name和ip" - 这是一回事。即使如果您的第二个节点在同一台机器上,也无法使用:

    net_kernel:connect('myname@127.0.0.1').
    

    因为它是不同的节点名称。

    1. 连接位于TCP
    2. 之上

      这意味着,要连接两个节点,只有一个节点必须看到另一个节点。

      示例:您有:

      • 具有外部IP地址的计算机上的一个节点(客户端)和
      • 具有内部IP地址(缓存节点)的计算机上的一个节点

      比:

      • 您无法从客户端连接到缓存节点(因为它无法看到该IP地址)
      • 可以从缓存节点连接到客户端(因为缓存节点看到客户端的外部ip),连接是双向的!

      在第二种情况下,连接就像它们在同一网络上一样。您只需要考虑谁应该初始化连接。

      1. 当您将新节点连接到现有群集时,它会尝试连接到所有其他节点。
      2. 如果您不想这样做 - 请使用hidden nodes

        1. 确保您在任何地方使用相同的Erlang cookie。
        2. 但我认为,如果你能够连接其他节点,那么你就可以了。

          最简单的解决方案是在任何地方使用外部IP地址,因为Erlang发行版旨在在本地网络上运行。更难的解决方案涉及确保您从本地网络中的节点连接到具有外部IP的节点。