Деплой Phoenix-приложений через Edeliver. Часть 3

В предыдущих частях был построен «скелет» Phoenix-приложения, сконфигурированного для создания и развёртывания релизов distillery при помощи edeliver. А теперь рассмотрим развёртывание релиза обновления с использованием горячего обновления кода Erlang.

Перезапускать приложение не придётся: его обновлённая версия будет доступна сразу же после развёртывания.

— из документации edeliver.

Релизы обновления

Прежде чем читать статью дальше, я настоятельно рекомендую вам ознакомиться с документацией distillery (раздел об обновлениях и откатах) и освежить свои знания, заглянув в документацию edeliver (раздел, посвящённый быстрому старту).

Чтобы развернуть обновление, потребуется создать «релиз обновления». В отличие от обычных релизов, релизы обновления содержат appups — инструкции по обновлению версии запущенного приложения. Создавая релиз обновления, необходимо указать исходную и конечную версии, чтобы distillery сгенерировал корректные инструкции appups.

Архивы релиза в директории релиза, созданные командой build release, не получится использовать для развёртывания обновления.

Релизы обновления позволяют делать невероятное — вносить изменения в приложение без простоя. Однако несмотря на все свои волшебные функции, distillery не в силах сгенерировать корректные инструкции appup для каждого возможного сценария обновления.

Шаг 1. Настройка работы edeliver

На момент написания данной статьи edeliver перестал поддерживать distillery, но решить эту проблему несложно. Достаточно лишь добавить одну строчку в конфигурацию окружения :prod, находящуюся по адресу rel/config.exs:

environment :prod do
  set include_erts: true
  set include_src: false
  set cookie: :"..."
  set output_dir: "rel/edelivered_app" # ADD THIS LINE!!!
end

Попробуем выполнить развёртывание изменений «дедовским» методом: сначала создадим обычный релиз, затем произведём его развёртывание и запуск.

mix edeliver stop production # Run this if production node is currently running
env MIX_ENV=prod mix edeliver build release production
mix edeliver deploy release to production
mix edeliver start production

Шаг 2. Внесение изменений в приложение

Во-первых, внесите изменения в приложение и увеличьте его версию до 0.0.2 в config/mix.exs. Это очень важный момент, так как нам предстоит подготовить и развернуть релиз обновления с версии 0.0.1 до версии 0.0.2:

def project do
  [app: :edelivered_app,
  version: "0.0.2", # Bump to 0.0.2!
  elixir: "~> 1.4",
  elixirc_paths: elixirc_paths(Mix.env),
  compilers: [:phoenix, :gettext] ++ Mix.compilers,
  build_embedded: Mix.env == :prod,
  start_permanent: Mix.env == :prod,
  aliases: aliases(),
  deps: deps()]
end

Сделайте коммит изменений и пометьте их тегом:

  1. git commit -am "Steal default Phoenix look to make Edeliver look"
  2. git tag 0.0.2

Повторюсь, что пушить коммиты в удалённый репозиторий не понадобится. Edeliver сделает это за вас: коммиты и теги с локального репозитория отобразятся на нужном вам сервере/серверах.

Шаг 3. Развертывание обновления

Прежде чем перейти к развёртыванию обновления, убедимся в возможности подключения edeliver к работающей ноде и подтверждения его версии:

mix edeliver version production

Должен появиться следующий текст:

mix edeliver version production

В случае возникновения ошибки или получения от edeliver сообщения о нерабочем состоянии ноды, переходите к пункту «устранение ошибок».

Теперь можно начинать развёртывание релиза обновления:

mix edeliver upgrade production --from=0.0.1 --to=0.0.2

Вывод команды:

Edeliver upgrade production

Обновите страницу, и... о, чудо!

App after deploy

Шаг 4. Устранение ошибок

Большинство решений по устранению ошибок из предыдущей статьи применимы и здесь, но есть и несколько особых подходов, актуальных только для работы с обновлениями:

  • Горячая замена кода может не сработать при обновлении зависимостей. В таком случае создайте «чистый» релиз и перезапустите ноду.

  • Иногда edeliver не видит работающую ноду на сервере, даже если она действительно запущена. Попробуйте подключиться к серверу по SSH и остановить Erlang-процесс вручную, после чего запустить ноду через edeliver или самостоятельно.

  • После выполнения команды mix edeliver start production, в некоторых случаях появляется сообщение «START SUCCESSFUL», однако на деле оказывается, что ничего не запустилось. Объяснения на этот счёт отыскать пока не удалось, поэтому просто подключитесь к серверу по SSH и запустите всё вручную.

Выводы

Обещанные свойства среды выполнения Erlang весьма привлекательны: это высоконадёжная система с бесконечным сроком существования, в которой можно проводить развёртывание обновлений, забыв о простое и перезагрузке кодовой базы. Звучит великолепно, но на своём скудном опыте я убедился, что процесс развёртывания Elixir-приложений не вызывает доверия. Мои ожидания не оправдались. На момент написания статьи я произвёл развёртывание 15 релизов обновления и в четверти случаев столкнулся с трудностями. Дошло до того, что не отображались даже простейшие изменения текста.

Я уверен, что это произошло из-за моей недостаточной компетентности в Appups, Relups и неполного понимания концепции релизов. Что ж, попробую пойти другим путём.

Таймон Тобольски в статье о развёртывании Phoenix-приложений в продакшн с помощью Docker (перевод) констатирует следующее:

  • Унификация: обычно в продакшн стеке запускаются приложения, написанные на разных языках программирования. Если бы можно было произвести развёртывание всех этих приложений одинаковым способом — это было бы большим прорывом в DevOps.

  • Как правило, для работы в продакшне требуется несколько серверов, и отказ одного из них должен пройти безболезненно. Балансировщик нагрузки оперативно отреагирует на это и остановит поток запросов к такому серверу, в результате чего некоторые пользователи потеряют WebSocket-соединение. Но эта проблема легко разрешима: нужно лишь выполнить переподключение клиентов этих пользователей. До тех пор, пока сбои не происходят ежеминутно, беспокоиться не о чем.

  • В последнее время интерес разработчиков к Docker достаточно высок, поэтому я бы хотел провести сравнение развёртывания с помощью Docker и Edeliver по критериям надёжности и возможности повторного использования.

© 2020 / Россия Любые мысли и вопросы пишите на elixir@wunsh.ru.