Є ідея гри чи геймінг-сервісу? Реєструйся на онлайн-хакатон 7.08! Призовий фонд — $3000
×Закрыть

Как удовлетворить все non functional requirements c помощью K8S

Я имею 20-ти летний опыт построения IT инфраструктуры как on premise, так и в облаках. За плечами — огромное количество проектов и опыта.

Эта статья поможет тем, кто ставит перед собой задачу разработки качественного ПО с использованием современных и действенных архитектурных решений. Любая автоматизированная система должна включать в себя ряд свойств, которые гарантируют стабильную работу. Их можно перечислять бесконечно долго, но здесь и сейчас хотелось бы выделить и рассмотреть ключевые архитектурные требования. Их много, но я выделю и опишу в этой статье всего пять ключевых: Availability (т.е. доступность), Maintainability (поддерживаемость, модифицируемость), Performance (производительность), Scalability (масштабируемость) и Security (безопасность).

Не только мой личный опыт, но так же и пример таких крупных публично-облачных провайдеров, как Google, Microsoft и Amazon показывает, что лучшее современное решение — это использование Kubernetes (k8s) . История k8s началась ещё в 2014 году, когда Google выложила в открытый доступ исходный код. С каждым годом становилось всё больше людей, которые оценили реализацию оркестровки контейнеризированных приложений. Я тоже нахожусь в числе этих людей и с уверенностью могу сказать, что Kubernetes — это game changer в области современных веб-сервисов.

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

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

Availability (доступность) — обеспечиваем работу ПО после возникновения ошибки

Какая самая главная черта качественного ПО? Всё очень просто — оно выполняет свои задачи тогда, когда нужно пользователю. Почти любое соглашение об уровне обслуживания (Service Level Agreement — SLA) предоставляет некоторые сведения о времени непрерывной работы ПО. Это зависит от конкретных требований к системе и как правило выражается в процентах:

Время простоя в годПроцентУровень доступности
8 ч, 45 мин, 57 сек.99,9%«три девятки»
52 мин, 34 сек.99,99%«четыре девятки»
5 мин, 15 сек99,999%«пять девяток»

Тут можно снова вспомнить Google, а точнее — Gmail. В 2013 году он был доступен в 99,978% случаев (~2 часов полной недоступности за год). Достижение доступности более 99% может быть сложнее, чем кажется на первый взгляд. Если заказчик будет запрашивать больше «трёх девяток», нужно учитывать, что такое решение будет достаточно дорого стоить.
Первое, о чем хотелось бы сказать с точки зрения человека, которому приходилось не раз сталкиваться с внезапными проблемами с физическими дисками, сетями и т.д., это то, что Kubernetes реально помогает в таких случаях. Мы просто брали и располагали сервис на 2-5 разных Node-ах (физических серверах), и даже если отказывал какой то один, то все остальные продолжали нормально работать (k8s позаботиться о том чтоб перезапустить приложение на доступных ресурсах).

В целом, есть несколько механизмов и объектов, с помощью которых приложение может работать на нескольких разных Podах (например, replica set), но я хотел бы особо отметить DeploymentSet.

