Как заставить узлы эликсира автоматически подключаться при запуске? - PullRequest
2 голосов
/ 25 апреля 2019

Фон

Я пытаюсь настроить кластеризацию между несколькими узлами эликсира.Насколько я понимаю, я могу настроить это, изменив релиз 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() я вижу другой узелна каждом узле, но это не происходит автоматически при запуске.

Ответы [ 2 ]

3 голосов
/ 25 апреля 2019

Файл vm.args заканчивается передачей Эрлангу с помощью аргумента -args_file.Я посмотрел на документацию для -args_file и обнаружил, что она на самом деле не очень хорошо документирована.Оказывается, что vm.args похоже на лук в том смысле, что в нем много слоев, и документация, похоже, полностью в исходном коде.

Давайте начнем с того, что нам нужно в итоге.Мы хотим, чтобы sync_nodes_mandatory был списком атомов, и нам нужно написать его в синтаксисе Эрланга.Если бы мы использовали короткие имена узлов, например my_app@myhost, мы могли бы не заключать в кавычки атомы, но атомы с точками в них нужно заключать в кавычки, используя одинарные кавычки:

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

Мы хотим, чтобы этобыть выводом функции build_args_from_string в erlexec.c.Эта функция имеет четыре правила:

  • Символ обратной косой черты экранирует любой один символ
  • Двойная кавычка экранирует все символы (включая обратную косую черту) до следующей двойной кавычки
  • Aодинарная кавычка экранирует все символы (включая обратную косую черту) до следующей одинарной кавычки
  • Пробел отмечает конец аргумента

Так как мы хотим передать одинарные кавычки допарсер, у нас есть две альтернативы.Мы можем избежать одинарных кавычек:

[\'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, и сначала она устанавливает свои собственные правила!А именно:

  • Символ обратной косой черты экранирует любой один символ
  • A # Символ игнорирует все символы до следующей новой строки
  • Любой символ пробела заменяется однимпробел, если не избежать обратной косой черты

Так что, если бы мы написали [\'my_app@10.10.10.100\',\'my_app@10.10.10.200\'] в vm.args, 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']"

Как указано в документации для kernel приложения , вам также необходимо установить sync_nodes_timeout для времени в миллисекундах или infinity:

Указывает время (в миллисекундах), в течение которого этот узел ожидает запуска обязательных и необязательных узлов.Если этот параметр не определен, синхронизация узлов не выполняется.

Добавить что-то вроде:

-kernel sync_nodes_timeout 10000
1 голос
/ 25 апреля 2019

Вот альтернативное решение.Я нашел его при исследовании этой проблемы.

Создать файл ./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() для проверки.

Теперь вы можете подумать о создании этого файла конфигурации при создании релиза.

...