Макс Лапшин (levgem) wrote,
Макс Лапшин
levgem

Category:

Как деплоится эрливидео

Попробую максимально подробно рассказать про процедуру упаковки деплоя эрливидео.

TL;DR: я не использую релизы. Эрливидео в таком же виде, в каком девелопится, пакуется в дебиановский пакет в /opt/flussonic, ставится и рестартится. Управление осуществляется допиленным обычным инитскриптом.



Надо начать с технических требований, обусловленных бизнесом.

1. Рестарт эрливидео неприятная процедура, но не смертельная. Если для бизнеса падение видеостримингового сервера фатально, то надо сразу выходить из бизнеса, потому что видеостриминг насилует и жжет железо почем зря, так что выход железа из строя бывает. Фактически это означает, что рестарт сервера должен происходить для клиентов практически незаметно, потому что флеш-плеер и прочее надо делать умеющим реконнектиться.

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

3. Эрливидео ставят очень разные пользователи и их немало. Ближайший аналоги по ситуации — это ejabberd или rabbitmq (с несравненно большим объёмом установок). Пользователей объединяет то, что они не любят читать документацию и любят иметь своё мнение по каждому вопросу (зачем ставить erlang R15, когда есть надежный и проверенный R13).

4. Пользователи иногда читают логи. В логи следует писать полезную информацию, а не херню вида «supervisor N started».

Релизы



Как только заходит разговор про деплой эрланговского приложения, сразу возникает разговор про релизы. Эрланговские релизы — это очень сложная, навороченная штука, которую вообще мало кто умеет готовить без хелперов. Я против использования релизов в большинстве случаев с которыми я сталкивался (видео, кометы, биржевой трейдинг) и объясню почему. Но перед этим надо понимать, что в использовании релизов можно выделить следующие аспекты:
1) потенциальная возможность обновить всё приложение без единого разрыва
2) некоторая стандартизованная организация структуры развертываемого приложения

Бесшовный деплой



Люди, агитирующие за использование релизов, упорно талдычат следующие доводы, связанные с бесшовным деплоем:

1) релизы сразу помогают запускать по цепочке все необходимые приложения с их зависимостями.

Довод крайне сомнительный, потому что программист достаточно быстро выяснит, что у него библиотека не запускается без другой. Если же это выяснится только при деплое и всё разломается, значит что-то не так существенно раньше.

2) релизы очень удобно использовать для миграции карты супервизоров.

Я это как правило отношу либо к ребячеству, либо к лукавству. Дело в том, что когда меняется структура супервизоров, то данные внутри меняются так сильно, что грамотно описать и _протестировать_ скрипт миграции из старой структуры в новую очень и очень сложно. Учитывая современный темп деплоя (раз в день, раз в час), поверить в то, что кто-то всерьез берется за _тестирование_ таких скриптов миграции очень тяжело. Когда деплой раз в полгода или есть какие-то очень серьезные причины не рестартить сервер, поверить в это уже можно. Но тут мы возвращаемся к той мысли о том, что если рестартить сервер нельзя, то либо вас очень жалко, либо стоит пересмотреть свой подход к проектированию ПО.

Например, в очередной версии эрливидео процесс файла стал OTP-совместимым супервизором, у которого появились в детях читальщики (плавающий пул с замедленным автосдуванием). Скрипт по миграции старой карты процессов в новую — это такая нехреновая задача на пару недель разработки.

Т.е. я допускаю, что релизы удобнее, чем самопальные скрипты, но называть этот механизм удобным нельзя. К нему приходится прибегать либо из-за больших проблем, либо из-за ошибок прошлого.


3) релизы очень удобно использовать для миграции стейтов процессов.

Ссаным веником по морде за такие сказки. Релизы опять же могут быть удобнее для миграции стейта, чем их отсутствие, но всерьез команд, которые мигрируют стейты очень и очень мало. Поясню, что за проблема.

В эрланговском процессе состояние хранится в 99,999% случаев в кортеже, который синтаксически представлен как именованный рекорд. В компилированном виде имена рекордов не сохраняются. Когда загружается новый код с другим стейтом, то ни в старом, ни в новом коде нет информации о том, как назывались имена. Что бы не рестартить всю систему, можно в _каждый_ процесс поместить код, который опишет в какое поле нового стейта надо переложить какое поле из предыдущего стейта. Причем под словами «какое поле» имеется ввиду числовой оффсет в кортеже. Грубо говоря так:


upgrade(Old, New) ->
 New1 = setelement(5, New, element(3,Old)),
 New2 = setelement(6, New1, element(4,Old)),
 ...
 New15.


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

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


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


Организация структуры в релизах



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

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

Крайне сомнительная возможность – умение релиза упаковать весь эрланговский рантайм в пакет. Проблема в том, что деплоимся не на винду, а на линукс. Я целый год возился с этой поделкой и наелся проблем с GLIBC_2.15 not found, несовместимая версия openssl и т.п. Короче, от этих игрищ пришлось отказаться и какое-то время пользователи ставили esl-erlang. Как сделано сейчас — ниже.


Как организовано у меня



Есть два способа запустить демоном эрланг: erl -detached и run_erl.

Первый способ вызывает стандартный механизм демонизации, второй способ похож на daemon_tools и запускает эрланг в собственном мини screen, перехватывая весь его вывод в erlang.log.1

