Продолжение истории «Контейнерный хостинг или чем Kubernetes лучше Docker Swarm» где я описывал проблемы при построении облачного сервиса,а возможные решения выбирал между Docker Swarm и Kubernetes. Статья будет особенно полезна тем, кто практически не имея опыта, сомневается что выбрать в качестве оркестратора для своих проектов. Забавно будет почитать и тем, кто уже прошел по этим граблям и имеет свой собственный опыт, чтобы освежить в памяти какие‑то моменты или где‑то взглянуть по новому.

Зачем эта статья

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

Коротко о первой части

На момент написания той статьи, наш сервис работал на docker compose, горизонтального масштабирования не было, а основные проблемы, с которыми столкнулись на тот момент решали своими силами и, до последнего, казалось, что и на большом проекте можно обойтись без Kubernetes. Там обозначил несколько моментов, которые рекомендуется прочитать, так как некоторые из них будем затрагивать здесь.

Как перешли на Docker Swarm

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

1. Нельзя управлять контейнерами напрямую

Серьезный недостаток Swarm, который может быть не очевиден для начинающих с ним работать, поэтому выделен в первый пункт. Точнее говоря, управлять контейнерами можно через docker cli или docker api, но если выполнить например остановку контейнера или его перезапуск, то контейнер перестает быть частью сервиса Swarm, а становится отдельным контейнером. Для swarm сервиса он оказывается не упавшим, как можно было бы ожидать, а просто исчезнувшим, и вместо него запускается другой. Учитывая, что Swarm это часть проекта Docker это выглядит довольно странно. Все команды docker работают как обычно, а команды меняющие состояние контейнера ломают контекст его запуска. На первый взгляд, это не критичный недостаток, однако, это только на первый взгляд, да и призадуматься заставляет.

2. Нет поэтапного запуска

Как говорилось в первой части, — Swarm не имеет механизма поэтапного запуска контейнеров. Если имеется много контейнеров, то демон docker, при старте, начнет отвечать на команды и запросы апи только когда все контейнеры с автозапуском будут запущены, а на это может уйти уйма времени, и если в докере есть критически важные, для работы сервисы, то нет никакой возможности, как в Kubernetes, установить приоритет запуска. С compose приходилось ставить всем сервисам restart:no, при старте системы, критически важные контейнеры стартовали автоматически, остальные скриптом, а потом прослушивать по docker api падения контейнеров и стартовать их. С compose так не получилось. Из‑за его практической неспособности поднимать упавший контейнер по команде. Потому что, если через docker поднимать контейнер, то он «отрывается», как было описано в первом пункте. А если пробовать обновить контейнер через docker service update, то это вообще беда, о которой позже. В итоге, по этому пункту, пришлось всё же положиться на штатный перезапуск контейнеров.

3. Невозможно запустить упавший контейнер командой

Так как в swarm просто нет команд управления контейнерами. То если контейнер упал, а у него не включен автозапуск, то его нельзя запустить командой. Аналог команды docker start на уровне контейнера в swarm отсутствует. Должны же быть какие, то умные команды, которые дозапустят недостающие реплики сервиса!? Самое лучшее решение это костыль, который советуют сами разработчики Docker. Мол вы можете, сначала установить количество реплик на одну меньше, а потом сразу установить на нужное количество реплик и тогда недостающие реплики запустятся, так как параметры сервиса были обновлены. В принципе неплохое решение, но для запуска упавших контейнеров оно нам не подошло, потому что горизонтальное масштабирование docker service scale меняет версию сервиса и если в это самое время клиент запустит команду на деплой сервисов, или деплой сработает по событию от Гит, то происходит ошибка нарушения порядка версий out of sequence. Поэтому в нашем проекте, всё же решили положиться на штатный перезапуск упавших контейнеров. А проблему тяжёлого запуска, решили тем что добавили команду которая срабатывает при остановке Docker которая устанавливает всем не критически важным сервисам количество реплик в 0. А при запуске сервер считывает какое количество реплик должно быть и устанавливает после запуска docker.

4. С плагинами сетей не всё хорошо