Какие же возможности дает DeploymentSet для обеспечения максимальной доступности:

  • возможность создания и пересоздания множества Pod-ов. DeploymentSet также умеет быстро обновлять версию вашего контейнера (приложения) без простоя с помощь canary deployment. Детали можно прочитать по этой ссылке;
  • k8s автоматически следит за доступностью с помощью таких параметров как:
    • liveness — когда приложение работает уже достаточно долго, оно может сломаться и только перезапуск поможет его восстановить. Liveness пробы как раз и созданы для того, чтобы находить и исправлять такие ошибки;
    • TCP Liveness — этот тип liveness проб использует TCP сокет. Таким образом, k8s открывает сокет к контейнеру на определённый порт. Если соединение будет установлено — контейнер считается здоровым, если нет — плохим, и будет пересоздан;
    • readiness — если возникает ситуация, когда приложение временно не может справиться с трафиком, потому что зависит от внешних факторов или чего-то ещё, но оно вполне работоспособно и нет смысла его убивать (так же как и нет смысла отправлять на него клиентские запросы), то можно использовать k8s readiness test для определения и нейтрализации таких ситуаций. То же самое касается и масштабирования. Если вам нужно увеличить масштаб развертывания на несколько копий, то пока новая копия не будет полностью готова, на нее нельзя отправлять трафик. Если не использовать readiness, то Kubernetes не будет ждать пока приложение полностью запустится и будет посылать трафик в новую (еще не готовую) копию. Поэтому для обеспечения большей жизнеспособности всего кластера перед запуском нужно делать readiness probe. Только после успешного её выполнения приложение может считаться готовым для того, чтобы на него поступал трафик. Readiness настраиваются так же, как и liveness пробы. Тут можно выбирать между тремя типами проверок (probes): HTTP, Command (если нет возможности или желания запускать HTTP-сервер) и TCP (если Kubernetes может установить TCP соединение, то контейнер считается исправным и готовым к работе);
  • всё, что создано под DeploymentSet будет им отслеживаться и контролироваться. То есть , в случае проблем с той же физической Node-ой, deploymentset пересоздаст ваши контейнеры на другой Node.

Если что-то всё таки сломалось в самом k8s, то приложение скорее всего продолжит свою работу без проблем.

В k8s есть много компонентов и многие из них очень важны. Но,пожалуй, одним из самых важных является Etcd, который позволяет любому узлу в кластере записывать и считывать данные.

Для всех данных, которые связаны с кластером, k8s использует etcd в качестве хранилища данных. Это значит, что в etcd хранится абсолютно всё, включая информацию не только о модулях, но и целых кластерах. Поэтому etcd нужно уметь справляться со сбоями без потери данных.

Критически важно обеспечить etcd правильную работу, потому что это, по сути, — мозг всего кластера. Etcd может работать с несколькими репликами.

Иногда в системе всё же случаются какие-то непредвиденные ошибки или сбои. Чтобы избежать потери критически важных данных, советую периодически делать резервное копирование в etcd, чтобы их можно было легко восстановить после сбоя.

Для того, чтобы сбой кластера etcd не привёл к потере резервной копии, нужно регулярно делать резервные копии и хранить их где-то изолировано от места работы кластера. Когда нужно записать текущее состояние данных в кластере, можно использовать команду etcdctl через интерфейс командной строки.

Maintainability (поддерживаемость/модифицируемость)

В ISO/IEC 25010 проводится различие между понятиями Maintainability и Modifiability, хотя по сути у них один и тот же смысл — они описывают простоту применения изменений к продукту или системе.

  • Maintainability — степень эффективности и результативности, с которой продукт или система могут быть изменены;
  • Modifiability — степень, в которой продукт или система могут быть эффективно и действенно модифицированы без внесения дефектов или ухудшения качества существующего продукта.

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

Такие изменения могут быть во-первых слишком дорогими, а во-вторых — слишком рискованными.

В случае использования Kubernetes — это декларативное описание состояния, к которому должно стремиться приложение.

Мы можем без проблем добавить 2-5 контейнеров, при этом не останавливая наше приложение (с помощью DeploymentSet, про который мы говорили выше).

В основе управления k8s лежит использование подхода IaC (Infrastructure as Code), который даёт такие преимущества:

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

В k8s реализованы различные подходы, которые позволяют обновлять и изменять приложение без его остановки, точно так же, как и работать с самим кластером.

Performance (производительность)

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

Рассмотрим некоторые ключевые характеристики производительности:

  • максимальная пропускная способность канала связи в цифровой системе;
  • время отклика — общее время, которое требуется с момента, когда пользователь делает запрос, до получения ответа;
  • задержка — время, между получением стимула и реакцией системы на него;
  • максимальная скорость, с которой что-то может быть обработано; количество «чего-то» за «единицу времени». Например, транзакций в секунду, количество бит в минуту или
  • количество одновременных пользователей в данный момент времени.

