[Перевод] Руководство от ненавистника Kubernetes: как использовать эту технологию

fdb5628faaed5de559a895fc717e269a.png

Прим. переводчика: Пол Батлер — инженер-программист и создатель платформы Jamsocket для создания и управления сессионными бэкендами. В этой статье он делится своим опытом работы с Kubernetes, рассуждает о его сложности и объясняет, когда использование этой платформы может быть нецелесообразным. Мы перевели его материал и делимся с вами.

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

Я и сам причастен к этому, потому что делаю колкие замечания:

Могу иногда поворчать по поводу Kubernetes, но на самом деле это замечательная технология. Настоятельно рекомендую её всем моим конкурентам.

— Пол Батлер (@paulgb), 9 сентября 2022 г.

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

Мы в Jamsocket используем Kubernetes в production уже несколько лет, и я к нему приспособился. Можно сказать, что мы в компании научились пользоваться Kubernetes — привыкли к нему. Для этого нам пришлось позаимствовать часть возможностей K8s и сделать вид, что остальных не существует.

Этот материал я написал как внутреннее руководство по использованию Kubernetes, поэтому не факт, что он подойдёт для каждого стартапа. Но думаю, что это хорошая отправная точка, которая позволит избежать многих сложностей в необъятном мире Kubernetes.

Зачем использовать Kubernetes

На мой взгляд, Kubernetes — это оптимальный путь, если нужно:

  • запускать множество процессов, серверов или запланированных задач;

  • запускать их с избытком и балансировать нагрузку между ними;

  • настраивать их и отношения между ними как код.

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

Кто-то говорит мне, что второй пункт — перебор, а стартапам не стоит зацикливаться на развёртываниях с нулевым временем простоя или высокой доступности. Но мы часто выполняем множество развёртываний в день, и когда наши продукты ломаются, ломаются и продукты наших клиентов. Даже минуту простоя кто-нибудь да заметит. Скользящие обновления в Kubernetes позволяют нам чувствовать себя уверенно, часто выкатывать ПО и не гадать о последствиях.

Как мы используем Kubernetes

Для справки, Jamsocket — это сервис для динамического запуска процессов, с которыми может взаимодействовать веб-приложение. Что-то вроде AWS Lambda, но здесь время жизни процесса привязано к WebSocket-соединению, а не к одному запросу/ответу.

Мы используем Kubernetes для запуска длительных процессов, необходимых для поддержки такой функциональности. Сервер API, реестр контейнеров, контроллер, сборщик логов, ряд DNS-сервисов, сбор метрик и так далее.

Несколько вещей, для которых мы не используем Kubernetes:

  • Сами эфемерные процессы. Мы попробовали, но быстро поняли, что это мешает нам (подробнее об этом позже).

  • Статические/маркетинговые сайты. Для них мы используем Vercel. Да, это стоит денег, но всё же обходится дешевле, чем если бы тем же занимались наши инженеры (в стартапе каждый час инженерного времени на вес золота). Vercel экономит больше, чем стоит.

  • Всё, что непосредственно хранит данные, которые было бы жалко потерять. Мы используем постоянные тома для кэширования или производных данных, но в остальном полагаемся на managed-базу Postgres вне кластера и blob-хранилище.

Стоит также отметить, что мы не занимаемся администрированием Kubernetes самостоятельно — главное преимущество использования K8s состоит в том, что управление им можно передать на уровне инфраструктуры. Нас устраивал Google Kubernetes Engine, и хотя фиаско с Google Domains пошатнуло мою веру в Google Cloud, я всё равно сплю спокойно, зная, что переход на Amazon EKS будет относительно простым.

Какими ресурсами Kubernetes мы охотно пользуемся

Есть несколько типов ресурсов K8s, которые мы используем без колебаний. Здесь я перечисляю только те из них, которые создаются явно. Большинство затем неявно создают другие ресурсы, например поды. Их я не буду упоминать — понятно, что мы ими пользуемся, хотя и косвенно.

  • Deployment«ы: большинство наших подов создаются с помощью этих абстракций K8s. Каждый Deployment, критический важный для функционирования нашего сервиса, содержит множество реплик и поддерживает скользящие обновления.

  • Service«ы: в частности, ClusterIP для внутренних сервисов и LoadBalancer — для внешних. Мы избегаем сервисов NodePort и ExternalName, так как предпочитаем держать конфигурацию DNS за пределами Kubernetes.

  • CronJob’ы: для скриптов очистки и тому подобных вещей.

  • ConfigMap«ы и Secret«ы: для передачи данных вышеуказанным ресурсам.

