如何让 elixir 节点在启动时自动连接?
How to get elixir nodes to connect automatically on startup?
背景
我正在尝试在几个 elixir 节点之间设置集群。我的理解是我可以通过修改发布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}]'
我有一个构建服务器 运行ning Ubuntu 18.04 和两个网络服务器 运行ning 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()
时看到另一个节点,但这不会在启动时自动发生。
vm.args
文件最终使用 -args_file
参数传递给 Erlang。我去看了 the documentation for -args_file
,发现它实际上没有很好的文档记录。原来vm.args
就像洋葱一样,层次很多,文档好像都在源码里面
让我们从我们想要结束的地方开始吧。我们希望 sync_nodes_mandatory
是一个原子列表,我们需要用 Erlang 语法来编写它。如果我们使用短节点名称,例如my_app@myhost
,我们可以不用引用原子,但是带点的原子需要用单引号引用:
['my_app@10.10.10.100','my_app@10.10.10.200']
我们希望这是 the function build_args_from_string
in erlexec.c
的输出。这个函数有四个规则:
- 反斜杠字符转义任何一个字符
- 双引号转义所有字符(包括反斜杠)直到下一个双引号
- 单引号转义所有字符(包括反斜杠)直到下一个单引号
- 一个space字符标记一个参数的结束
既然我们想将单引号传递给解析器,我们有两种选择。我们可以转义单引号:
[\'my_app@10.10.10.100\',\'my_app@10.10.10.200\']
或者我们可以用双引号将单引号引起来:
["'my_app@10.10.10.100','my_app@10.10.10.200'"]
(事实上,双引号的数量和位置并不重要,只要每次出现的单引号都在一对双引号内即可。这只是一种可能的实现方式.)
BUT 如果我们选择用反斜杠转义单引号,我们会遇到另一层! The function read_args_file
是在将 vm.args
文件传递给 build_args_from_string
之前实际从磁盘读取文件的函数,它首先强加了自己的规则!即:
- 反斜杠字符转义任何一个字符
- 一个
#
字符忽略所有字符直到下一个换行符
- 任何白色space字符都被单个space替换,除非用反斜杠
转义
所以如果我们在 vm.args
中写 [\'my_app@10.10.10.100\',\'my_app@10.10.10.200\']
,read_args_file
会吃掉反斜杠,而 build_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']"
如 the documentation for the kernel
application 所述,您还需要将 sync_nodes_timeout
设置为以毫秒为单位的时间或 infinity
:
Specifies the time (in milliseconds) that this node waits for the mandatory and optional nodes to start. If this parameter is undefined, no node synchronization is performed.
添加如下内容:
-kernel sync_nodes_timeout 10000
这是一个替代解决方案。我在调查这个问题的时候发现的。
创建包含以下内容的文件 ./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()
验证。
现在您可以考虑在构建版本时生成此配置文件。
背景
我正在尝试在几个 elixir 节点之间设置集群。我的理解是我可以通过修改发布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}]'
我有一个构建服务器 运行ning Ubuntu 18.04 和两个网络服务器 运行ning 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()
时看到另一个节点,但这不会在启动时自动发生。
vm.args
文件最终使用 -args_file
参数传递给 Erlang。我去看了 the documentation for -args_file
,发现它实际上没有很好的文档记录。原来vm.args
就像洋葱一样,层次很多,文档好像都在源码里面
让我们从我们想要结束的地方开始吧。我们希望 sync_nodes_mandatory
是一个原子列表,我们需要用 Erlang 语法来编写它。如果我们使用短节点名称,例如my_app@myhost
,我们可以不用引用原子,但是带点的原子需要用单引号引用:
['my_app@10.10.10.100','my_app@10.10.10.200']
我们希望这是 the function build_args_from_string
in erlexec.c
的输出。这个函数有四个规则:
- 反斜杠字符转义任何一个字符
- 双引号转义所有字符(包括反斜杠)直到下一个双引号
- 单引号转义所有字符(包括反斜杠)直到下一个单引号
- 一个space字符标记一个参数的结束
既然我们想将单引号传递给解析器,我们有两种选择。我们可以转义单引号:
[\'my_app@10.10.10.100\',\'my_app@10.10.10.200\']
或者我们可以用双引号将单引号引起来:
["'my_app@10.10.10.100','my_app@10.10.10.200'"]
(事实上,双引号的数量和位置并不重要,只要每次出现的单引号都在一对双引号内即可。这只是一种可能的实现方式.)
BUT 如果我们选择用反斜杠转义单引号,我们会遇到另一层! The function read_args_file
是在将 vm.args
文件传递给 build_args_from_string
之前实际从磁盘读取文件的函数,它首先强加了自己的规则!即:
- 反斜杠字符转义任何一个字符
- 一个
#
字符忽略所有字符直到下一个换行符 - 任何白色space字符都被单个space替换,除非用反斜杠 转义
所以如果我们在 vm.args
中写 [\'my_app@10.10.10.100\',\'my_app@10.10.10.200\']
,read_args_file
会吃掉反斜杠,而 build_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']"
如 the documentation for the kernel
application 所述,您还需要将 sync_nodes_timeout
设置为以毫秒为单位的时间或 infinity
:
Specifies the time (in milliseconds) that this node waits for the mandatory and optional nodes to start. If this parameter is undefined, no node synchronization is performed.
添加如下内容:
-kernel sync_nodes_timeout 10000
这是一个替代解决方案。我在调查这个问题的时候发现的。
创建包含以下内容的文件 ./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()
验证。
现在您可以考虑在构建版本时生成此配置文件。