Когда мы запускаем какое-либо приложение, в первую очередь нам нужно понимать как оно ведёт себя при развертывании. Мы использовали Kubernetes для проверки производительности в кластере, изучая контейнеры, модули и службы. Эта информация помогает оценить производительность приложения в целом, а также выявить отдельные слабые места, над которыми ещё нужно поработать.

Сразу хочу сказать, что напрямую с помощью Kubernetes повлиять на производительность (если она изначально не очень хорошая) сайта или приложения мы, конечно же, проблематично. Однако, со своей стороны мы имеем возможность сделать всё, чтобы нашему приложению было комфортно работать на имеющихся мощностях. Отличным решением для такой задачи будет использование Horizontal Pod Autoscaler и Send feedback
Vertical Pod autoscaling
. Принцип работы Horizontal Pod Autoscaler можно посмотреть на графике ниже:

Horizontal Pod Autoscaler — это контроллер который переодически проверяет наши Podы на нагрузку. Он запрашивает информацию об использовании ресурсов по метрикам в течение каждого определенного периода. Он получает её либо из API метрик ресурсов, либо из пользовательского API метрик. Контроллер рассчитывает значение использования в процентах от эквивалентного запроса ресурсов для контейнеров в каждом модуле. Затем он берёт среднее значение использования и выдаёт соотношение, которое используется для масштабирования количества требуемых реплик.

Подробнее об этом инструменте можно почитать по ссылке.

Как альтернативу можно использовать и Vertical Pod Autoscaler который позволяет увеличивать мощность нашего Pod-a в зависимости от нагрузки. Грубо говоря, Vertical Pod Autoscaler освобождает вас от необходимости думать о том, какие значения указывать для процессора и памяти Pod-a. Autoscaler может рекомендовать значения для запросов и ограничений процессора и памяти или может автоматически обновлять ваши Pod-ы поднимая ресурсы для них.

Scalability (масштабируемость)

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

Есть несколько взглядов на то, что же понимать под термином «масштабируемость»:

  • это способность системы, сети или процесса справляться с растущим объёмом работы или её потенциал для удовлетворения этого роста;
  • это способность системы расширяться для удовлетворения потребностей бизнеса;
  • это способность системы обрабатывать увеличение нагрузки без влияния на производительность системы ( или способность легко расширяться).

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

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

Для того, чтобы решить эту задачу, используя k8s, нужно будет ещё раз обратититься к Horizontal Pod Autoscaler или Vertical Pod Autoscaler, о которых мы говорили в предыдущей части. Они используется когда нужно удовлетворить растущие требования к приложению за счёт изменения количества Pod-ов или ресурсов на Pod-ах, на которых выполняются рабочие нагрузки. в случае, если обнаруживается какая-нибудь проблема с производительностью, число узлов автоматически увеличивается в соответствии с требованиями приложения. Если наоборот есть узлы с маленьким количеством запущенных Podов, при их обнаружении число узлов соответственно снижается.

Что же делать когда физически не хватает ресурсов и Nod-ы так же закончились и наш k8s не может физически найти место для Pod-ов?

Для этого Cloud провайдеры придумали простое решение — увеличивать количество Node для того чтоб кластер мог быстро создавать новые Podы. Типовыми реализациями данного подхода будут такие облачные хостинги как Amazon EKS и Azure Kubernetes Service с решением Cluster Autoscaler. Cluster Autoscaler — это инструмент, который автоматически настраивает размер кластера Kubernetes, когда выполняется одно из следующих условий:

  1. Существуют Pod-ы, которые не удалось запустить в кластере из-за недостатка ресурсов.
  2. В кластере есть узлы, которые не использовались в течение длительного периода времени, и их модули могут быть размещены на других существующих узлах, в таком случае кластер просто поможет вам сэкономить деньги за счет удаления ненужных Nod.

Security (безопасность)

