Хабрахабр

Резервирование в Kubernetes: оно существует

Меня зовут Сергей, я из компании ITSumma, и я хочу вам рассказать, как мы подходим к резервированию в Kubernetes. В последнее время я много занимаюсь консультативной работой по внедрению разнообразных devops-решений для различных команд, и, в частности, плотно работаю по проектам с использованием K8s. На конференции Uptime day 4, которая была посвящена резервированию в сложных архитектурах, я выступал с докладом о резервировании «кубика», и вот его вольный пересказ. Только заранее предупрежу, что он является не непосредственным руководством к действию, а скорее, обобщением размышлений на указанную тему.

Но ведь в кубере всё балансируется само, скажете вы, всё масштабируется само, и если что-то произойдёт — поднимется само… То есть, при первом поверхностном исследовании темы, на вопрос, кто как подходит к резервированию K8s, интернет ответил мне «а зачем?» Многие думают, что кубер представляет собой такую магическую штуку, которая избавляет от всех инфраструктурных проблем и делает так, что проект никогда не упадет. В принципе мониторинг и резервирование — это два основных инструмента повышения отказоустойчивости любого проекта. У нас были идентичные площадки для размещения — либо это были виртуалки, либо это были железные серверы, к которым мы применяли три базовых практики: Но… мир не то, чем кажется.
Как мы подходили к процессу резервирования раньше?

  1. синхронизация кода и статики
  2. синхронизация конфигураций
  3. репликация бд

И вуаля: в любой момент мы переключаемся на резервную площадку, все счастливы, встаём-расходимся.

Первое, о чём говорит неофициальная документация — это поставить много машин, сделать много мастеров — их количество должно удовлетворять условиям достижения кворума внутри кластера, и чтобы на каждом из мастеров был поднят etcd, api, MC, scheduler… И, вроде как, всё замечательно: при выходе нескольких рабочих нод или мастеров из строя наш кластер перебалансируется, и приложение продолжит работать. А что нам предлагают для увеличения постоянной доступности нашего kubernetes-приложения? Но часто наш кластер находится в рамках одного центра обработки данных и это может вызвать определённые вопросы. Опять выглядит, как волшебство! Всё накрылось, нашего кластера больше нет. Что если приехал экскаватор и раскопал кабель, ударила молния, произошел вселенский потоп? Как подойти к резервированию с учётом этой стороны проблемы?

При этом с точки зрения кубера, инфраструктуры должны быть полностью идентичными. Прежде всего, у вас должен быть ещё один кластер в горячем резерве, то есть кластер, на который вы можете переключиться в любой момент. Необходимо чётко определить два набора приложений (deployment’ов, statefulset’ов, daemonset’ов, cronjob’ов и т д): какие из них могут работать на резерве постоянно, а какие лучше не запускать до непосредственного переключения. То есть если есть какие-то нестандартные плагины для работы с файловой системой, кастомные решения для ingress, они должны быть полностью идентичными на ваших двух (или трёх, или десяти, тут уж на сколько хватит денег и сил админов) кластерах.

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

Должны быть запущены приложения, которые в любой момент могут перехватить обработку трафика и позволят нашему проекту продолжить жить. Например, начнем с базовых сущностей кубернетеса — deployments – они должны быть идентичны. То есть если мы, умные люди, не употребляем никаких запрещенных веществ и не держим базу в K8s, то у нас в configmaps’ах должны быть настройки доступов до боевой базы (процесс резервирования которой построен отдельно). Если мы говорим о файлах конфигурации, то здесь нужно смотреть, должны ли они быть идентичны или нет. Ровно так же мы работаем и с secret’ами: паролями для доступа в базу, api-ключами; в любой момент времени у нас может работать либо боевой secret, либо резервный. Соотвественно для обеспечения доступов до резервного экземпляра базы данных мы должны иметь отдельный файл конфигурации (configmap). Следующая сущность на которой стоит остановиться — cronjob. Итого мы имеем уже две сущности kubernetes, резервные версии которых не должны быть идентичны боевым. Если мы поднимаем резервный кластер и поднимаем его полностью со всем включенными cronjob'ами — то, например, люди будут получать у вас по два письма одновременно вместо одного. Cronjob’ы на резерве ни в коем случае не должны быть идентичны набору cronjob’ов продакшен-кластера! Либо какая-то синхронизация данных с внешними источниками будет проходить два раза, соответственно мы начинаем болеть, плакать, кричать и ругаться.

Второй по популярности ответ после «а зачем?» — использование Kubernetes Federation. А как же нам предлагают организовать резервирующий кластер люди из интернета?

Это, скажем так, большой мета-кластер. Что это такое? То есть мы работаем с теми же сущностями, с теми же примитивами, как и с единичным кубером, только крутим-вертим не нашими физическими машинами, а целыми кластерами. Если мы представим архитектуру кубера — где у нас есть мастер, несколько нод, — то с точки зрения федерации у нас тоже есть мастер и несколько нод, только каждая нода — это отдельный кластер. Например, если мы запустили какой-то деплоймент через федерацию — он у нас задеплоится на каждый наш дочерний кластер. В рамках федерации у нас идет полная синхронизация федеративных ресурсов от родителей к потомкам. То есть мы взяли какой-нибудь configmap, задеплоили его через федерацию и затем уже, если нам что-то нужно подправить на конкретных кластерах, мы идем править на отдельном кластере, и это изменение уже никуда не будет синхронизироваться. Если мы возьмем какой-либо configmap, секрет, раскатим его на федерации — оно растечется во все наши дочерние кластеры; при этом федерация позволяет кастомизировать наши ресурсы на детях.

