Деплой Phoenix-приложений через Edeliver. Часть 2
В предыдущей части мы составили план деплоя приложений, написанных на Elixir с использованием Phoenix. Теперь пришло время подробно раскрыть каждый из шагов и ответить на основные вопросы.
Шаг 1. Создание нового Phoenix-приложения
Чтобы создать новое приложение, следуйте этой инструкции или просто запустите соответствующую команду в терминале:
Теперь Phoenix-приложение должно появиться в директории edelivered_app
. Следуйте указаниям команды mix phoenix.new
, и убедитесь, что приложение запускается на вашей системе.
Укажите реквизиты базы данных в файле config/prod.secret.exs
. Можно смело использовать ту же базу данных, что и для dev-окружения, т.к. этот файл не добавляется в систему контроля версий, и на сервере будет его другая копия. Чтобы можно было создать релиз для продакшна, локальное приложение должно корректно работать в режиме «prod».
Убедитесь, что команды корректно выполняются:
Инициализируйте пустой Git-репозиторий и сделайте начальный коммит.
Шаг 2. Настройка distillery для создания релизов
Как гласит документация distillery:
Релиз — это пакет, состоящий из файлов с расширением .beam, включающих зависимости приложения, sys.config, vm.args, сценарий загрузки, а также различные утилиты и файлы метаданных, предназначенные для управления релизом после его установки. Кроме этого, релиз может также включать копию ERTS.
Фактически релиз представляет собой архив (*.tar.gz
) со скомпилированным приложением и всеми его зависимостями, включая саму среду выполнения.
Созданный релиз помещается на сервер, и затем происходит его развёртывание с помощью Edeliver (подробнее здесь).
Добавьте в mix.exs
следующий код:
и запустите
Создайте файл конфигурации релиза:
Откройте созданный файл rel/config.exs
. По умолчанию релиз будет сконфигурирован для двух окружений: dev
и prod
. В конфигурацию можно добавлять и другие релизы и окружения, однако пока остановимся на конфигурации по умолчанию, но с одной оговоркой.
Создавать и запускать distillery-релиз в режиме dev — бессмысленно, так как это всё равно не сработает (https://github.com/bitwalker/distillery/issues/25).
Поэтому нужно поставить окружение prod
в настройках по умолчанию. Замените default_environment
в rel/config.exs
на «prod».
Обязательно загляните на страницу терминологии distillery. Это поможет избежать суеты при возникновении ошибок и поиска в интернете решений по их исправлению.
Измените точку входа Endpoint в файле config/prod.exs
на следующую:
Важно, чтобы порты, указанные в опциях http
и url
, совпадали. Подробнее об этих опциях читайте здесь.
Теперь всё готово для создания первого релиза.
Даже если установить prod-окружение по умолчанию, distillery всё равно будет работать в dev-окружении Mix. Поэтому измените MIX_ENV
на «prod» и только после этого выполните команду mix release
.
Вот вы и создали свой релиз для продакшна!
Шаг 3. Локальное тестирование релиза distillery
По умолчанию релизы располагаются в директории _build/<env>/rel/<app-name>
, и можно запускать релиз прямо оттуда. Однако, для демонстрации переносимости релизов на Elixir, извлечём архив с релизом в отдельную папку и проведём запуск из неё.
- Создайте директорию для своего приложения:
mkdir ~/Downloads/edelivered_app
- Поместите копию релиза в эту директорию:
cp _build/prod/rel/edelivered_app/releases/0.0.1/edelivered_app.tar.gz ~/Downloads/edelivered_app/
- Откройте директорию назначения:
cd ~/Downloads/edelivered_app/
- Извлеките файлы из архива
tar -zxvf edelivered_app.tar.gz
Никогда не мог запомнить эти переключателиtar
, так как не особо часто извлекаю файлы типа*.tar.gz
. Специально для этого я создал документ в Evernote.Подсказка: создайте простенький сценарий и назовите егоuntar
. - Запустите приложение:
PORT=8080 bin/edelivered_app foreground
. Убедитесь, что обязательная переменная среды PORT соответствует необходимому порту.
Воспользуемся командой «foreground», чтобы для начала запустить приложение в обычном режиме и выявить существующие на данном этапе ошибки.
Если всё прошло нормально, то можно запустить приложение в фоновом режиме (в качестве демона):
Используйте этот же скрипт для остановки и перезапуска приложения, а также для подключения к нему. Наиболее полезные команды:
bin/edelivered_app
выводит список доступных команд.bin/edelivered_app stop
останавливает приложение.bin/edelivered_app ping
дает обратную связь «pong», если в приложении нет ошибок.bin/edelivered_app remote_console
подключается к запущенному релизу через консоль IEx. В отличие от «console» и «attach», «remote_console» не завершает запущенный релиз при выходе из консоли.
После развёртывания можно использовать те же команды на продакшн сервере/серверах.
Сделайте коммит внесённых изменений: git commit -am "Add distillery dependency"
Более подробную информацию о создании релизов можно найти в инструкции по установке на странице distillery в GitHub или вот в этом чудесном гайде. Очень рекомендуется изучить документацию distillery полностью, так как в ней содержится достаточно много информации о релизах, а также рассказывается о способах устранения ошибок, к коим мы ещё вернёмся в конце данной статьи.
Шаг 4. Подготовка сервера в облаке
Нам понадобится сервер Ubuntu 16.04 с открытым 22 SSH-портом, IP адресом и root-доступом.
Для создания сервера можно пользоваться абсолютно любым провайдером облачных вычислений. Из российских хостингов отлично себя зарекомендовал Vscale. Ценовая политика у него вполне приемлема. Всё, что нам потребуется, — это минимум 1 Гб оперативной памяти. Можно, конечно, сэкономить и рассмотреть вариант с 512 Мб, но тогда придётся увеличить область подкачки, чтобы на таком сервере можно было создавать релизы, что, к слову сказать, будет происходить крайне медленно. Посмотреть на примере, как увеличить область подкачки, можно здесь. Надеюсь, выделенное красным предупреждение в самом начале поста сможет посеять в ваши мысли зерно сомнения.
Ещё один вариант — установить Ubuntu 16.04 LTS на виртуальную машину. VirtualBox вполне подойдёт. Настройте сеть виртуальной машины: выберите NAT (Network Address Translation), чтобы стало возможным подключение к ней по SSH и HTTP/HTTPS.
Дабы упростить себе жизнь, забудем про Chef, Ansible и другие DevOps инструменты.
Выполните следующее:
- Создайте нового пользователя «app» в домашней директории:
adduser app
. - Поместите свой публичный RSA-ключ в
/home/app/.ssh/authorized_keys
для подключения к серверу по SSH без необходимости ввода пароля. Создайте директорию.ssh
, если её не существует. - Установите следующие права доступа:
chmod 700 /home/app/.ssh
chmod 644 /home/app/.ssh/authorized_keys
chown -R app:app /home/app/.ssh
- Для удобства добавьте пользователя «app» в группу
sudo
: внесите правки в файл/etc/group
и поместите app в конец строки «sudo». - Подключитесь к серверу по SSH в качестве пользователя
app
; пароль запрашиваться не должен. - Следуйте инструкции по установке Ubuntu для Elixir. Установите Erlang и Elixir.
- Следуйте указаниям по установке NodeJs и NPM в Ubuntu.
- Установите git:
sudo apt-get install git
- Установите сервер базы данных Postgres:
sudo apt-get install postgresql postgresql-contrib
. - Настройте роль Postgres для данного пользователя:
- Переключитесь на linux-пользователя «postgres»:
sudo su - postgres
- Запустите консольный клиент Postgres:
psql
CREATE ROLE app WITH superuser;
ALTER ROLE app WITH login;
ALTER ROLE app WITH createdb;
ALTER USER app WITH PASSWORD 'coolpass';
Надеюсь, вы не будете использовать этот пароль для своих реальных серверов :)
- Закройте консольный клиент Postres: Ctrd+D.
- Выполните выход пользователя postgres: exit или Ctrl+D.
- Переключитесь на linux-пользователя «postgres»:
- Создайте базу данных Postgres для своего приложения:
createdb edelivered_app_prod
- Создайте директорию приложения и настроек:
mkdir /home/app/mysite.com
- Создайте директорию хранения релизов:
mkdir /home/app/mysite.com/edeliver_release_store
- Добавьте глобальную переменную окружения PORT:
echo "PORT=8080" | sudo tee -a /etc/environment
- Добавьте ещё одну глобальную переменную окружения MIX_ENV:
echo "MIX_ENV=prod" | sudo tee -a /etc/environment
Шаг 5. Развёртывание distillery-релиза в продакшн с помощью Edeliver
Edeliver — это набор полезных сценариев для создания релиза при помощи distillery
и его развёртывания на некоторое количество серверов. В отличие от Rails и Capistrano, Edeliver подгружает код (используя Git) только на ОДИН сервер (билд-сервер), там же компилирует его, собирает ассеты, а затем производит развёртывание готового пакета на все серверы. Capistrano по умолчанию производит развёртывание кода и компиляцию ассетов на ВСЕХ серверах.
Добавьте edeliver
в список зависимостей проекта и в список приложений:
и запустите
В директории проекта создайте файл .deliver/config
:
Вышеуказанная конфигурация сгенерирует на сервере следующее дерево каталогов:
Подтвердите изменения и пометьте коммит «0.0.1» — версией, совпадающей с версией вашего проекта в mix.exs
.
Теги впоследствии понадобятся для обновления релизов в edeliver.
Подключитесь к серверу по SSH и создайте файл /home/app/mysite.com/prod.secret.exs
со следующим содержимым:
Создайте релиз, произведите развёртывание и запустите его:
env MIX_ENV=prod mix edeliver build release
— создаёт релиз и помещает его в директорию релизов на сервере.mix edeliver deploy release to production --version=0.0.1
производит развёртывание релиза на все серверы, но не запускает его!- Попробуйте на всякий случай после первого развёртывания запустить релиз в обычном режиме:
- Подключитесь к серверу по SSH в качестве пользователя
app
. cd ~/mysite.com/edelivered_app
bin/edelivered_app foreground
- Убедитесь, что сервер работает и откройте его в браузере: [http://138.197.37.15:8080][http://138.197.37.15:8080] (ваш IP-адрес, естественно, будет другим)
- Выполните выход: Ctrl+C
- Подключитесь к серверу по SSH в качестве пользователя
mix edeliver start production
запускает приложение на сервере в виде демона!
Иногда команда для запуска релиза по какой-то неведомой мне причине не справляется со своими обязанностями. Если после выполнения mix edeliver start production
сайт недоступен, подключитесь к серверу по SSH и проверьте, запустился ли процесс Erlang: ps -ef | grep erl
. Если нет, то ищите решение в следующем пункте.
Шаг 6. Устранение ошибок
Последняя версия образца Phoenix-приложения с настроенными distillery и edeliver доступна по ссылке: https://github.com/alex-kovshovik/edelivered_app.
- Не забывайте прописывать
MIX_ENV=prod
во всех командах развёртывания. - Если что-то пошло не так, удалите директорию
_build
и попробуйте снова. - Не используйте автоматическую версию AUTO_VERSION с самого начала, попробуйте сперва настроить всё вручную. Мне пришлось пройти через многое в попытках сделать этот способ развёртывания таким же простым, как у Capistrano. Не забывайте увеличивать номер версии своего приложения и создавать тег с таким же именем.
- Значение переменной APP должно совпадать с названием релиза в
rel/config.exs
. В противном случае получим ошибку: «Failed to build release: :no_release». - Значение переменной APP должно совпадать с именем приложения, иначе оно не запустится! Я пытался изменить его на «current_release», чтобы оптимизировать дерево каталогов сервера, в результате чего столкнулся с непредвиденными ошибками.
- Полезные переключатели mix edeliver:
--verbose
— отображает результаты работы команд;--debug
— показывает все команды и их вывод.
- Внесите поправку в файл
rel/config.exs
, как указано в первом комментарии здесь distillery support broke with changed output_dir in distillery 1.0.0 — Issue #182.
Шаг 7. Что теперь?
В следующих статьях будет рассмотрено:
- Настройка nginx в качестве обратного прокси-сервера для виртуальной машины Erlang.
- Создание и настройка SSL-сертификата с помощью letsencrypt.
- Создание и развёртывание обновлённых релизов.
- Быстрое создание релизов в docker-контейнерах или на локальной виртуальной машине.
- Создание релизов на CI-сервере.