Конфиденциальность, целостность и доступность — так выглядит модель информационной безопасности. Обычно при разработке/тестировании безопасности должен присутствовать эксперт по безопасности.

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

Техника моделирования угроз, которой пользуюсь я, состоит из 5 ключевых шагов: определение элементов (компонентов и модулей), определение угроз, документация угроз, оценка угрозы, определение контрмер.

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

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

Итак, для сканирования образов Kubernetes могу посоветовать Anchore.

Anchore интегрируется со средой k8s с помощью контроллеров доступа, что в свою очередь обеспечивает возможность развертывания только тех образов, которые соответствуют политикам пользователя. Он может быть развернут как автономно, так и как служба, работающая в среде Kubernetes. Кроме сканирования образов контейнеров, Anchore проводит много дополнительных проверок, например лицензии ПО, Dockerfile, утечки данных и многое другое. Предоставляется как свободная лицензия (Apache), так и коммерческая лицензия, которая обладает дополнительными возможностями.

Для обеспечения безопасности запущенных контейнеров подойдёт Sysdig open source.

Sysdig поддерживает исполняемые среды для контейнеров k8s. Анализировать кластер можно несколькими способами: запустить интерактивный интерфейс с помощью плагина kubectl dig или провести захват состояния системы через kubectl capture.

Sysdig предоставляет мощные инструменты с открытым исходным кодом. Его услугами пользуются такие компании как Olx, Pixar, Booking.com, Quby и другие, а общее число пользователей по всему миру в настоящее время — 274 428.

Немаловажным является также сетевая безопасность в кластере Kubernetes, для этого мы можем использовать Istio.

Istio — это открытая платформа для подключения, управления и защиты микросервисов. Не смотря на то, что это относительно новый продукт, он уже успел зарекомендовать себя как отличное решение как в плане отказоустойчивости, так и в плане безопасности. В Istio реализовано специализированное решение, которое полностью отделено от сервисов и функционирует через вмешательство в сетевое взаимодействие. Имеющийся набор функций по обеспечению сетевой безопасности в Istio включат прозрачное шифрование TLS для улучшения протокола коммуникации до HTTPS. Также там есть собственная система RBAC, которая служит для разрешения или запрета обмена данными между рабочими нагрузками в кластере.

Отдельно хотелось бы выделить Kube-hunter, которым пользуются для проведения аудита безопасности Kubernetes.

Kube-hunter помогает выявить удаленное выполнение кода, раскрытие данных и другие потенциальные уязвимости в кластерах. Его можно запускать как Pod внутри кластера, так и как удаленный сканер. В результате вы получите полный отчёт, который освещает проблемы конфигурации, которые делают кластер уязвимым для злоумышленников. Исходный код Kube-hunter доступен на GitHub.

Хочу сказать спасибо тем, кто дочитал статью до конца. А для тех, кто экономит своё время и сразу переходит к выводам, хочу вкратце обобщить всё, что написано выше:

  1. Пользоваться Kubernetes очень удобно. Надежность, гибкость, безопасность — это о нём.
  2. Чтобы повысить отказоустойчивость и доступность приложения — используем DeploymentSet. Тогда есть вероятность, что даже если что-то сломается, ни вы, ни пользователи этого просто не заметят.
  3. Периодически нужно делать резервное копирование Etcd и хранить его изолированно чтобы не потерять важные данные.
  4. В k8s можно обновлять приложения и добавлять новые контейнеры, не останавливая их работу (снова с помощью DeploymentSet).
  5. Напрямую производительность можно увеличить только апгрейдом. Если на данный момент не хватает мощностей и нет возможности их нарастить — пользуемся Horizontal Pod Autoscaler или Vertical Pod Autoscaler.
  6. Чтобы не возникало проблем с масштабируемостью — помогает тот же Horizontal Pod Autoscaler.
  7. Безопасность — наше всё. Для её обеспечения в Kubernetes рассмотрите Anchore, Sysdig open source, Istio, Kube-hunter. Не обязательно выбирать что то одно, можно использовать сервисы параллельно, но с осторожностью!

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

