Все знают о базовых практиках DevOps: Continuous Integration и Continuous Deployment, которые позволяют правильно выстроить процесс разработки, тестирования и деплоймента. Это в свою очередь радикально улучшает качество продукта, Time to Market, и ускоряет development pipeline. 

Но что делать после того, как вы построили CI/CD? Олег Миколайченко, Head of Infrastructure в SQUAD, в своей колонке для AIN.UA рассказал о 7 интересных практиках, которые ускорят разработку и будут полезными.

Олег Миколайченко, фото предоставлено автором

1. Dynamic development environment 

Для каждого Pull Request нужно создавать полностью отдельное окружение, со своим доменным именем, базой данных, всеми нужными зависимостями – полной копией production окружения, только в микромасштабе. В таком случае мы даем разработчику возможность не переживать о самостоятельной настройке своего окружения, получаем консистентную среду и избавляемся от вечной проблемы “локально работает”.

Инженерная рабочая практика –  описать в Jenkinsfile для сборки Pull Request набор шагов для создания отдельной копии namespace в Kubernetes, устанавливать приложение с помощью чарта (которое хранить, конечно, в этом же репозитории) и опционально конфигурировать параметрами.
На выходе для разработчика – DNS-имя, отдельный namespace, возможность триггерить redeploy. 

В зависимости от текущего вида инфраструктуры для разработки (локальное окружение, разное для всей команды || единственный сервер для команды, который постоянно ломается, etc) ускорение разработки может быть очень существенным. 

2. Autoscaling  

Автоматическое масштабирование должно быть заложено на этапе проектирования сервиса, а в 2021 году это должно быть сделано по умолчанию и без исключений. Сервис должен уметь легко параллелится, делать graceful shutdown, предоставлять информативные логи. Обязательно настраивать resource requests & limits. 

Каждый более-менее ресурсоемкий сервис необходимо выносить в отдельный node pool, и автоматически масштабировать на нагрузки.  Например, в AWS EKS есть Cluster Autoscaler  – в случае, если количество pod не вмещается в node pool – он добавляет нужное количество нод в пределах Autoscaling Group. Очень удобно. 

С автоскейлингом сервисов дела намного интереснее: конечно, можно опять же это делать с помощью  Horizontal Pod Autoscaler, минусы решения – он добавляет по 1 экземпляру пода. Это значит, что если у вас резко выросла нагрузка – нужно будет подождать, пока HPA будет добавлять по одному поду.
Моя рекомендация – делать скейлинг по событиям, а не по CPU Load + HPA.  И даже не по HPA + custom metric. Например, сервис работает с AWS SQS, и обрабатывает 10 задач в секунду. В какой-то момент, в очередь прилетает 1.000.000 задач. Конечно, можно подождать 27 часов, можно добавить HPA и подкидывать по 1 поду, но самое эффективное решение – отскейлить node pool, максимально насоздавать подов, и обработать все задачи за 30 минут. Как? KEDA – event-driven autoscaling. 

Event-driven auto scaling inside Kubernetes. Схема предоставлена автором

Инженерная рабочая практика – в чарте с приложением добавляем манифест ScaledObject, добавляем в параметр ссылку на AWS SQS очередь и конфигурируем scale factor. Указываем имя деплоймента, который будем скейлить. Мы в SQUAD реализовали, удобно, работает. 

Моя рекомендация – делать скейлинг по событиям, а не по CPU Load + HPA.

У KEDA миллион вариантов для скейлинга (Prometheus, Redis, Azure, Cloudwatch, etc), и один супер интересный – external. Все доступные скейлеры можно посмотреть в документации.  

В результате получается микросервисная архитектура, когда мы относимся с контейнерам как к стаду (Riding herd over your microservices), а не как к Single Point of Failure, обрабатываем задачи намного быстрее, экономим время на тушении пожаров от ручного масштабирования и не теряем данные, т.к. обрабатываем SIGTERM. 

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

3. Rate Limits 

Rate limits идет в паре с масштабированием и защищает приложение от перегрузки. По Теории Ограничений, у системы всегда есть узкое место, и наша задача – его определить. Очень часто это база данных, медленное холодное хранилище объектов, что угодно. Наша задача – отскейлить приложение до этого ограничения, и отдавать клиентам – 429 Too Many Requests. Всегда лучше отдать 429 ошибку, чем позволить приложению упасть, или в случае с базой данных – работать намного медленнее. 

Обратная сторона – на клиентах обязательно реализовывать Circuit Breaker шаблон, при котором клиент будет экспоненциально увеличивать таймауты между запросами к перегруженной системе. 

 Инженерная рабочая практика – добавить в стек Istio, использовать Local Rate Limit  и сайдкар в поде. Сайд эффект – получаем отличные realtime метрики от Istio по статус кодам, latency, в перспективе – получить трейсинг.  

