Если вы используете Docker, следующим логичным шагом кажется переход на Kubernetes, он же K8s, правильно? Ну, предположим. Однако решения, предназначенные для 500 инженеров-программистов, одновременно разрабатывающих одно приложение, достаточно сильно отличаются от решений для 50 человек. А решение для команды из 5 программистов — это и вовсе другая история.
Если вы работаете в маленькой команде, Kubernetes, вероятнее всего, не для вас. Он принесет вам много боли в обмен на крайне скромные преимущества.
Давайте разберемся, почему это может произойти.
Всем нравятся «движущиеся части»
У Kubernetes двигается и меняется очень многое: концепции, подсистемы, процессы, машины, код… И все это означает массу сложностей.
Несколько машин
Kubernetes является распределенной системой: в нем присутствует главная машина, которая которая контролирует остальные, рабочие. Каждая машина производит работу в контейнерах.
Итак, мы уже говорим минимум о двух физических или виртуальных машинах, необходимых только для того, чтобы всё это заработало. Но по факту вы получаете… всего одну машину. Если вы собираетесь масштабироваться (вот, где собака зарыта!), вам понадобятся три, четыре, а может, целых семнадцать виртуальных машин.
Очень, очень много кода
Кодовая база Kubernetes на начало марта 2020 года включает в себя более 580 000 тысяч строк кода на Go. И это только чистый код, исключая комментарии, пустые строки, а также вендорские пакеты. Security review 2019 года описывает кодовую базу следующим образом:
«Кодовая база Kubernetes имеет значительный простор для улучшения. Она велика и сложна, содержит крупные секции кода с минимальной документацией и огромное количество зависимостей, включая системы, не входящие в Kubernetes. Также в кодовой базе присутствует много случаев повторной реализации логики, которая могла бы быть централизована в поддерживающих библиотеках, что позволило бы сократить сложность, упростить внесение исправлений и снизить документальную нагрузку в различных областях кодовой базы».
Если честно, то же самое можно сказать и о многих других крупных проектах, но весь этот код должен корректно функционировать, если вы не хотите, чтобы ваше приложение отказало.
Архитектурная, операционная, конфигурационная и концептуальная сложность
Kubernetes — это комплексная система со множеством различных сервисов, систем и прочего.
Прежде чем вы сможете запустить свое единственное приложение, вам придется обеспечить следующую, сильно упрощенную архитектуру (оригинальное изображение взято из документации по Kubernetes):
Документация по концепциям K8s включает множество сугубо «образовательных» вещей, таких как приведенный ниже фрагмент:
In Kubernetes, an EndpointSlice contains references to a set of network endpoints. The EndpointSlice controller automatically creates EndpointSlices for a Kubernetes Service when a selector is specified. These EndpointSlices will include references to any Pods that match the Service selector. EndpointSlices group network endpoints together by unique Service and Port combinations.
By default, EndpointSlices managed by the EndpointSlice controller will have no more than 100 endpoints each. Below this scale, EndpointSlices should map 1:1 with Endpoints and Services and have similar performance.
На самом деле, мне понятно, о чем здесь речь, но обратите внимание, как много понятий требуется изучить: EndpointSlice, Service, selector, Pod, Endpoint.
И — да, большую часть времени вы не будете использовать все эти возможности. Следовательно, большую часть времени вам вообще не будет нужен Kubernetes.
Вот еще один случайный фрагмент:
By default, traffic sent to a ClusterIP or NodePort Service may be routed to any backend address for the Service. Since Kubernetes 1.7 it has been possible to route “external” traffic to the Pods running on the Node that received the traffic, but this is not supported for ClusterIP Services, and more complex topologies — such as routing zonally — have not been possible. The Service Topology feature resolves this by allowing the Service creator to define a policy for routing traffic based upon the Node labels for the originating and destination Nodes.
Вот что по этому поводу говорится в Security review:
Kubernetes — это большая система, обладающая значительной операционной сложностью. Команда оценки сочла, что конфигурация и развертывание Kubernetes — нетривиальный процесс, определенные компоненты имеют спорные значения по умолчанию, не хватает оперативного контроля, а меры безопасности определены неявно.
Сложности при разработке
Чем больше вы приобретаете в Kubernetes, тем сложнее становится нормальный процесс разработки: вам нужны все эти концепции (Pod, Deployment, Service, и т.д.) просто чтобы ваш код заработал. Таким образом, вам нужно раскрутить полноценную K8s систему даже просто для тестирования через виртуальную машину или вложенные контейнеры Docker.
И, поскольку ваше приложение становится труднее запустить локально, разработка усложняется за счет множества вариантов решения этой задачи, от стендового окружения до проксирования локального процесса в кластер (специально для этого я пару лет назад написал этот инструмент) и проксирования удаленного процесса на локальную машину…
Можно выбрать любой вариант, но ни один из них не будет идеален. Проще всего вообще не использовать Kubernetes.
Микросервисы (это плохая идея)
Второстепенная проблема состоит в том, что, поскольку ваша система позволяет вам запускать множество сервисов, вам приходится писать это множество сервисов. Плохая идея.
Распределенное приложение тяжело написать качественно. На самом деле, чем больше движущихся частей, тем больше эти проблемы мешают работе.
Распределенные приложения тяжело отлаживать. Вам понадобится совершенно новый тип инструментов отладки и логирования, которые все равно дадут вам меньше, чем логи монолитного приложения.
Микросервисы — это одна из техник масштабирования в организациях: когда у вас в штате 500 разработчиков, которые обслуживают один продуктивный веб-сайт, имеет смысл смириться со стоимостью крупномасштабной распределенной системы, если это позволит командам разработчиков работать независимо друг от друга. Таким образом, каждая команда из 5 человек получает единственный микросервис, и делает вид, что все остальные микросервисы являются внешними службами, которым не стоит доверять.
Если же вся ваша команда состоит из 5 человек, у вас 20 микросервисов и обстоятельства непреодолимой силы не вынуждают вас создавать распределенную систему, то где-то вы просчитались. Вместо 5 человек на 1 микросервис, как у больших компаний, у вас получается 0,25 человека.
Разве Kubernetes вообще не полезен?
Масштабирование
Kubernetes мог бы вам пригодиться, если вам требуется серьезное масштабирование. Тем не менее, давайте посмотрим, какие у вас есть альтернативы:
- Вы можете приобрести ВМ в облаке, и у них будет до 416 виртуальных CPU и 8 ТБ RAM, то есть совершенно невдолбительные мощности. Это влетит вам в копеечку, но будет крайне просто сделать.
- Многие простые веб-приложения можно масштабировать достаточно легким путем с помощью таких сервисов как Heroku.
Предполагается, конечно же, что увеличение количества рабочих ВМ также сыграет вам на руку:
- Большинству приложений не требуется существенное масштабирование, им будет достаточно качественной оптимизации.
- Узким местом масштабирования большинства веб-приложений являются базы данных, а не web worker'ы
Надежность
Чем больше движущихся частей, тем больше возможностей для возникновения ошибки.
Возможности Kubernetes, заточенные под увеличение надежности (health checks, rolling deploys), во многих случаях могут быть уже встроенными или реализованными гораздо проще. Например, nginx может делать health checks рабочих процессов, а еще можно использовать docker-autoheal или нечто подобное, чтобы автоматически перезапускать эти процессы.
Если же вас особенно волнует даунтайм, первой мыслью, которая вас посетит не должно быть «как мне сократить даунтайм при развертывании с 1 секунды до 1 миллисекунды), а должно быть «как мне убедиться, что изменения в схеме базы данных позволят откатиться, если я где-то накосячу?».
И если вам нужны надежные web worker'ы без единой машины в качестве точки отказа, есть много способов реализовать это и без Kubernetes.
Лучшие практики?
На самом деле, никаких Самых Лучших Практик не существует в природе. Есть только лучшие практики для каждой конкретной ситуации. Поэтому если что-то находится в тренде и пользуется популярностью, это вовсе не значит, что конкретно для вас это правильный выбор.
В каких-то случаях Kubernetes — это самый лучший вариант. В остальных — напрасная трата времени.
Пока вы не испытываете острой необходимости во всех этих сложностях, перед вами широкий выбор инструментов, которые решат ваши задачи: Docker Compose для одной машины, Hashicorp’s Nomad для оркестрации, Heroku и похожие системы для масштабирования и что-то вроде Shakemake для вычислительных конвейеров.
Послесловие от редактора
Будучи облачным провайдером, мы регулярно сталкиваемся с самыми разными клиентами, от небольших стартапов до крупных организаций со сложными бизнес-процессами и соответствующими запросами к инфраструктуре. Вне зависимости от того, насколько хороша технология, всегда найдутся прецеденты, в которых её применение обернется лишними трудностями. Всегда следует исходить из ситуации и аккуратно взвешивать плюсы и минусы доступных вариантов. Автор статьи несколько сгустил краски, но его посыл вполне понятен: иногда, чтобы принять правильное решение, стоит отвернуться от трендов и непредвзято оценить свой проект. Это и разработчикам силы сэкономит, и расходование ресурсов компании сделает более целесообразным.
Автор: it_man