Все знают о базовых практиках 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.
Инженерная рабочая практика – в чарте с приложением добавляем манифест 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.
Суть состоит в возможности описать в 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 – ответ должен быть “Спасибо, мы знаем, получили алерт и отписались в чатике. Исправляем”.
Самый простой вариант, который только может быть – 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