LinkedIn
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Воу крутая статья спасибо, все будущим SRE читать обязательно

Спасибо! Если отбросить усилия на вхождение в тему, итоговая конфигурация выходит не такой уж сложной в плане того же количества кода, например. То есть, может быть сложно выучить Кубер, зато потом достаточно легко решать им проблемы.

не буду оригінальним, дуже годно. Супер стаття!

Немаловажным является также сетевая безопасность в кластере Kubernetes, для этого мы можем использовать Istio.

Есть опыт внедрения и главное поддержки Istio в проде, например в пределах пары сотен микросервисов на k8s кластер?

очень-очень трики вопрос.. можно поделиться мыслями!

Два пива человеку! ))

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

всё, что создано под DeploymentSet будет им отслеживаться и контролироваться. То есть , в случае проблем с той же физической Node-ой, deploymentset пересоздаст ваши контейнеры на другой Node.

осталась самая малость — полностью переписать все stateful-приложения в stateless

я вообще против переносить stateful приложения в k8s. это идеологически не правильно :) , но можем обязательно подискутировать на эту тему.

а зачем он тогда вообще нужен, этот k8s? если туда легко засунуть только вебморду приложения, но не его бэкенд (операторы и прочее ведь далеко не для всего есть?)
просто потому, что стало популярно среды разработки поднимать в контейнерах и как это делать без них на проде уже никто внятно не представляет?

Удобно пилить бабло ) Просто раньше ничего не работало нормально, а теперь все так же не работает но в контейнерах.

На бэкэнде можно разделить сам аппликейшн(стейтлесс) и содержащую стейт базу данных

Тогда выходит что проще переехать на amazon lambda или другой serverless )

А почему идеологически неправильно -? меня интересует пример реальных stateful сервисов в классическом понимании с in-process стейтом и логикой в рамках того же процесса(akka/actors, всякий stateful stream processing (flink) , ms reliable services и т.д.) а не субд в контейнерах.

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

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

Сугубо мое мнение — чего не стоит делать на самом деле:
запускать в контейнерах то, что требуем максимальной утилизации подсистемы ввода вывода.
там очень высокие накладные расходы. Пример — БД.

P.S.
насчет операторов — их написание не такой сложный процесс, вполне посильный для специалиста уровня «ведущий».
АПИ k8s документировано, все довольно прозрачно, вагонище примеров.
Тут скорее сложность в том, чтобы понимать как работает то, что Вы хотите засунуть в контейнеры. На мой взгляд — это главная сложность

Сугубо мое мнение — чего не стоит делать на самом деле:
запускать в контейнерах то, что требуем максимальной утилизации подсистемы ввода вывода.
там очень высокие накладные расходы. Пример — БД.

но сами то наверняка не запускаете БД на baremetal, чтобы избежать этих накладных расходов?
накладные расходы (обычно это X%) будут при любой технологии виртуализации — это плата за остальные плюсы
другое дело, что использование нескольких разных платформ одновременно почти кратно увеличивают объемы/сложность сопровождения

А PersistentVolume/PersistentVolumeClaim нащо? Ставте якийсь CSI драйвер розподіленого чи відділеного стореджу, напишіть правильні клейми в ваших под темплейтах, і кубернетес буде монтувати ваші томи куди треба. В серйозних деплойментах дані все одно зберігаються в окремих підсистемах, а не на дисках підключених безпосередньо до сервера. Кубернетесу можна розповісти про топологію (які диски доступні з яких нодів) і він розкидатиме поди з урахуванням топології.

persistent volume не решают проблему stateful
и для реляционной СУБД, когда ее прибивают, а потом пытаются запустить на другой ноде — такой сценарий не является штатным (в том плане что успешность, несмотря на соответствующие встроенные в СУБД механизмы — не гарантируется)
это игра в русскую рулетку на регулярной основе

Толковая статья, спасибо !

Подписаться на комментарии