Какие ресурсы Kubernetes мы используем с осторожностью

Некоторые ресурсы Kubernetes требуют более тщательного подхода и внимательного управления из-за их сложности.

  • StatefulSet и PersistentVolumeClaim: у нас был опыт со StatefulSet. Конфигурация немного сложнее, чем у развёртываний, зато у них есть постоянные тома, которые сохраняются при перезапусках. Однако мы предпочитаем хранить важные данные в управляемых сервисах за пределами K8s. Жёстких ограничений на тома у нас нет, потому что иногда полезно сохранить, например, кэш после перезапуска сервиса. Но я избегаю их, когда это возможно, потому что они могут мешать (взаимная блокировка) скользящим развёртываниям.

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

Каких ресурсов Kubernetes мы активно избегаем

  • Написание YAML вручную. В YAML достаточно ловушек, чтобы избегать его по мере возможности. Вместо этого определения ресурсов Kubernetes создаются из TypeScript с помощью Pulumi.

  • Невстроенные ресурсы и операторы. Я уже писал о том, что паттерн цикла управления — это палка о двух концах. С одной стороны, он отвечает за надёжность K8s, с другой — выступает источником косвенности и сложности. Паттерн операторов и кастомные ресурсы позволяют стороннему программному обеспечению использовать устойчивую инфраструктуру Kubernetes для своих контуров управления. В теории это отличная идея, но на практике она мне показалось неудобной. Вместо cert-manager мы используем инструмент для автоматизации сертификации Caddy.

  • Helm. Helm не годится из-за зависимости от операторов и отсутствия строгих правил для YAML. Также я считаю, что использовать неструктурированную строковую шаблонизацию для создания чего-то пригодного для машинного парсинга — это как добавлять хрупкость без какой-либо реальной пользы. nindent для меня — как мел, скрипящий по классной доске, ничего не могу с собой поделать.

  • Всё со словом «mesh» в названии. Наверное, они кому-то нужны, но не мне и не тем, кого я знаю.

  • Ingress-ресурсы. У меня не было проблем с ними, и я знаю, что кто-то использует их вполне продуктивно. Однако наш успех с Kubernetes базируется на простом принципе: не добавлять лишние уровни косвенности. Мы обходимся настройкой Caddy.

  • Попытка воспроизвести весь стек K8s локально. Вместо k3s или kind для точной репликации production мы просто используем Docker Compose или собственные скрипты, запускающие то подмножество системы, которое нас действительно интересует в данный момент.

Обновление от июля 2024 года

Я немного пересмотрел отношение к Ingress. Мы переносим некоторые пути из Caddy в Ingress-контроллер, так как тот хорошо интегрируется с Google Cloud Armor (инструмент для обеспечения сетевой безопасности). Я по-прежнему считаю, что Caddy был бы оптимальным выбором, если бы нам не требовался внешний балансировщик нагрузки на прикладном уровне. Было круто, когда трафик маршрутизировался внутри обычного контейнера K8s, — это сильно помогало наблюдаемости.

Почему Kubernetes не подходит для запуска интерактивных процессов

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

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

Какие существуют альтернативы Kubernetes

Для полноты картины должен отметить, что некоторые из появившихся альтернатив Kubernetes весьма неплохи. Особенно если для вас неактуален третий пункт из моего списка (возможность задавать инфраструктуру в виде кода). Для одного из наших продуктов мы решили использовать Railway вместо кластера K8s: в основном для preview-окружений. Часть моих друзей, которых я очень уважаю, поют дифирамбы Render. Я тоже пробовал его и считаю, что модель окружений Railway понятнее. Мне также импонирует подход Flightcontrol — «создай свое облако».

Для многих SaaS-приложений этих инструментов будет достаточно. Но если три пункта, перечисленные в начале статьи, для вас актуальны и вы применяете дисциплинированный подход, никого не слушайте: самое время переходить на Kubernetes.

P. S.

Читайте также в нашем блоге:

Habrahabr.ru прочитано 921 раз