Секреты не поддерживались, работа с volume также не поддерживалась. Kubernetes Federation — не так давно существующий инструмент, и он поддерживает далеко не весь набор ресурсов, который предоставляет сам K8s: на момент публикации одной из первых версий документации там говорилось о поддержке только конфиг-мапов, деплоймента под реплика-сет, ingress. Особенно если мы любим развлекаться, — например, через custom resource definition передавать свои собственные ресурсы кубернетесу, — в федерацию мы их уже не затолкаем. Слишком ограниченный набор. С другой стороны, федерация позволяет гибко управлять нашим replicaset'ом. То есть как бы… очень похожее на правду решение, но заставляет нас периодически стрелять себе в ногу. И это все можно ещё и конфигурировать! Например, мы хотим, чтобы было запущено 10 реплик нашего приложения, по умолчанию федерация поделит это число пропорционально между количеством кластеров. Что тоже достаточно удобно. То есть можно указать, что на боевом кластере нужно держать 6 реплик нашего приложения, а на резервирующем кластере, для экономии ресурсов, либо для собственных каких-то развлечений — только 4 реплики нашего приложения. Но с федерацией нам приходится использовать какие-то новые решения, что-то додеплоивать на ходу, заставлять себя чуть-чуть больше думать…

Какие инструменты у нас вообще есть? Можно ли подойти к процессу резервирования кубера как-то попроще?

Система генерирует yaml’ики для наших контейнеров. Во-первых, у нас всегда есть некая ci/cd система, то есть мы вручную не ходим, не пишем на серверах create/apply.

И есть замечательная утилита kubectl, которая может работать с несколькими кластерами одновременно. Во-вторых, есть несколько кластеров, у нас есть либо одно, либо несколько (если мы умные) registry, которое мы тоже взяли и зарезервировали.

Есть какой-то пайплайн в ci/cd системе; сначала билдим наши контейнеры, тестируем и раскатываем приложения через kubectl на несколько независимых кластеров. Так вот: на мой взгляд, самое простое и верное решение для построения резервного кластера — это примитивный параллельный деплой. Соответственно, доставку конфигураций мы тоже решаем на этом этапе. Мы можем строить одновременные выкладки на несколько кластеров. По сравнению с федерацией не надо ходить после определения федеративного ресурса на каждый дочерний кластер и что-то переопределять. Можно заранее определить набор конфигураций для нашего боевого кластера, набор конфигураций для резервного кластера и на уровне ci/cd системы раскатывать продовое окружение в продовый кластер, резервное окружение — в резервный кластер. Какие мы молодцы. Мы это сделали заранее.

Во-первых, файловая система. Но… есть… я было написал, есть «корень всех зол», но их на самом деле два. Если мы храним файлы внутри кластера, то тут надо действовать по старым практикам, оставшимся со времён железных инфраструктур: например, синхронизировать lsync'ом. Есть какой-то PV, либо мы используем внешнее хранилище. Раскатываем всё на другие тачки и живем. Ну или любым другим предпочитаемым лично вами костылём.

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

Мы, во-первых, параллельно деплоим stateless-приложения. А теперь о том, как, в принципе, у нас будет происходить процесс переключения на резервную площадку в случае пожара. Очень важно в процессе переключения на резервную площадку обязательно посмотреть — нужно ли переопределять конфигурации? Они не влияют на бизнес-логику наших приложений, нашего проекта, мы можем постоянно держать два набора запущенных аппликейшнов, и они могут начать принимать трафик. У нас четыре варианта, как эти приложения в проде могут начать между собой взаимодействовать. Например, у нас есть продовый кластер кубернетес, есть резервный кластер кубернетес, есть внешняя база данных мастер, есть резервная база данных мастер. У нас может переключиться база, и получится, что надо в продовом кластере переключить трафик на новую базу, либо у нас может навернуться кластер — и мы переехали на резерв, но продолжаем работать с продовой базой, ну и третий вариант, когда у нас навернулось это, навернулось то, и мы переключаем оба приложения, переопределяем нашу конфигурацию, для того чтобы новые приложения уже работали с новой базой данных.

Ну и, собственно говоря, какие выводы из всего этого можно сделать?

Но дорого. Вывод первый: с резервом жить хорошо. В идеале вообще нужно жить с несколькими резервами. Но в идеале жить не с одним резервом. Часто бывало — и на моей практике это было. Во-первых, резерв должен быть как минимум, не в одном ДЦ, и, во-вторых, как минимум, у другого хостера. А резервные серваки в этой же стойке стояли… Проекты я, к сожалению, не могу назвать, как раз когда произошел пожар в дата-центре… Я такой: переключаемся на резерв!

И всё: толку от того, что в другом amazon лежит наш резерв? Или представьте себе, что Amazon забанили в России (а такое было). Так что повторюсь: держим резерв, как минимум, в другом ДЦ, а желательно — у другого хостера. Он тоже недоступен.

Определите базу отдельным сервисом, стучитесь в нее, как будто она у вас внутри кластера: если у вас навернётся база, вы в одном месте меняете ip и продолжаете жить счастливо. Второй вывод: если у вас в кубере приложение общается с какими-то внешними источниками (это может быть как база данных, так и какое-то внешнее api), обязательно определите его как сервис с внешним Endpoint'ом, чтобы в момент переключения не передеплоивать 15 ваших приложений, которые стучатся в ту же самую базу.

А ещё люблю делиться результатами этих экспериментов и вообще своим личным опытом. И напоследок: я «кубик» люблю, как и эксперименты с ним. Поэтому я записал серию вебинаров про K8s, велком в наш youtube-канал за подробностями.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»