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

Предыстория

Мы уже писали о собственном проекте Mondiad advertising platform. Это рекламная биржа с интерфейсом для конечного клиента, который позволяет создавать и размещать рекламные кампании. 

Сервера нашего проекта стоят в двух гео-разнесенных дата-центрах - один в Европе другой в США. Инфраструктура в дата-центрах не дублируется и зависит друг друга: в США у нас расположены некоторые сервисы, которых нет в Европе, такие как админка, UI и так далее. Европейская часть забирает служебную информацию для своей работы из дата-центра в США по выделенному каналу (и не может работать, если связь с США пропадает). Однако и в Европе нам прилетают довольно высокие нагрузки - в общей сложности мы обрабатываем там порядка 500 тыс. запросов в секунду.

Ранее мы рассказывали уже о том, как переезжали и модифицировали инфраструктуру в США. Сегодня речь пойдет о Европейском сегменте.

Инструменты, обеспечивающие работоспособность проекта - Kafka, Aerospike, кластер Clickhouse и полтора десятка серверов traffic exchange - функционируют как bare metal, т.е. на голом железе. Также есть дополнительные сервисы, необходимые для работы системы обмена трафиком и мониторинга. Они существуют в виде docker контейнеров. И до недавнего времени мы самостоятельно пытались группировать их по серверам, мониторить их состояние, масштабировать, а также обеспечивать их отказоустойчивость.

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

Kubernetes - проверенный инструмент. Забегая вперед отмечу, что переезд сервисов проходил штатно - мы запускали копию в Kubernetes, проверяли, что все хорошо, и переключали на нее трафик. Но, как говорится, есть нюансы, о которых и поговорим.

Миграция железа на фоне

Ранее мы писали о проблемах при переезде на новое железо в дата-центре в США, которая заставила нас попотеть. Здесь миграция прошла проще, хотя и несколько спутала нам карты при развертывании Kubernetes. На некоторой части машин память попалась глючная - машины саморебутились. 

По нашей просьбе в первые несколько месяцев хостер ее поменял и больше проблем не было, благо в европейском дата-центре железо довольно неплохое - blade-сервера Supermicro на десктопных процессорах AMD Ryzen 9 7950X. Из проблем у нас были только broken parts после нештатного перезапуска ClickHouse.

Для информации: в США сбои все-таки проявляются до сих пор, хотя и редко. Последний сбой был в сентябре. Хостер каждый раз меняет нам проблемные машины, в целом ситуация устаканилась, но не исправилась полностью. Возможно, дело в том, что в том дата-центре часть железа классом ниже. Примерно половина машин - AsRock на 5950X. Вторая половина (новая) - аналогичные европейскому дата-центру Supermicro на 7950Х.

Требование безопасности: спрятать сервисы Kubernetes внутрь

Из-за особенностей работы наших сервисов рассматривали несколько вариантов внедрения Kubernetes на bare metal.

Часто над уровнем железа запускают виртуализацию, выделяют ВМ и на них разворачивают Kubernetes. Этот вариант нам не подходил, поскольку предполагал еще один слой, с которым могут быть проблемы. Кроме того, нам пришлось бы на серверах писать свои правила для iptables/firewall и т.д.

Традиционно Kubernetes внедряется в облаке - в защищенной части сети. Снаружи обычно есть какой-то балансировщик и firewall, который и обеспечивает безопасность от внешнего мира. Но у нас все bare metal, одной ногой наружу, а значит нам нужно было думать, как реализовать это самостоятельно.

Фактически, у нас реализована внутренняя и внешняя сетки. С Kafka, Aerospike и кластером Clickhouse мы общаемся по внутренним адресам. Firewall развернут только на хостовых машинах, плюс через сетевой плагин можно что-то подкрутить. Но по большому счету все открыто на весь мир. Поэтому нашим основным требованием было, чтобы внутренние сервисы самого Kubernetes не “светились” наружу. 

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

