mix release
Собирает автономный релиз для текущего проекта:
MIX_ENV=prod mix release MIX_ENV=prod mix release NAME
После сборки релиза его можно упаковать и развернуть на целевой системе, если целевая система работает на той же дистрибуции и версии операционной системы (ОС), что и машина, на которой выполняется команда mix release.
Релиз можно настроить в файле mix.exs по ключу :releases внутри def project.
def project do
[
releases: [
demo: [
include_executables_for: [:unix],
applications: [runtime_tools: :permanent]
],
...
]
]
end
Можно указать несколько релизов, где ключ — это имя релиза, а значение — список ключевых слов с конфигурацией релиза. Выпуск определенного имени выполняется так:
MIX_ENV=prod mix release demo
Если указанного имени не существует, возникает ошибка.
Если вызов mix release без имени и есть несколько имен, будет выведена ошибка, если вы не установите default_release: NAME в корневой части конфигурации вашего проекта.
Если вызов mix release и нет имен, собирается релиз с использованием имени приложения и значениями по умолчанию.
Зачем релизы?
Релизы позволяют разработчикам предварительно компилировать и упаковывать весь свой код и среду выполнения в единый блок. Преимущества релизов:
Предварительная загрузка кода. ВМ имеет два механизма загрузки кода: интерактивный и встроенный. По умолчанию она работает в интерактивном режиме, динамически загружая модули при первом использовании. В первый раз, когда ваше приложение вызывает
Enum.map/2, ВМ найдет модульEnumи загрузит его. Есть недостаток. Когда вы запускаете новый сервер в производстве, ему может потребоваться загрузить много других модулей, что приводит к неожиданному пику времени отклика первых запросов. При работе с Erlang/OTP версии ниже 23 система всегда работает во встроенном режиме. При использовании Erlang/OTP 23+ они работают в интерактивном режиме во время настройки, а затем переключаются на встроенный режим, гарантируя, что ваша система готова обрабатывать запросы после загрузки.Настройка и настройка. Релизы предоставляют разработчикам точный контроль над конфигурацией системы и флагами ВМ, используемыми для запуска системы.
Автономность. Для релиза не требуется включение исходного кода в производственные артефакты. Весь код предварительно скомпилирован и упакован. Релизы даже не требуют Erlang или Elixir на ваших серверах, поскольку они по умолчанию включают Erlang VM и его среду выполнения. Кроме того, стандартные библиотеки Erlang и Elixir усечены, чтобы содержать только те части, которые вы фактически используете.
Несколько релизов. Вы можете собрать разные релизы с различной конфигурацией для каждого приложения или даже для разных приложений.
Сценарии управления. Релизы поставляются со сценариями для запуска, перезапуска, удаленного подключения к работающей системе, выполнения вызовов RPC, запуска в режиме демона, установки как службы Windows и многое другое.
Запуск релиза
После сборки релиза вы можете запустить его, вызвав bin/RELEASE_NAME start внутри релиза. В производстве вы бы сделали так:
MIX_ENV=prod mix release _build/prod/rel/my_app/bin/my_app start
bin/my_app start запустит систему, подключенную к текущему стандартному вводу/выводу, куда также по умолчанию записываются логи. Это предпочтительный способ запуска системы. Многие инструменты, такие как systemd, платформы как услуга, такие как Heroku, и многие платформы контейнеров, такие как Docker, могут обрабатывать стандартный ввод/вывод и перенаправлять содержимое логов в другое место. Эти инструменты и платформы также позаботятся о перезапуске системы в случае сбоя.
Вы также можете выполнить одноразовые команды, запустить релиз в режиме демона на системе Unix-подобной системе или установить его как службу в Windows. Мы рассмотрим эти варианты далее. Вы также можете перечислить все доступные команды, вызвав bin/RELEASE_NAME.
Одноразовые команды (eval и rpc)
Если вы хотите вызвать определенные модули и функции в своем релизе, вы можете сделать это двумя способами: с помощью eval или rpc.
bin/RELEASE_NAME eval "IO.puts(:hello)" bin/RELEASE_NAME rpc "IO.puts(:hello)"
Команда eval запускает свой экземпляр ВМ, но без запуска каких-либо приложений в релизе и без запуска распространения. Например, если вам нужно выполнить некоторые подготовительные работы перед запуском фактической системы, например, миграцию базы данных, eval может подойти. Просто имейте в виду, что любое приложение, которое вы используете во время eval, должно быть явно загружено и/или запущено.
Вы можете запустить приложение, вызвав Application.ensure_all_started/1. Однако, если по какой-то причине вы не можете запустить приложение, возможно, потому что оно запустит другие службы, которые вам не нужны, вы должны хотя бы загрузить приложение, вызвав Application.load/1. Если вы не загрузите приложение, любая попытка чтения его окружения или конфигурации может завершиться неудачей. Обратите внимание, что если вы запускаете приложение, оно автоматически загружается перед запуском.
Другой способ выполнения команд — использование rpc, которое подключится к текущей работающей системе и даст ей указание выполнить данное выражение. Это означает, что вам нужно убедиться, что система уже запущена, и быть осторожным с инструкциями, которые вы выполняете. Вы также можете использовать remote для подключения удаленной сессии IEx к системе.
Вспомогательный модуль
При работе с системой вы можете часто выполнять какой-либо код в виде одноразовой команды. Вы можете рассмотреть возможность создания модуля для группировки этих задач:
# lib/my_app/release_tasks.ex
defmodule MyApp.ReleaseTasks do
def eval_purge_stale_data() do
# Eval commands needs to start the app before
# Or Application.load(:my_app) if you can't start it
Application.ensure_all_started(:my_app)
# Code that purges stale data
...
end
def rpc_print_connected_users() do
# Code that print users connected to the current running system
...
end
end
В примере выше мы добавили в имена функций префикс с именем команды, используемой для их выполнения, но это необязательно.
И для их запуска:
bin/RELEASE_NAME eval "MyApp.ReleaseTasks.eval_purge_stale_data()" bin/RELEASE_NAME rpc "MyApp.ReleaseTasks.rpc_print_connected_users()"
Режим демона (Unix-подобные системы)
Вы можете запустить релиз в режиме демона с помощью команды:
bin/RELEASE_NAME daemon
В режиме демона система запускается в фоновом режиме с помощью run_erl. Вы также можете включить heart в режиме демона, чтобы он автоматически перезапускал систему в случае сбоев. См. сгенерированный файл releases/RELEASE_VSN/env.sh.
Дэмон будет записывать весь свой стандартный вывод в каталог "tmp/log/" в корне релиза. Вы можете следить за лог-файлом, выполнив tail -f tmp/log/erlang.log.1 или аналогичное действие. После того как файлы станут слишком большими, индексный суффикс будет увеличен. Разработчик также может подключиться к стандартному вводу демона, вызвав "to_erl tmp/pipe/" из корня релиза. Однако обратите внимание, что подключение к системе следует выполнять с особой осторожностью, поскольку обычные команды для выхода из Elixir-системы, такие как дважды нажатие клавиш Ctrl+C или Ctrl+\, фактически остановят демона. Поэтому рекомендуется использовать bin/RELEASE_NAME remote даже в режиме демона.
Вы можете настроить каталог tmp, используемый как для ведения журнала, так и для конвейера в режиме демона, установив переменную среды RELEASE_TMP. См. раздел "Настройка".
Режим служб (Windows)
В то время как демоны недоступны в Windows, можно установить релиз системы в виде службы в Windows с помощью erlsrv. Это можно сделать, выполнив:
bin/RELEASE_NAME install
После установки служба должна управляться явно с помощью исполняемого файла erlsrv, который находится в каталоге erts-VSN/bin. Служба не запускается автоматически после установки.
Например, если у вас есть релиз с именем demo, вы можете установить службу, а затем запустить ее из корня релиза следующим образом:
bin/demo install erts-VSN/bin/erlsrv.exe start demo_demo
Имя службы — demo_demo, поскольку имя формируется путем конкатенации имени узла и имени релиза. Поскольку Elixir автоматически использует одно и то же имя для обоих, служба будет упоминаться как demo_demo.
Команда install должна выполняться с правами администратора.
Команды bin/RELEASE_NAME
Следующие команды поддерживаются bin/RELEASE_NAME:
start Starts the system start_iex Starts the system with IEx attached daemon Starts the system as a daemon (Unix-like only) daemon_iex Starts the system as a daemon with IEx attached (Unix-like only) install Installs this system as a Windows service (Windows only) eval "EXPR" Executes the given expression on a new, non-booted system rpc "EXPR" Executes the given expression remotely on the running system remote Connects to the running system via a remote shell restart Restarts the running system via a remote command stop Stops the running system via a remote command pid Prints the operating system PID of the running system via a remote command version Prints the release name and version to be booted
Развертывание
Требования
Релиз создается на хосте, машине, содержащей Erlang, Elixir и все другие необходимые зависимости для компиляции вашего приложения. Затем релиз развертывается на целевой системе, потенциально на той же машине, что и хост, но обычно на другой, и часто бывает несколько целевых систем (или несколько экземпляров, или релиз развертывается в разнородных средах).
Чтобы развернуть релиз непосредственно с хоста на отдельную целевую систему без кросс-компиляции, между хостом и целевой системой должны быть одинаковыми:
- Архитектура целевой системы (например, x86_64 или ARM)
- Производитель + операционная система целевой системы (например, Windows, Linux или Darwin/macOS)
- ABI целевой системы (например, musl или gnu)
Это часто представляется в виде тройки целевой системы, например, x86_64-unknown-linux-gnu, x86_64-unknown-linux-musl, x86_64-apple-darwin.
Поэтому, чтобы развернуть релиз непосредственно с хоста на отдельную целевую систему, Erlang Runtime System (ERTS) и все нативные зависимости (NIF) должны быть скомпилированы для одной и той же тройки целевой системы. Если вы собираете на MacBook (x86_64-apple-darwin) и пытаетесь развернуть на типичной машине Ubuntu (x86_64-unknown-linux-gnu), релиз не будет работать. Вместо этого вы должны собрать релиз на хосте x86_64-unknown-linux-gnu. Как мы увидим, это можно сделать несколькими способами, например, выпуском на самой целевой системе или с помощью виртуальных машин или контейнеров, обычно в рамках вашей системы CI/CD.
Помимо соответствия тройке целевой системы, важно, чтобы целевая система имела все системные пакеты, необходимые вашему приложению во время выполнения. Часто требуется OpenSSL при создании приложения, использующего :crypto или :ssl, которые динамически связаны с ERTS. Другим распространенным источником нативных зависимостей такого рода являются зависимости, содержащие NIF (функции, реализованные нативными средствами), которые могут ожидать динамической связи с используемыми библиотеками.
Конечно, операционные системы и менеджеры пакетов могут отличаться между версиями, поэтому, если ваша цель — полная совместимость между хостом и целевой системой, лучше убедиться, что у операционной системы и менеджера пакетов одинаковые версии на хосте и целевой системе. Это может даже стать требованием в некоторых системах, особенно в системах с менеджерами пакетов, стремящимися создать полностью воспроизводимые среды (Nix, Guix).
Аналогично, при создании автономного пакета и выпуска для Windows, обратите внимание на зависимость Erlang Runtime System от некоторых библиотек Microsoft (Visual C++ Redistributable Packages для Visual Studio 2013). Эти библиотеки устанавливаются (если они отсутствуют) при установке Erlang, но они не входят в стандартную среду Windows. Развертывание автономного релиза на компьютере без этих библиотек приведет к ошибке при попытке запустить релиз. Один из способов решения этой проблемы — загрузить и установить эти библиотеки Microsoft при первом развертывании релиза (версия установщика Erlang 10.6 поставляется с «Microsoft Visual C++ 2013 Redistributable - 12.0.30501»).
В качестве альтернативы вы также можете скомпилировать объектные файлы в релизе, при условии, что они были скомпилированы для того же целевого варианта. Если вы это делаете, вам необходимо обновить переменную среды LD_LIBRARY_PATH с путями, содержащими скомпилированные объекты в системах Unix-подобных или переменную среды PATH в системах Windows.
В настоящее время нет официального способа кросс-компиляции релиза из одного целевого тройного кода в другой из-за сложности процесса.
Технические приёмы
Существует несколько способов гарантировать, что релиз создаётся на хосте с такими же свойствами, как и целевой. Простой вариант — получить исходный код, скомпилировать код и собрать релиз на самом целевом устройстве. Это примерно так:
git clone remote://path/to/my_app.git my_app_source cd my_app_source mix deps.get --only prod MIX_ENV=prod mix release _build/prod/rel/my_app/bin/my_app start
Если вы предпочитаете, вы также можете скомпилировать релиз в отдельную директорию, чтобы удалить все исходники после сборки релиза:
git clone remote://path/to/my_app.git my_app_source cd my_app_source mix deps.get --only prod MIX_ENV=prod mix release --path ../my_app_release cd ../my_app_release rm -rf ../my_app_source bin/my_app start
Однако этот вариант может быть дорогостоящим, если у вас много производственных узлов или процесс сборки релиза длительный, так как каждый узел должен индивидуально собрать релиз.
Вы можете автоматизировать этот процесс несколькими способами. Один из вариантов — сделать его частью вашей системы непрерывной интеграции (CI) / непрерывного развертывания (CD). Когда у вас есть CI/CD-система, обычно машины в вашей CI/CD-системе работают с тем же целевым тройным кодом, что и ваши производственные серверы (если нет, они должны). В этом случае вы можете собрать релиз в конце вашей CI/CD-системы, вызвав MIX_ENV=prod mix release и поместить артефакт в хранилище S3 или любое другое сетевое хранилище. Для выполнения развертывания ваши производственные машины могут извлечь развертывание из сетевого хранилища и запустить bin/my_app start.
Другой механизм автоматизации развертываний — использование образов, таких как Amazon Machine Images, или платформ контейнеров, таких как Docker. Например, вы можете использовать Docker для запуска локальной системы с тем же целевым тройным кодом, что и ваши производственные серверы. Внутри контейнера вы можете вызвать MIX_ENV=prod mix release и создать полный образ и/или контейнер с операционной системой, всеми зависимостями, а также релизами.
Другими словами, существует множество способов развертывания систем, и релизы могут быть автоматизированы и интегрированы во все из них, если вы помните о сборке системы в той же целевой тройке.
После развертывания системы вы можете остановить её, отправив SIGINT/SIGTERM системе, что делают большинство контейнеров, платформ и инструментов, или явно вызвав bin/RELEASE_NAME stop. После получения запроса на остановку каждое приложение и соответствующие деревья надзора будут останавливаться по одному, в обратном порядке их запуска.
Настройка
Существует несколько способов, которыми разработчики могут настроить сгенерированные артефакты внутри релиза.
Параметры
Следующие параметры можно задать в вашем mix.exs для каждого определения релиза:
-
:applications- список ключевых слов, который настраивает и добавляет новые приложения в релиз. Ключ — имя приложения, а значение — одно из:-
:permanent- приложение запускается, и узел останавливается, если приложение завершается по любой причине -
:transient- приложение запускается, и узел останавливается, если приложение завершается аномально -
:temporary- приложение запускается, и узел не останавливается, если приложение завершается -
:load- приложение только загружается -
:none- приложение является частью релиза, но не загружается и не запускается. Все приложения по умолчанию:permanent. По умолчанию:applicationsвключает текущее приложение и все приложения, от которых зависит текущее приложение, рекурсивно. Вы можете включить новые приложения или изменить режим существующих, перечислив их здесь. Порядок приложений, заданных в:applications, будет сохраняться по возможности, за исключением:kernel,:stdlib,:sasl, и:elixir, которые указываются перед заданным списком приложений. Релизы, собранные из проекта-зонтика, требуют явного указания этой конфигурации.
-
:strip_beams- управляет тем, удаляются ли из файлов BEAM информация о отладке, фрагменты документации и другие не существенные метаданные. По умолчаниюtrue. Может быть установлено вfalseдля отключения удаления. Также принимает[keep: ["Docs", "Dbgi"]]для сохранения определённых фрагментов, которые обычно удаляются.-
:cookie- строка, представляющая cookie Erlang Distribution. Если этот параметр не задан, случайная cookie записывается в файлreleases/COOKIEпри первой сборке релиза. Во время выполнения мы сначала попытаемся получить cookie из переменной средыRELEASE_COOKIE, а затем прочитаем файлreleases/COOKIE.Если вы устанавливаете этот параметр вручную, рекомендуется, чтобы cookie была длинной и случайной строкой, например:
Base.url_encode64(:crypto.strong_rand_bytes(40)). Также рекомендуется ограничить символы в cookie подмножеством, возвращаемымBase.url_encode64/1. :validate_compile_env- по умолчанию релиз будет сопоставлять все конфигурации выполнения с любой конфигурацией, которая была помечена во время компиляции в вашем приложении или его зависимостях с помощью функцииApplication.compile_env/3. Если есть несоответствие между ними, это означает, что ваша система неправильно настроена и не может загрузиться. Вы можете отключить эту проверку, установив этот параметр в false.:path- путь, в который должен быть установлен релиз. По умолчанию"_build/MIX_ENV/rel/RELEASE_NAME".:version- версия релиза в виде строки или{:from_app, app_name}. По умолчанию — текущая версия приложения. Формат{:from_app, app_name}может использоваться для лёгкой ссылки на версию приложения из другого приложения. Это особенно полезно в приложениях-зонтиках.:quiet- булево значение, которое контролирует, будут ли шаги записи в стандартный вывод. По умолчаниюfalse.-
:include_erts- булево значение, строка или анонимная функция арности ноль. Если булево значение, оно указывает, должен ли Erlang Runtime System (ERTS), который включает Erlang VM, включаться в релиз. Значение по умолчаниюtrue, что также является рекомендуемым значением. Если строка, она представляет путь к существующей установке ERTS. Если анонимная функция арности ноль, это функция, которая возвращает любое из вышеперечисленного (булево значение или строка).Вы также можете установить этот параметр в
false, если хотите использовать версию ERTS, установленную на целевом устройстве. Однако обратите внимание, что версия ERTS на целевом устройстве должна быть точной версией ERTS, используемой при сборке релиза. Установка его вfalseтакже отключает горячие обновления кода. Следовательно,:include_ertsдолжен быть установлен вfalseс осторожностью и только если вы собираете релиз на том же сервере, на котором он работает. -
:include_executables_for- список атомов, определяющих, для каких операционных систем должны генерироваться исполняемые файлы. По умолчанию он настроен на[:unix, :windows]. Вы можете настроить их следующим образом:releases: [ demo: [ include_executables_for: [:unix] # Or [:windows] or [] ] ] :rel_templates_path- путь к файлам шаблонов, которые копируются в релиз, например, "vm.args.eex", "remote.vm.args.eex", "env.sh.eex" (или "env.bat.eex") и "overlays". По умолчанию "rel" в корне проекта.:overlays- список директорий с дополнительными файлами, которые копируются как есть в релиз. Директория "overlays" по пути:rel_templates_pathвсегда включается в этот список по умолчанию (обычно по пути "rel/overlays"). Смотрите раздел "Надстройки" для получения дополнительной информации.:steps- список шагов, которые нужно выполнить при сборке релиза. См. раздел "Шаги" для получения дополнительной информации.
Обратите внимание, что каждое определение релиза может быть задано как анонимная функция. Это полезно, если некоторые атрибуты релиза дорогостоящие для вычисления:
releases: [
demo: fn ->
[version: @version <> "+" <> git_ref()]
end
]
Помимо перечисленных выше параметров, можно настроить сгенерированный релиз с помощью пользовательских файлов, изменив шаги релиза или выполнив пользовательские параметры и команды при запуске. Мы подробно рассмотрим оба подхода ниже.
Надстройки
Зачастую необходимо скопировать дополнительные файлы в корневую директорию релиза после его сборки. Это можно легко сделать, поместив такие файлы в директорию rel/overlays. Любой файл в этой директории копируется как есть в корень релиза. Например, если вы разместили файл "rel/overlays/Dockerfile", "Dockerfile" будет скопирован как есть в корень релиза.
Если вы хотите указать дополнительные директории надстроек, вы можете сделать это с помощью параметра :overlays. Если вам нужно динамически копировать файлы, обратитесь к разделу "Шаги".
Шаги
Можно добавить один или несколько шагов перед и после сборки релиза. Это можно сделать с помощью параметра :steps.
releases: [
demo: [
steps: [&set_configs/1, :assemble, ©_extra_files/1]
]
]
Параметр :steps должен быть списком и всегда должен включать атом :assemble, который выполняет большую часть работы по сборке релиза. Вы можете передать анонимные функции до и после :assemble для настройки вашей системы сборки релиза. Эти анонимные функции получат структуру Mix.Release и должны вернуть ту же или обновлённую структуру Mix.Release. Также возможно создать tar-архив релиза, передав шаг :tar в любой точке после :assemble. Если сборка релиза :path не настроена, то tar-архив создается в _build/MIX_ENV/RELEASE_NAME-RELEASE_VSN.tar.gz. В противном случае, он создается внутри настроенной директории :path.
См. Mix.Release для получения дополнительной информации о структуре и полях, которые можно изменить. Обратите внимание, что поле :steps само по себе может быть изменено и обновляется каждый раз, когда вызывается шаг. Поэтому, если вам нужно выполнить команду до и после сборки релиза, вам нужно только объявить первые шаги в своей конвейерной линии, а затем ввести последний шаг в структуру релиза. Поле steps также можно использовать для проверки, был ли шаг установлен до или после сборки релиза.
vm.args и env.sh (env.bat)
Разработчики могут захотеть настроить флаги виртуальной машины (ВМ) и переменные среды, предоставляемые при запуске релиза. Самый простой способ настроить эти файлы — запустить mix release.init. Задача Mix скопирует пользовательские rel/vm.args.eex, rel/remote.vm.args.eex, rel/env.sh.eex, и rel/env.bat.eex файлы в корень вашего проекта. Вы можете изменить эти файлы, и они будут оцениваться каждый раз, когда вы выполняете новый релиз. Эти файлы являются обычными шаблонами EEx, и у них есть единственное присваивание, называемое @release, со структурой Mix.Release.
Файлы vm.args и remote.vm.args могут содержать любые флаги ВМ, принимаемые командой erl.
Файлы env.sh и env.bat используются для установки переменных среды. В них вы можете установить переменные, такие как RELEASE_NODE, RELEASE_COOKIE, и RELEASE_TMP, соответственно, чтобы настроить имя узла, cookie и каталог tmp. Всякий раз, когда вызывается env.sh или env.bat, переменные RELEASE_ROOT, RELEASE_NAME, RELEASE_VSN, и RELEASE_COMMAND уже установлены, поэтому вы можете полагаться на них. Более подробную информацию см. в разделе о переменных среды.
Кроме того, хотя файлы vm.args являются статическими, вы можете использовать env.sh и env.bat для динамической установки параметров ВМ. Например, если вы хотите убедиться, что Erlang Distribution прослушивает только определенный порт, известный во время выполнения, вы можете установить следующее:
case $RELEASE_COMMAND in
start*|daemon*)
ELIXIR_ERL_OPTIONS="-kernel inet_dist_listen_min $BEAM_PORT inet_dist_listen_max $BEAM_PORT"
export ELIXIR_ERL_OPTIONS
;;
*)
;;
esac
Обратите внимание, что мы устанавливаем порт только для команд start/daemon. Если вы также ограничите порт другими командами, такими как rpc, то вы не сможете установить удаленное соединение, так как порт уже занят узлом.
В Windows ваш файл env.bat будет выглядеть так:
IF NOT %RELEASE_COMMAND:start=%==%RELEASE_COMMAND% ( set ELIXIR_ERL_OPTIONS="-kernel inet_dist_listen_min %BEAM_PORT% inet_dist_listen_max %BEAM_PORT%" )
Настройка приложения
Релизы предоставляют два механизма для настройки приложений OTP: на этапе сборки и во время выполнения.
Настройка на этапе сборки
Всякий раз, когда вы вызываете команду mix, Mix загружает конфигурацию в config/config.exs, если такой файл существует. Часто файл config/config.exs сам по себе импортирует другую конфигурацию на основе текущей MIX_ENV, такой как config/dev.exs, config/test.exs, и config/prod.exs. Мы говорим, что эта конфигурация является конфигурацией на этапе сборки, так как она оценивается при каждой компиляции вашего кода или при каждой сборке релиза.
Другими словами, если ваша конфигурация делает что-то вроде:
config :my_app, :secret_key, System.fetch_env!("MY_APP_SECRET_KEY")
Ключ :secret_key в :my_app будет вычисляться на хост-машине при каждой сборке релиза. Установка MY_APP_SECRET_KEY непосредственно перед запуском релиза не повлияет на результат.
К счастью, релизы также предоставляют конфигурацию во время выполнения, которую мы рассмотрим далее.
Настройка во время выполнения
Чтобы включить настройку во время выполнения в вашем релизе, вам нужно создать файл с именем config/runtime.exs:
import Config
config :my_app, :secret_key, System.fetch_env!("MY_APP_SECRET_KEY")
Этот файл будет выполняться всякий раз, когда запускается ваш проект Mix или ваш релиз.
Ваш файл config/runtime.exs должен соответствовать трём важным правилам:
- Он ДОЛЖЕН
import Configвверху вместо устаревшегоuse Mix.Config - Он НЕ ДОЛЖЕН импортировать другие файлы конфигурации с помощью
import_config - Он НЕ ДОЛЖЕН обращаться к
Mixкаким-либо образом, так какMix— это инструмент сборки, и он недоступен внутри релизов
Если существует файл config/runtime.exs, он будет скопирован в ваш релиз и выполнен на ранней стадии процесса запуска, когда будут запущены только основные приложения Elixir и Erlang. После загрузки конфигурации система Erlang будет перезапущена (в том же процессе операционной системы), и новая конфигурация вступит в силу.
Вы можете изменить путь к файлу конфигурации во время выполнения, установив :runtime_config_path в каждой конфигурации релиза. Этот путь разрешается на этапе сборки, так как указанный файл конфигурации всегда копируется внутрь релиза:
releases: [
demo: [
runtime_config_path: ...
]
]
Наконец, для корректной работы настройки во время выполнения (а также любого другого «поставщика конфигурации», как определено ниже), она должна иметь возможность сохранять вычисленную конфигурацию на диске. Вычисленный файл конфигурации будет записан в каталог «tmp» внутри релиза каждый раз при запуске системы. Вы можете настроить каталог «tmp», установив переменную среды RELEASE_TMP, либо явно, либо внутри вашего releases/RELEASE_VSN/env.sh (или env.bat в Windows).
Поставщики конфигурации
Релизы также поддерживают пользовательские механизмы, называемые поставщиками конфигурации, для загрузки любого типа конфигурации во время выполнения в систему во время её запуска. Например, если вам нужно получить доступ к хранилищу или загрузить конфигурацию из файла JSON, это можно сделать с помощью поставщиков конфигурации. Конфигурация во время выполнения, описанная в предыдущем разделе, обрабатывается поставщиком Config.Reader. Дополнительную информацию и примеры см. в модуле Config.Provider.
Следующие параметры можно установить в ключе releases вашего файла mix.exs для управления работой поставщиков конфигурации:
:reboot_system_after_config— каждый раз, когда ваш релиз настраивается, система перезапускается, чтобы позволить новой конфигурации вступить в силу. Вы можете установить этот параметр в значениеfalseдля отключения перезапуска для приложений, чувствительных к времени запуска, но при этом помните, что вы не сможете настроить системные приложения, такие как:kernelи:stdlib. По умолчаниюtrueпри использовании устаревшегоconfig/releases.exs,falseв противном случае.:prune_runtime_sys_config_after_boot— если:reboot_system_after_configустановлен, каждый раз при запуске системы релиз запишет файл конфигурации в каталог tmp. Эти файлы конфигурации, как правило, небольшие. Но если вы обеспокоены объемом дискового пространства или у вас есть другие ограничения, вы можете попросить систему удалить эти файлы конфигурации после запуска. Недостатком является то, что вы больше не сможете перезапустить систему внутренним образом (ни черезSystem.restart/0, ни черезbin/RELEASE_NAME restart). Если вам нужен перезапуск, вам нужно будет завершить процесс операционной системы и запустить новый.:start_distribution_during_config— если:reboot_system_after_configустановлен, релизы запускают функции распределения Erlang VM только после оценки файлов конфигурации. Вы можете установить его в значениеtrueесли вам нужна дистрибуция во время конфигурирования. По умолчаниюfalseот Erlang/OTP 22+.:config_providers— список кортежей с пользовательскими поставщиками конфигурации. Дополнительную информацию см. вConfig.Provider. По умолчанию[].
Резюме по настройке и кастомизации
В общем случае следующие файлы доступны для настройки и конфигурации работающей системы:
config/config.exs(иconfig/prod.exs) — предоставляет конфигурацию приложений на этапе сборки, которая выполняется при сборке релизаconfig/runtime.exs— предоставляет конфигурацию приложений во время выполнения. Она выполняется каждый раз, когда запускается ваш проект Mix или ваш релиз, и дополнительно расширяется с помощью поставщиков конфигурации. Если вы хотите определить, находитесь ли вы внутри релиза, вы можете проверить переменные среды, специфичные для релиза, такие какRELEASE_NODEилиRELEASE_MODErel/vm.args.eexиrel/remote.vm.args.eex— файлы шаблонов, которые копируются в каждый релиз и предоставляют статическую конфигурацию виртуальной машины Erlang и других флагов во время выполнения.vm.argsвыполняется для командstart,daemon, иeval.remote.vm.argsнастраивает ВМ для командremoteиrpcrel/env.sh.eexиrel/env.bat.eex— файлы шаблонов, которые копируются в каждый релиз и выполняются при каждой команде для настройки переменных среды, включая специфические для ВМ и общие переменные среды
Структура каталогов
Релиз организован следующим образом:
bin/
RELEASE_NAME
erts-ERTS_VSN/
lib/
APP_NAME-APP_VSN/
ebin/
include/
priv/
releases/
RELEASE_VSN/
consolidated/
elixir
elixir.bat
env.bat
env.sh
iex
iex.bat
remote.vm.args
runtime.exs
start.boot
start.script
start_clean.boot
start_clean.script
sys.config
vm.args
COOKIE
start_erl.data
tmp/
Мы документируем эту структуру для полноты картины. На практике разработчики не должны изменять ни один из этих файлов после сборки релиза. Вместо этого используйте скрипты env, пользовательские поставщики конфигурации, наложения и все другие механизмы, описанные в этом руководстве, чтобы настроить работу вашего релиза.
Переменные среды
Система устанавливает различные переменные среды. Следующие переменные устанавливаются на ранней стадии и могут читаться только env.sh и env.bat:
RELEASE_ROOT— указывает на корень выпуска. Если система включает ERTS, то она совпадает с:code.root_dir/0. Эта переменная всегда вычисляется и не может быть задана пользовательским значениемRELEASE_COMMAND— команда, данная для выпуска, например,"start","remote","eval", и так далее. К ней обычно обращаются внутриenv.shиenv.batдля установки различных переменных среды в разных условиях. Обратите внимание, однако, чтоRELEASE_COMMANDне валидируется к моменту вызоваenv.shиenv.bat, поэтому она может быть пустой или содержать недопустимые значения. Эта переменная всегда вычисляется и не может быть задана пользовательским значениемRELEASE_NAME— имя выпуска. Его можно задать пользовательским значением при вызове выпускаRELEASE_VSN— версия выпуска, в противном случае используется последняя версия. Ее можно задать пользовательским значением при вызове выпуска. Пользовательское значение должно быть существующей версией выпуска в каталогеreleases/RELEASE_PROG— исполняемый файл командной строки, используемый для запуска выпуска
Следующие переменные можно установить до вызова выпуска или внутри env.sh и env.bat:
RELEASE_COOKIE— куки выпуска. По умолчанию использует значение вreleases/COOKIE. Его можно задать пользовательским значениемRELEASE_NODE— имя узла выпуска в форматеname@host. Его можно задать пользовательским значением. Часть имени должна состоять только из букв, цифр, символов подчеркивания и дефисовRELEASE_SYS_CONFIG— расположение файла sys.config. Его можно установить в пользовательский путь, и он не должен содержать расширение.configRELEASE_VM_ARGS— расположение файла vm.args. Его можно установить в пользовательский путьRELEASE_REMOTE_VM_ARGS— расположение файла remote.vm.args. Его можно установить в пользовательский путьRELEASE_TMP— каталог в выпуске для записи временных файлов. Его можно установить в пользовательский каталог. По умолчанию используется$RELEASE_ROOT/tmpRELEASE_MODE— режим запуска выпуска: встроенный или интерактивный. По умолчанию «встроенный». Применяется только к командам start/daemon/installRELEASE_DISTRIBUTION— способ запуска дистрибутива. Может бытьname(полные имена),sname(краткие имена) илиnone(дистрибутив не запускается автоматически). По умолчаниюsname, что позволяет получить доступ только внутри текущей системы.nameпозволяет внешние подключения. Если используетсяname, и вы не работаете на Erlang/OTP 22 или более поздней версии, вы должны установитьRELEASE_NODEнаRELEASE_NAME@127.0.0.1с IP-адресом или известным хостомRELEASE_BOOT_SCRIPT— имя скрипта загрузки, используемого при запуске выпуска. Этот скрипт используется при выполнении таких команд, какstartиdaemon. Ожидается, что скрипт загрузки будет расположен по путиreleases/RELEASE_VSN/RELEASE_BOOT_SCRIPT.boot. По умолчаниюstartRELEASE_BOOT_SCRIPT_CLEAN— имя скрипта загрузки, используемого при чистом запуске выпуска без вашего приложения или его зависимостей. Этот скрипт используется командами, такими какeval,rpc, иremote. Ожидается, что скрипт загрузки будет расположен по путиreleases/RELEASE_VSN/RELEASE_BOOT_SCRIPT_CLEAN.boot. По умолчаниюstart_clean
Umbrellas
Выпуски хорошо интегрированы с проектами umbrella, позволяя вам выпустить один или несколько подмножеств ваших дочерних элементов umbrella. Единственное отличие между выполнением выпуска в проекте umbrella и обычным приложением состоит в том, что umbrella требуют явного перечисления вашего выпуска и точки входа для каждого выпуска. Например, представьте эти приложения umbrella:
my_app_umbrella/
apps/
my_app_core/
my_app_event_processing/
my_app_web/
где как my_app_event_processing так и my_app_web зависят от my_app_core, но не зависят друг от друга.
Внутри вашего umbrella вы можете определить несколько выпусков:
releases: [
web_and_event_processing: [
applications: [
my_app_event_processing: :permanent,
my_app_web: :permanent
]
],
web_only: [
applications: [my_app_web: :permanent]
],
event_processing_only: [
applications: [my_app_event_processing: :permanent]
]
]
Обратите внимание, что вам не нужно определять все приложения в :applications, а только точки входа. Также помните, что рекомендуемый режим для всех приложений в системе — :permanent.
Наконец, имейте в виду, что не обязательно собирать выпуск из корня umbrella. Вы также можете собрать выпуск из каждого дочернего приложения индивидуально. Однако сборка из корня позволяет включить два приложения, которые не зависят друг от друга, в один выпуск.
Горячие обновления кода
Erlang и Elixir иногда известны возможностью обновления узла, работающего в производственной среде, без остановки этого узла. Однако эта функция не поддерживается из коробки в Elixir releases.
Причина, по которой мы не предоставляем горячие обновления кода, заключается в том, что они очень сложны для реализации на практике, так как требуют тщательного кодирования ваших процессов и приложений, а также обширного тестирования. Учитывая, что большинство команд могут использовать другие методы, независимые от языка, для обновления своих систем, такие как развертывания Blue/Green, Canary развертывания, Rolling развертывания и другие, горячие обновления редко являются жизнеспособным вариантом. Давайте разберемся почему.
При горячем обновлении кода вы хотите обновить узел с версии A на версию B. Для этого первым шагом является написание рецептов для каждого приложения, которое изменилось между этими двумя выпусками, точно описывающих изменения приложения между версиями. Эти рецепты называются файлами .appup. Хотя некоторые шаги по созданию файлов .appup могут быть автоматизированы, не все. Кроме того, каждый процесс в приложении должен быть явно запрограммирован с учетом горячих обновлений кода. Посмотрим пример. Представьте, что ваше приложение имеет процесс счётчика как GenServer:
defmodule Counter do
use GenServer
def start_link(_) do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
def bump do
GenServer.call(__MODULE__, :bump)
end
## Callbacks
def init(:ok) do
{:ok, 0}
end
def handle_call(:bump, counter) do
{:reply, :ok, counter + 1}
end
end
Вы добавляете этот процесс в свою древовидную структуру управления и отправляете версию 0.1.0 своей системы. Теперь предположим, что в версии 0.2.0 вы внесли два изменения: вместо bump/0, который всегда увеличивает счётчик на единицу, вы ввели bump/1, который передаёт точное значение для увеличения счётчика. Вы также меняете состояние, так как хотите сохранить максимальное значение увеличения:
defmodule Counter do
use GenServer
def start_link(_) do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
def bump(by) do
GenServer.call(__MODULE__, {:bump, by})
end
## Callbacks
def init(:ok) do
{:ok, {0, 0}}
end
def handle_call({:bump, by}, {counter, max}) do
{:reply, :ok, {counter + by, max(max, by)}}
end
end
Если вы выполните горячее обновление кода в таком приложении, оно упадет, потому что в исходной версии состояние было просто счётчиком, а в новой — кортежем. Кроме того, вы изменили формат сообщения call с :bump на {:bump, by}, и процесс может временно смешивать старые и новые сообщения, поэтому нам нужно обработать оба. Конечной версией будет:
defmodule Counter do
use GenServer
def start_link(_) do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
def bump(by) do
GenServer.call(__MODULE__, {:bump, by})
end
## Callbacks
def init(:ok) do
{:ok, {0, 0}}
end
def handle_call(:bump, {counter, max}) do
{:reply, :ok, {counter + 1, max(max, 1)}}
end
def handle_call({:bump, by}, {counter, max}) do
{:reply, :ok, {counter + by, max(max, by)}}
end
def code_change(_, counter, _) do
{:ok, {counter, 0}}
end
end
Теперь вы можете добавить этот процесс в файл .appup и выполнить горячее обновление кода. Это один из многих шагов, необходимых для выполнения горячих обновлений кода, и его необходимо учитывать для каждого процесса и приложения, обновляемого в системе. .appup поваренная книга предоставляет хорошую справку и больше примеров.
После создания .appup следующий шаг — создание файла .relup со всеми инструкциями по обновлению самого выпуска. Документация Erlang предоставляет главу о создании и обновлении целевой системы. Learn You Some Erlang имеет главу о горячих обновлениях кода.
В целом, существует множество шагов, сложностей и предположений при горячих обновлениях кода, что в конечном итоге является причиной того, почему они не предоставляются Elixir из коробки. Тем не менее, горячие обновления кода всё ещё могут быть реализованы командами, которые хотят реализовать эти шаги поверх mix release в своих проектах или в виде отдельных библиотек.
Опции командной строки
-
--force— принудительная перекомпиляция -
--no-archives-check— не проверять архив -
--no-deps-check— не проверять зависимости -
--no-elixir-version-check— не проверять версию Elixir -
--no-compile— не компилировать перед сборкой выпуска -
--overwrite— если существует существующая версия выпуска, перезаписать её -
--path— путь к выпуску -
--quiet— не писать прогресс в стандартный вывод -
--version— версия выпуска
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/mix/1.12.0/Mix.Tasks.Release.html