【问题标题】:Connecting Erlang nodes when an internal and external IP address are at play在使用内部和外部 IP 地址时连接 Erlang 节点
【发布时间】:2014-12-15 23:07:02
【问题描述】:

我有两台虚拟机使用内部 IP 地址相互通信,而外界仅通过外部 IP 地址知道这些虚拟机。

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

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

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

【问题讨论】:

  • 我认为你的问题更多是关于虚拟网络而不是 erlang。尝试编辑您的问题,更详细地解释所涉及的拓扑,包括您所在的 VM 环境,并添加诸如“虚拟化”和“网络”之类的标签。

标签: erlang


【解决方案1】:

在回答问题之前,我想指出,Distributed Erlang 不安全,您不应该在受信任的局域网之外使用它。 (在看到“外部 IP 地址”后,我不得不留下该评论,我认为这并不意味着公开)。以下是您应该注意的 4 个重要事项的列表:

  1. IP 地址是节点名称的一部分。

当你启动一个节点时,最好给它起这样的名字:

erl -name myname@192.168.0.1

当您尝试从其他机器连接到该节点时,您可以在 erlang shell 中使用类似这样的东西:

net_kernel:connect('myname@192.168.0.1').

重要的部分是节点名称:'myname@192.168.0.1' 是一个原子。它不是“名称和 ip”——它是一回事。即使你的第二个节点在同一台机器上,你也不能使用:

net_kernel:connect('myname@127.0.0.1').

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

  1. 连接在 TCP 之上

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

例子:你有:

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

比:

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

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

  1. 当您将新节点连接到现有集群时,它会尝试连接到所有其他节点。

如果您不想这样做,请使用hidden nodes

  1. 确保在任何地方都使用相同的 Erlang cookie。

但我认为,如果您能够连接其他节点,您已经涵盖了这一点。

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

【讨论】:

    【解决方案2】:

    您想要实现的目标绝对可行

    预赛

    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。假设您决定使用简称。

    您可以在 VM A 上添加 /etc/hosts 中的此条目:

    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
    

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

    安全

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 2011-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-27
      • 2015-08-14
      相关资源
      最近更新 更多