Эволюция средств поставки, или размышления о Docker, deb, jar и прочем +9




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

Любой продукт, какой бы он ни был, должен каким-то образом добраться до продуктовых серверов, должен быть настроен и запущен. Вот об этом и будет эта статья.

Размышлять я буду в историческом контексте, «что вижу — о том пою», что я видел, когда начинал только писать код и что наблюдаю сейчас, что мы сами используем в настоящий момент и почему. Статья не претендует на полноценное исследование, некоторые моменты упущены, это мой личный взгляд на то, что было и что есть сейчас.

Итак, в старые добрые времена… самый ранний способ поставки, который я застал — это были кассеты от магнитофонов. У меня был компьютер БК-0010.01…

Эпоха калькуляторов


Нет, был еще более ранний момент, был еще калькулятор МК-61 и МК-52.

Так вот, когда у меня был МК-61, то способом переноса программы был обычный листок бумаги в клеточку, на котором была записана программа, которая при необходимости ее запустить вручную записывалась в калькулятор. Хочешь поиграть (да-да, даже на этом допотопном калькуляторе были игры) — садишься и вписываешь программу в калькулятор. Естественно, при выключении калькулятора программа уходила в небытие. Кроме собственноручно выписанных на бумагу кодов калькулятора, программы публиковались в журналах «Радио» и «Техника молодежи», а также печатались в книгах того времени.

Следующей модификацией был калькулятор МК-52, у него уже появилось какое-то подобие энергонезависимого хранения данных. Теперь уже игру или программу не надо было вбивать вручную, а, проделав некоторые магические пассы кнопками, она загружалась сама.

Объем самой большой программы в калькуляторе был 105 шагов, а размер постоянной памяти в МК-52 — 512 шагов.

Кстати, если есть фанаты этих калькуляторов, кто читает эту статью — в процессе написания статьи я нашел и эмулятор калькулятора для андроид, и программы для него. Вперед, в прошлое!


Небольшое отступление про МК-52 (из википедии)

МК-52 летал в космос на корабле «Союз ТМ-7». Его предполагалось использовать для расчёта траектории посадки в случае, если выйдет из строя бортовой компьютер.

МК-52 с блоком расширения памяти «Электроника-Астро» с 1988 года поставлялся на корабли ВМФ в составе штурманского вычислительного комплекта.


Первые персональные компьютеры



Вернемся к временам БК-0010. Понятное дело, что и памяти там стало больше, и вбивать код с бумажки было уже совсем не вариант (хотя первое время я делал именно так, потому что другого носителя попросту не было). Основным средством хранения и поставки ПО становятся аудиокассеты для магнитофонов.



Хранение на кассете обычно было в виде одного или двух бинарных файлов, все остальное содержалось внутри. Надежность была очень низвая, приходилось держать 2-3 копии программы. Время загрузки тоже не радовало, энтузиасты экспериментировали с разным частотным кодированием, чтобы побороть эти недостатки. Я сам в то время еще не занимался профессиональной разработкой софта (не считая простых программ на бейсике), поэтому в деталях, как все было устроено внутри, к сожалению, не расскажу. Сам факт наличия на компьютере только ОЗУ по большей части определяло простоту схемы хранения данных.

Появление надежных и больших носителей информации


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

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

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

В те времена для меня еще не было открыто существование Linux, я жил в мире MS DOS и, позже, Windows, а писал на Borland Pascal и Delphi, иногда поглядывая в сторону C++. Для поставки продуктов в те времена многие использовали InstallShield ru.wikipedia.org/wiki/InstallShield, который вполне успешно решал все поставленные задачи развртывания и конфигурирования софта.



Эпоха интернет


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

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

Для себя я отметил, что в этот момент произошла смена поколений разработчиков (или это было только в моем окружении), и сложилось такое ощущение, что все старые добрые способы поставки были позабыты в один момент и все началось с самого начала: всю поставку стали делать наколеночными скриптами и назвали это гордо «Continuous delivery». По факту начался какой-то период бардака, когда старое позабыто и не используется, а нового попросту нет.

Я помню времена, когда у нас в компании, где я тогда работал (не буду называть), вместо того, чтобы делать сборку через ant (maven тогда еще не был популярен или вообще не было), народ просто собирал jar в IDE и безмятежно коммитил его в SVN. Соответственно, разворачивание заключалось в доставании файла из SVN и копированию его по SSH на нужную машину. Вот так просто и топорно.

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


RPM- и DEB-пакеты


С другой стороны, с развитием интернета все большую популярность стали набирать UNIX-подобные системы, в частности, именно в то время для себя я открыл RedHat Linux 6, примерно 2000г. Естественно, что и там были определенные средства для поставки ПО, согласно википедии, RPM как основной пакетный менеджер появился аж в 1995г, в версии RedHat Linux 2.0. И с тех пор и до наших дней система поставляется в виде RPM-пакетов и вполне успешно существует и развивается.

Дистрибутивы семейства Debian пошли похожим путем и реализовали поставку в виде deb-пакетов, что так же неизменно до наших дней.

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

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

