3

背景

我正在尝试在几个长生不老药节点之间设置集群。我的理解是我可以通过修改release vm.args来设置它。我正在使用 Distillery 构建版本,并遵循此处的文档:https ://hexdocs.pm/distillery/config/runtime.html 。

我的 rel/vm.args 文件如下:

-name <%= release_name %>@${HOSTNAME}
-setcookie <%= release.profile.cookie %>
-smp auto
-kernel inet_dist_listen_min 9100 inet_dist_listen_max 9155
-kernel sync_nodes_mandatory '[${SYNC_NODES_MANDATORY}]'

我有一个运行 Ubuntu 18.04 的构建服务器和两个运行 Ubuntu 18.04 的网络服务器。我正在构建服务器上构建版本,将存档复制到网络服务器,然后取消存档并从那里开始。

在服务器上,两个 vm.args 文件计算为:

-name hifyre_platform@10.10.10.100
-setcookie wefijow89236wj289*PFJ#(*98j3fj()#J()#niof2jio
-smp auto
-kernel inet_dist_listen_min 9100 inet_dist_listen_max 9155
-kernel sync_nodes_mandatory '["\'my_app@10.10.10.100\'","\'my_app@10.10.10.200\'"]'

-name hifyre_platform@10.10.10.200
-setcookie wefijow89236wj289*PFJ#(*98j3fj()#J()#niof2jio
-smp auto
-kernel inet_dist_listen_min 9100 inet_dist_listen_max 9155
-kernel sync_nodes_mandatory '["\'my_app@10.10.10.100\'","\'my_app@10.10.10.200\'"]'

这些版本通过 systemd 运行,配置如下:

[Unit]
Description=My App
After=network.target

[Service]
Type=simple
User=ubuntu
Group=ubuntu
WorkingDirectory=/opt/app
ExecStart=/opt/app/bin/my_app foreground
Restart=on-failure
RestartSec=5
Environment=PORT=8080
Environment=LANG=en_US.UTF-8
Environment=REPLACE_OS_VARS=true
Environment=HOSTNAME=10.10.10.100
SyslogIdentifier=my_app
RemainAfterExit=no

[Install]
WantedBy=multi-user.target

问题

两个服务器上的发布都很好,但是当我打开远程控制台并运行时Node.list(),结果是一个空列表,除非我手动连接两个节点。

如果我手动运行,Node.connect(:"my_app@10.10.10.200")我会在每个节点上运行时看到另一个节点Node.list(),但这不会在启动时自动发生。

4

2 回答 2

4

该文件最终使用参数vm.args传递给 Erlang 。-args_file我去看了的文档-args_file,发现它实际上并没有很好的记录。事实证明这vm.args就像一个洋葱,因为它有很多层,并且文档似乎都在源代码中。

让我们从我们想要结束的地方开始。我们想sync_nodes_mandatory成为一个原子列表,我们需要用 Erlang 语法来编写它。如果我们使用短节点名称,例如my_app@myhost,我们可以不引用原子,但其中带有点的原子需要使用单引号引用:

['my_app@10.10.10.100','my_app@10.10.10.200']

我们希望这是函数build_args_from_stringinerlexec.c的输出。这个函数有四个规则:

  • 反斜杠字符转义任何一个字符
  • 双引号转义所有字符(包括反斜杠),直到下一个双引号
  • 单引号转义所有字符(包括反斜杠),直到下一个单引号
  • 空格字符标记参数的结束

因此,由于我们想将单引号传递给解析器,我们有两种选择。我们可以转义单引号:

[\'my_app@10.10.10.100\',\'my_app@10.10.10.200\']

或者我们可以将单引号括在双引号中:

["'my_app@10.10.10.100','my_app@10.10.10.200'"]

(事实上​​,我们放置双引号的数量和位置无关紧要,只要单引号的每次出现都在一对双引号内。这只是一种可能的方法。)

但是如果我们选择用反斜杠转义单引号,我们会遇到另一层! 该函数read_args_file是在将vm.args文件传递给之前实际从磁盘读取文件的函数,build_args_from_string它首先施加自己的规则!即:

  • 反斜杠字符转义任何一个字符
  • 一个#字符忽略所有字符,直到下一个换行符
  • 除非用反斜杠转义,否则任何空白字符都将替换为单个空格

因此,如果我们写入[\'my_app@10.10.10.100\',\'my_app@10.10.10.200\'],会吃掉反斜杠,吃掉单引号,给我们留下一个无效的术语和一个错误:vm.argsread_args_filebuild_args_from_string

$ iex --erl '-args_file /tmp/vm.args'
2019-04-25 17:00:02.966277 application_controller: ~ts: ~ts~n
    ["syntax error before: ","'.'"]
    "[my_app@10.10.10.100,my_app@10.10.10.200]"
{"could not start kernel pid",application_controller,"{bad_environment_value,\"[my_app@10.10.10.100,my_app@10.10.10.200]\"}"}
could not start kernel pid (application_controller) ({bad_environment_value,"[my_app@10.10.10.100,my_app@10.10.10.200]"})

Crash dump is being written to: erl_crash.dump...done

所以我们可以使用双反斜杠:

-kernel sync_nodes_mandatory [\\'my_app@10.10.10.100\\',\\'my_app@10.10.10.200\\']

或者只是坚持使用双引号(这次是一个不同的、同样有效的变体):

-kernel sync_nodes_mandatory "['my_app@10.10.10.100','my_app@10.10.10.200']"

应用程序文档中所述kernel,您还需要设置sync_nodes_timeout以毫秒为单位的时间或infinity

指定此节点等待强制节点和可选节点启动的时间(以毫秒为单位)。如果未定义此参数,则不执行节点同步。

添加类似:

-kernel sync_nodes_timeout 10000
于 2019-04-25T16:05:28.770 回答
1

这是一个替代解决方案。我在调查这个问题时发现了它。

创建./priv/sync.config具有以下内容的文件:

[{kernel, [
  {sync_nodes_mandatory, ['my_app@10.10.10.200', 'my_app@10.10.10.200']},
  {sync_nodes_timeout, 15000}
]}].

将此行添加到vm.args

-config <%= :code.priv_dir(release_name) %>/sync

构建一个版本并在 15 秒内启动两个节点(配置文件中的超时值),并附加控制台。执行Node.list()验证。

现在您可能会考虑在构建版本时生成此配置文件。

于 2019-04-25T18:58:02.007 回答