Учитывая, что облачным сервисом могут пользоваться много разных людей, возникает вопрос о безопасности сетей друг от друга и безопасности сетей хост системы. Из коробки, на уровне узла, докер разделяет сети через iptables. Это не совсем удобный способ да и он будет эффективен только при однонодовом варианте. Поэтому при переходе на Swarm сразу хотелось использовать плагин, с помощью которого можно управлять политиками доступа сетей. Выбор был сделан в сторону Calico, однако она видимо дружила со swarm очень давно, и сейчас её если и можно как‑то подрубить под swarm, то это, судя по всему, уже никому не интересно из её разработчиков. Других плагинов пробовать не стал, потому что в тот момент уже зародилось твердое намерение, в будущем, переходить на Kubernetes. А это будущее всё ближе и ближе.

5. Нельзя перезапустить сервис

Это звучит дико, но когда в 2016 году самым первым ответом на обоснованный issue в github проекта moby, был ответ разработчика, — «а зачем вам перезапускать сервис?», а потом в этом же обсуждении теми же разработчиками давались такие советы.

  • 1. Установите количество реплик на 0, а потом сразу установите на нужное количество и тогда фактически сервис перезапустит все реплики.

  • 2. Используйте команду docker service update ‑force

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

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

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

Стоит ли использовать Swarm?

Я бы теперь так сказал. Если пользуетесь Docker,то попробуйте и Swarm. Но если планируете, что то под него программировать, то хорошенько подумайте. Да он выполняет свою функцию по запуску реплик и доступу к ним по сети. Но на долгосрочную перспективу вряд‑ли он сгодится. Потому что он во всем проигрывает Kubernetes, кроме простоты. А простота, сама по себе, даёт преимущества только на короткой дистанции.

Почему Kubernetes такой сложный

Изначально, когда я только начинал вникать в тему оркестратора. Я пользовался docker compose, мне этого хватало. И каждый раз, когда пытался познакомится с Kubernetes, ужасался его сложностью и не понимал всего хайпа вокруг него. Я видел что у докер есть оркестратор «из коробки» (Swarm) и мне не попадались обоснованные разборы его недостатков. При этом, приходилось видеть и положительные отзывы.

Теперь я понимаю, что такое отношение было из‑за отсутствия опыта. Сначала казалось, что нужно сделать только биллинг и подключить т. н. готовые инструменты, а на деле всё далеко не так просто. Когда сталкиваешься с программированием распределенной системы, перед тобой встают вызовы, пережив которые, ты абсолютно по‑другому начинаешь относится к сложности Kubernetes и понимаешь, что она оправдана на все сто процентов. После полутора лет скитаний, встреча с кубером, после принятия решения перехода на него, напоминала для меня, встречу с родителями, которые в детстве направляли на путь истинный, но ты хотел пойти своим путём и сам набить себе шишек. С другой стороны, не жалею, что так вышло. Зато, с низкого старта, удалось оформить прототип сервиса и получить результаты тестов и обратную связь. А самое главное, лучше разобраться в вопросе, применяя разные инструменты, и приобрести опыт, столь важный в нашем деле. Теперь главное, чтобы получилось переписать на кубер.

Если есть вопросы пишите, ожидаю обратную связь. Когда, со временем, узнаю что‑то интересное по теме, то постараюсь держать в курсе событий. Благодарю за внимание. Успехов вам во всех благих начинаниях!

P. S.: Кстати, для себя, сразу ещё хороший знак получил в пользу того, что пора учить Kubernetes, а не тешить себя надеждами о Swarm. Пока вникал в k8s, попробовал containerd, сразу решил попробовать CRI‑O и наткнулся на баг, оформил им issue https://github.com/cri‑o/cri‑o/issues/8999. Оказалось — это было пофикшено две недели назад. В мой дистрибутив ОС просто пока не дошла новая версия. Когда получается идти в ногу со временем, это вдохновляет?

Важное уточнение

Благодаря некоторым коментаторам, а особенно @mk2 я осознал, что всё это время неправильно понимал принцип работы механизма entrypoint. Почему то мне втемяшилось в голову, что он срабатывает один раз, только при старте контейнера. На содержании статьи это отражается в контексте такой уж большой важности именно перезапуска, а не пересоздания контейнера. Потому что раз entrypoint всё равно страбатывает при каждом старте, то разницы нет пересоздаешь ты контейнер или типо "перезапускаешь".

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

Комментарии (33)