Стоит заметить, что в настоящее время есть некоторые поползновения в сторону ухода от deb и перереход на snap-пакеты, но об этом позже.

Так вот, это новое поколение облачных разработчиков, которое не знало ни DEB, ни RPM, тоже потихоньку росло, набиралось опыта, продукты усложнялись, и нужны были какие-то более разумные способы поставки, нежели FTP, bash-скриптики и подобные студенческие поделки.
И здесь на сцену выходит Docker, эдакая смесь виртуализации, разграничения ресурсов и способа поставки. Это сейчас модно, молодежно, но нужен ли он для всего? Панацея ли это?

По моим наблюдениям, очень часто Docker предлагается не как разумный выбор, а просто потому, что об этом, с одной стороны, говорят в сообществе, и те, кто предлагают, только его и знают. С другой стороны, о старых добрых системах упаковки по большей части молчат — они есть и есть, свое дело делают тихо и незаметно. В такой ситуации другого выбора особо-то и нет — выбор очевиден — Docker.

Попробую поделиться опытом, как у нас проходило внедрение Docker, и что в результате получилось.


Самописные скрипты


Изначально были bash-скрипты, которые деплоили jar-архивы на нужные машины. Управлял этим процессом Jenkins. Это успешно работало, благо сам по себе jar-архив уже является сборкой, содержащей в себе классы, ресурсы и даже конфигурацию. Если сложить в него все по максимуму — то разложить его скриптом — это не самое сложное, что нужно

Но у скриптов есть несколько недостатков:

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

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

Это все очевидно ограничивает круг применения такого способа развертывания только простейшими системами. Настал момент это менять.


Docker


В какой-то момент к нам начали приходить свежеиспеченные мидлы, бурлящие идеями и бредящие докером. Что ж, флаг в руки — делаем! Было две попытки. Обе неудачных — скажем так, из-за больших амбиций, но недостаточности реального опыта. Надо ли было форсировать и доделывать любыми силами? Вряд ли — коллектив должен эволюционно дорасти до нужного уровня, прежде чем сможет использовать соответствующие инструменты. Ко всему прочему, используя готовые образы докера, мы часто сталкивались с тем, что там некорректно работала сеть (что, возможно, было еще связано с сыростью самого докера) или было сложно расширять чужие контейнеры.

С какими неудобствами мы столкнулись?

  • Проблемы с сетью в режиме bridge
  • Неудобно смотреть логи в контейнере (если они никуда не вынесены отдельно в файловую системы хост-машины)
  • Периодически странное зависание ElasticSearch внутри контейнера, причину так и не установили, контейнер официальный
  • Нудобно пользоваться шеллом внутри контейнера — все сильно урезано, нет привычных инструментов
  • Большой размер собираемых контейнеров — дорого хранить
  • Из-за большого размера контейнеров сложно поддерживать множественные версии
  • Более длительная сборка, в отличие от других способов (скрипты или deb-пакеты)

С другой стороны, чем Spring-сервис в виде jar-архива хуже деплоить через тот же deb? Реально ли нужна изоляция ресурсов? Стоит ли лишаться удобных инструментов операционной системы, запихивая сервис в сильно урезанный контейнер?

Как показала практика — в реальности это не нужно, deb-пакета хватает в 90% случаев.

Когда же все-таки старый добрый deb не срабатывает и когда действительно нам был необходим докер?

Для нас это было развертыванием сервисов на python. Множество библиотек, нужных для машинного обучения и отсуствующих в стандартной поставке операционной системы (а то, что там было — не тех версий), хаки с настройками, необходимость разных версий для разных сервисов, живущих на одной и той же хост-системе привели к тому, что единственным разумный способом поставки этой ядерной смеси оказался докер. Трудоемкость сборки докер-контейнера оказалась ниже, чем идея упаковать все это в отдельные deb-пакеты с зависимостями, да собственно никто в здравом уме за это бы и не взялся.

Второй момент, где планируется использовать докер — для развертывания сервисов по схеме blue-green deploy. Но здесь хочется получить постепенное увеличение сложности: сначала собираются deb-пакеты, а затем уже из них собирается докер-контейнер.


Snap-пакеты


Вернемся к snap-пакетам. Впервые они официально появились в Ubuntu 16.04. В отличие от привычных deb-пакетов и rpm-пакетов, snap несут в себе все зависимости. С одной стороны, это позволяет избежать конфликта библиотек, с другой стороны — это более значительные размеры результирующего пакета. Кроме того, это же может влиять на безопасность системы: в случае поставки snap за всеми изменениями включенных библиотек должен следить сам разработчик, который создает пакет. В общем не все так однозначно и всеобщее счастье от их использования не наступает. Но, тем не менее, это вполне себе разумная альтернатива, если тот же Docker используется только как средство упаковки, а не виртуализации.


Как итог, у нас сейчас в разумном сочетании используются как deb-пакеты, так и докер-контейнеры, которые, возможно, в отдельных случаях мы заменим на snap-пакеты.




К сожалению, не доступен сервер mySQL