В итоге мы остановились на официальном решении Kubeadm (https://kubernetes.io/docs/reference/setup-tools/kubeadm/), которое позволяет через конфиги настроить привязку компонентов Kubernetes к внутренним IP-адресам. Написали свою роль для ansible, которая деплоит kubeadm.

Для балансировки нагрузки на данный момент используем MetalLB в режиме L2. Но тестируем другие варианты.

Требование сервиса: сохранить IP-адреса клиентов

Одна из особенностей работы наших сервисов в том, что нам нужны реальные IP-адреса клиентов (а кроме того, часть ресурсов мы закрываем ACL, где тоже нужны адреса). Используемый нами сейчас MetalLB в связке с сетевым плагином CNI может работать в двух режимах:

  • externalTrafficPolicy: Local - в этом случае трафик пользователей попадает на те ноды где работают поды с сервисом. Минус - может быть неравномерная балансировка, если на ноде работает больше одного пода;

  • externalTrafficPolicy: Cluster - трафик попадает на все узлы кластера, но проходит через SNAT и мы теряем адрес клиента.

Поэтому хотя часть сервисов мы перенесли в Kubernetes, чтобы сохранить адреса нам пришлось публиковать их через CDN. Мы передаем адреса в заголовках, используя CDN по сути как балансировщик.

Миграция мониторинга

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

В связи с тем, что нам нужно было переехать на новое железо к определенной дате (а на нем запускали уже Kubernetes), сначала мы просто адаптировали то, что у нас было: написали для Prometheus и Alertmanager манифесты Kubernetes. Получился полуручной вариант: как только меняется набор серверов или набор собираемых метрик, автоматически генерируется конфиг Prometheus и деплоится в каждый инстанс. Далее отдельный контейнер в каждом инстансе, следящий за изменениями конфигов, делает reload Prometheus для перечитки конфига. Проще говоря, куда же без костылей на проде.

Только после окончания переезда мы начали разбираться с Prometheus Operator, который упрощает жизнь  конфигурирование и управление инструментов мониторинга. Вместе с ним внедрили и Thanos, который позволяет хранить метрики с разрежением в 5 и 60 минут (это нужно для метрик старше 90 и 180 дней, соответственно), закидывая данные в S3 нашего хостера. За счет этого мы отказались от объемных хранилищ в кластере. Также Thanos обеспечил продвинутое кеширование, что повлияло на скорость отображения данных в Grafana.

Сейчас все работает в полуавтоматическом режиме - нам нужно только добавлять, какие метрики и откуда надо собирать. Алерты мы пока не перевели и, вероятно, переносить не будем. Их слишком много, но живут они в одном месте - нам так удобнее.

Итоги

Kubernetes работает у нас уже около полугода. Пара не очень нагруженных сервисов в европейском дата-центре пока еще вне Kubernetes, но в ближайшем будущем мы планируем их также перенести, пытаясь все настроить так, чтобы работать без CDN как прокси, сохраняя IP-адреса клиентов. Пока мы только тестируем такой подход - обкатываем другой сетевой плагин Cilium, у которого есть встроенный механизм балансировки.

В целом управлять сервисами стало намного проще. Можно сказать, что мы подготовили почву для дальнейшего масштабирования проекта. Сейчас мы можем вручную увеличивать количество реплик, но в планах автоматизировать это через HPA - https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/

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

Поскольку в дата-центре, с которым мы работаем, нельзя выбрать конфигурацию машин - все идут в топовой конфигурации с AMD Ryzen 7950X (16 ядер, 32 потока) - мастер-ноды также запускают рабочую нагрузку.

Мы планируем аналогичный переезд в дата-центре в США. Сейчас получается, что некоторые сервисы мы деплоим двумя разными способами - в Европе все работает на Kubernetes, а в США в Docker. Это не очень удобно. Мигрировав в США на Kubernetes, мы упростим себе процесс. И там за счет возможности выбрать конфигурацию железа ожидаем больше экономии в деньгах.

P.S. Мы публикуем наши статьи на нескольких площадках Рунета. Подписывайтесь на нашу страницу в VK или на Telegram-канал, чтобы узнавать обо всех публикациях и других новостях компании Maxilect.

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