В результате мы защищаем сервис от перегрузки, и разработчикам не приходится тратить свое время на поиск ошибки в стиле “пришло много трафика”, или “не справились с нагрузкой”. Второе – знаем ограничения системы, и можем более точно планировать. 

4. KubeFlow  

Когда Machine Learning эксперименты занимают месяцы, а у конкурентов часы – вы проиграете. Данные – новое золото, и тренировка не должна занимать слишком много времени. Distributed train позволяет запускать ворклоады на десятках серверов, а KubeFlow будет их масштабировать и управлять пайплайнами. 

Последний KubeCon + CloudNativeCon показал, что KubeFlow – лучший выбор для запуска ML ворклоадов. Установка и настройка очень сложные (чего только стоит сборка kfctl + ArgoCD), но результат того стоит. 

Это решение может сэкономить сотни часов для ML инженера. 

5. Dependencies with app 

Поставлять зависимости приложения с ним в комплекте – практика, которая поможет реализовать Dynamic development environment или будет полезна, когда разработчики занимаются инфраструктурой. Также подходит для автоматизации рутинных задач от клиентов – один манифест сделал, и работает у каждого.
Для реализации этой практики необходимо выбрать GitOps для инфраструктуры, в зависимости от облачного провайдера. Для GCP нормально работает Google Config Connector, в AWS я бы пока что не рискнул использовать AWS Controllers for Kubernetes, но есть отличная реализация от CNCF – CrossPlane.

CrossPlane sample architecture. Схема предоставлена автором

Суть состоит в возможности описать в YAML небольшие куски инфраструктуры (S3 бакеты, SQS очереди, см. поддерживаемые ресурсы)  и задеплоить их вместе с приложением. Контроллер подхватит изменения, и создаст нужную инфраструктуру. Удаление тоже работает – на событие “PR merge” – удаляется namespace, манифесты инфраструктуры, и контроллер удаляет эти ресурсы.

Инженерная рабочая практика – добавить небольшие куски в helm chart для динамических окружений, или дать отдать процесс создания частей инфраструктуры вашим клиентам – они сами делают изменение, оно проходит ревью и создается временный S3 бакет.

Таким образом разработчику не нужно ждать, пока DevOps подхватит его задачу на изменение инфраструктуры, а может сам решить свою задачу обычным PR. 

6. Knowledge sharing 

DevOps – это коммуникация, поэтому создаем как больше презентаций и митингов о том, как работает инфраструктура, как работает мониторинг, какие можно “вкусности” из этого получить и чем может быть полезно. 

Чем больше прозрачности – тем лучше. Чем лучше разработчик понимает “как оно работает в проде”, тем лучше он адаптирует приложение, и тем больше внедрит ведущих инженерных практик, которые приведут к лидерству на рынке за счет конкурентного преимущества. 

Проведите цикл из нескольких мероприятий “Как работает инфраструктура” для всех, кому это может быть интересно, и наблюдайте за ростом использования предложенных подходов. Одно дело скинуть ссылку на Grafana, и совсем другое – показать как добавить Prometheus SDK в приложение, нарисовать график, настроить оповещение в Slack.  Это работает, проверено. 

7. Monitoring & Alerting 

Единственный, кто должен сообщать о проблемах в системе – это мониторинг. Если к вам приходят клиенты (или пишут в support), работают с вашей системой – у вас нет мониторинга. Даже если это ваш QA или разработчик, который только что увидел 503 – ответ должен быть “Спасибо, мы знаем, получили алерт и отписались в чатике. Исправляем”. 

Компоненты в составе kube-prometheus-stack. Схема предоставлена автором

Самый простой вариант, который только может быть – helm install prometheus-community/kube-prometheus-stack. Вы получите базовый бандл метрик, графиков, и алертов, который покроет самые частые кейсы (забился диск, рестартится под, умерла задача) и покроет 80% проблем в Kubernetes кластере. 

Дальше желательно добавить long-term storage, описать метрики на приложениях в формате OTEL (OpenTelemetry) и сделать Infrastructure as a Code для алертов и графиков. 

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

Epilogue

В реальной жизни команда DevOps может сделать намного больше для бизнеса, чем CI/CD. Если ваши девопсы засиделись – отправьте им эту статью, или покажите архитектору, который принимает решения. 

Я лично даю гарантию, что каждая команда и компания, которая внедрит хотя бы одну практику из этой статьи – ускорит общий development pipeline, улучшит качество продукта и Time-to-market в диапазоне от 1% до ∞%. Если так случилось – подпишитесь на мой Telegram-канал “ДевОпс Инженер” – это будет лучшей благодарностью. 

Автор: Олег Миколайченко, Head of Infrastructure в SQUAD