От первого способа я отказался, потому что он оказался неуправляемым в случае какой-то ошибки в инсталяции. Например, в каком-то модуле есть следы R15, а пользователь стартует под R14. С run_erl это можно увидеть сразу, с detached навозишься долго. Релизы тут так же не спасут, потому что ставим и выясняем, что openssl только версии 0.9, а не 1.0. Выясняем это только при загрузке crypto, и в случае -detached иногда некоторые очень важные сообщения не доходят до логов.

Каталог /opt/flussonic полностью повторяет девелопмент окружение и более того: его вполне можно вытащить из гита. На паре стейджинговых серверов у меня именно так и сделано, потому что я оттуда же могу и закоммитить в репо. Это очень удобно и фанаты релизов могут пошипеть из угла о том, как это плохо.


Итак, есть файл flussonic.erl, в нём функция start/0, эрливидео запускается:

ERL_LIBS=apps:deps erl -boot start_sasl -s flussonic -sasl errlog_type error

sasl я бы выкинул на помойку, если бы не настойчивое требование disksup, запускать эту непонятную мне либу. Но писать от сасля нужно только сообщения об ошибке.

Демонизация делается просто:

run_erl -daemon log/pipe/ log/console/ "exec make run"

вот так.

При старте первое что делает эрливидео, это чтение конфига. Если он плохой, надо сразу отказаться запускаться. Это наименьшее зло, потому что пользователь никогда не читает логи, когда в них есть намеки на то, что он что-то сделал не так.

После этого происходит хитрая настройка логгирования. Я не хочу мучать пользователя малоосмысленными сообщениями о старте сотен супервизоров, достаточно написать что запустились нужные подсистемы (приложения) и написать: Эрливидео начал конфигурироваться.

Дальше происходит заливка из сети платного, закрытого байткода с его запуском и после этого чтение конфига.

Конфигурация



Про конфигурацию отдельная тема. Я придерживаюсь того подхода, что читать настройки приложения из env этого приложения плохо. Т.е. это можно делать, но надо иметь публичное API вида: «приведи себя в соответствие с этим конфигом». Это нужно не только для того, что бы можно было на лету переконфигурироваться (тут странная штука: люди, которые выступают за бесшовный деплой, зачастую ничего не говорят про переконфигурацию без рестарта). Такое API очень полезно при тестировании. Сначала загрузили все приложения, а потом начинаешь в тестах менять их конфигурацию и заодно выясняешь, насколько хорошо у тебя этот реконфиг работает.

Я считаю, что конфигурация должна быть в декларативном виде: «сделай себя таким», а не в стиле циско «выполни эту команду».


Старт и управление



После этого эрливидео пишет пид файл и пишет в лог: «я хорошо запустился, давай смотри видео».

Описанная выше процедура очень сложно реализуется с релизами, потому что релизы заставляют просто запускать приложения и выполнять всю конфигурацию в start/2.

При этом возникает порой немного нелепая ситуация, когда конфигурация предыдущего приложения идет в следующем, потому что для неё нужно сразу две фичи. А то и вовсе сваливается в последнее приложение.

Где в случае с релизами, должна быть запись пид-файла, вообще непонятно. В http-клиенте или в адаптере к БД?


Упаковка в пакеты



Я очень доволен тем, что упаковка в дебиановские пакеты осуществляется из под макоси. У меня только один таргет сборки: debian/ubuntu 64 версий 6.0/12.04 и моложе. Для этого у меня есть специальная сборочка эрланга http://debian.erlyvideo.org/erlang_amd64.tgz на 11 мегабайт, которая имеет минимальное количество внешних зависимостей. Эта сборка заточена на распаковку в каталоге /opt/flussonic. Соответственно сборка пакета осуществляется раскладыванием на макоси всего в tmproot/opt/flussonic и упаковку в дебиановский пакет с помощью gist.github.com/maxlapshin/6251523 простого скрипта.

Профит на лицо: установка быстрая, никаких внешних зависимостей. Пользователи не верят в то, что софт ставится не три дня, а минуту.

Точно так же готовится gist.github.com/maxlapshin/6251552 дебиановский initscript, в котором жестко прописаны пути к /opt/flussonic.

переконфигурация



Переконфигурация требует просто аккуратного прописывания распространения новых конфигов по системе, а так же вычисления дельт между старым и новым конфигом. Например, надо убить старые потоки и запустить новые.

Это делается как из скрипта управления, так и из HTTP API.


UPD:

Конфигурация



Небольшое замечание про конфиги. Длительное время конфиги к эрливидео загружались банальным file:path_consult. От этого пришлось отказаться, потому что пользователи не в состоянии сбалансировать скобочки, а так же не в состоянии проникнуться концепцией кортежей и проплистов. Когда добавлять новый элемент в кортеж, а когда пихать новый проплист — это очень непростая задача для непрограммиста.

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

Очень полезным в спускании семантики в конфиг оказалось то, что упростилась документация. Не уверен, что описал все новые фичи? Открой .peg файл и проверь, все ли клозы прописаны в мануале!


Вроде всё. Что я упустил, что скомкал. Есть какие-то вопросы?
Tags: erlang, fp, деплой, эрливидео
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 34 comments