Недавно мы создали распределенную систему планирования cron-заданий на основе Kubernetes – захватывающей новой платформы для управления кластером контейнеров. Сейчас Kubernetes занимает лидирующие позиции и предлагает множество интересных решений. Одно из основных его достоинств – то, что инженерам не нужно знать, на каких машинах работают их приложения.
Распределенные системы по-настоящему сложны, и управление их службами – одна из самых больших проблем, с которыми сталкиваются операционные группы. Внедрить новое программное обеспечение в производство и научиться надежно управлять им – задача, к которой стоит относиться серьезно. Чтобы понять, почему обучение работе с Kubernetes важно (и почему это сложно!), мы предлагаем ознакомиться с фантастическим одночасовым переключением, вызванным ошибкой в Kubernetes. В этой статье объясняется, почему мы решили построить архитектуру на Kubernetes. Мы расскажем, как проходила интеграция Kubernetes в существующую инфраструктуру, приведем подход к построению (и улучшению) доверия надежности кластера Kubernetes, а также рассмотрим абстракции, которые мы реализовали над Kubernetes. Kubernetes – распределенная система для планирования работы программ в кластере. Вы можете приказать Kubernetes запустить пять копий программы, и он динамически запланирует их развертывание на рабочих узлах. Развертывание контейнеров происходит автоматически, что улучшает утилизацию ресурсов и экономит деньги. Мощные примитивы развертывания (Deployment Primitives) позволяют постепенно выкатывать новый код, а контексты безопасности (Security Contexts) и сетевые политики (Network Policies) – безопасно запускать разные проекты в одном кластере. В Kubernetes существует множество встроенных возможностей планирования. Планирование длительных (long-running) служб HTTP, демоны (daemonsets), которые запускаются на каждом узле кластера, cron-задачах, которые запускаются каждый час, и т.д. Если вы хотите узнать больше, Kelsey Hightower дал несколько отличных разъяснений: Kubernetes for sysadmins и healthz: Stop reverse engineering applications and start monitoring from the inside. Также существует отличное сообщество в Slack. Каждый инфраструктурный проект (надеюсь!) начинается с потребностей бизнеса, и наша цель заключалась в повышении надежности и безопасности существующей распределенной системы cron-задач. Наши требования: Если вы рассматриваете Kubernetes, имейте в виду: не используйте Kubernetes только потому, что другие компании используют его. Для создания надежного кластера требуется огромное количество времени, и бизнес-пример его использования не всегда очевиден. Инвестируйте свое время в разумный путь. Когда дело доходит до операционных услуг, слово «надежный» не имеет смысла само по себе. Чтобы говорить о надежности, сначала необходимо установить SLO (цель уровня обслуживания).
У нас было три цели: Наш базовый подход к построению первого кластера Kubernetes состоял в том, чтобы создать кластер с нуля, без применения таких инструментов, как kubeadm или kops, используя в качестве справочника Kubernetes The Hard Way. Мы развернули кластер с помощью Puppet. Построение кластера с нуля было хорошим решением по двум причинам: мы смогли глубоко интегрировать Kubernetes в нашу архитектуру и приобрели глубокое понимание работы его внутренних компонентов. Построение с нуля позволит интегрировать Kubernetes в существующую инфраструктуру.
Мы хотели бесшовную интеграцию с существующими системами для ведения журнала логов, управления сертификатами, секретов, сетевой безопасности, мониторинга, управления инстансами AWS, развертывания, прокси-серверов баз данных, внутренних DNS-серверов, управления конфигурацией и т.д. Интеграция всех этих систем иногда требовала небольшого творчества, но в целом интегрировать было легче, чем заставить kubeadm/kops сделать то, что мы хотели.
Мы уже доверяем существующим системам и знаем, как ими управлять,, поэтому хотели бы продолжать использовать их в новом кластере Kubernetes. Например, безопасное управление сертификатами является очень сложной проблемой, и у нас уже есть способ выпуска сертификатов и управления ими. Мы смогли избежать создания нового CA только для Kubernetes с надлежащей интеграцией. Мы должны были понять, как установленные параметры повлияли на настройку Kubernetes. Например, существует более дюжины параметров настройки сертификатов/центров сертификации, используемых для аутентификации. Понимание работы этих параметров облегчило отладку установки, когда мы столкнулись с проблемами аутентификации. В начале работы с Kubernetes ни один из членов команды раньше не работал с ним (за исключением некоторых случаев для игрушечных проектов). Как вы относитесь к таким утверждениям:, «никто из нас никогда не использовал Kubernetes», «мы уверены в том, что Kubernetes готов работать в производстве»?
 Мы спросили об опыте работы с Kubernetes нескольких сотрудников других компаний. Все они использовали Kubernetes по-разному или в разных средах (для запуска HTTP-сервисов, на голом железе, в Google Kubernetes Engine и т.д.).
Когда речь идет большой и сложной системе, такой как Kubernetes, важно серьезно подумать о вариантах использования. Нужно проводить эксперименты, укреплять уверенность в своей среде и принимать собственные решения. Например, вы не должны прочитать эту статью и решить: «Хорошо, Stripe успешно использует Kubernetes, поэтому и мы будем его использовать!»
Вот что мы узнали от сотрудников компаний, работающих с кластерами Kubernetes: В наших планах была очень сильная зависимость от одного из компонентов Kubernetes – контроллера cronjob. Этот компонент был в то время в состоянии альфа, что вызвало у нас беспокойство. Мы проверили его работу в тестовом кластере, но не могли сказать, будет ли это работать в производстве?
К счастью, все основные функции контроллера cronjob составляют всего 400 строк на Go. Чтение исходного кода быстро показало, что: Перед созданием кластера мы провели небольшое нагрузочное тестирование. Мы не беспокоились о том, каким количеством узлов сможет управлять Kubernetes (в наших планах речь шла о ~20 узлов), но действительно хотели, чтобы некоторые узлы могли обрабатывать как можно больше заданий cron (около 50 в минуту).
Мы провели тест на кластере из 3 узлов, где создали 1000 заданий cron, каждое из которых выполнялось раз в минуту. Каждое из этих заданий просто запускало bash -c 'echo hello world'. Мы выбрали простые задания, потому что хотели протестировать возможности планирования и оркестровки кластера, а его не общую вычислительную емкость.
Наш тестовый кластер не мог обрабатывать 1000 заданий cron в минуту. Мы заметили, что каждый узел будет запускать не более одного элемента в секунду, и кластер мог бы запускать 200 заданий cron в минуту без проблем. Поскольку мы хотели запустить только примерно 50 заданий cron в минуту, то решили, что эти ограничения не являются блокирующими и что мы могли бы справиться с ними позже, если потребуется. Вперед! Одна из самых важных задач, которые нужно выполнить при настройке Kubernetes, – запуск etcd. Etcd – это сердце вашего кластера Kubernetes. Здесь хранятся данные обо всех событиях в вашем кластере. Все компоненты Kubernetes, кроме etcd, являются stateless. Если etcd не запущен, вы не сможете вносить изменения в свой кластер (хотя существующие службы будут продолжать работать!).
На этой диаграмме показано, как именно etcd выполняет роль «сердца» вашего кластера Kubernetes. Сервер API – конечная stateless-точка перед etcd, каждый компонент кластера разговаривает с etcd через сервер API.

При работе необходимо учитывать два важных момента: Мы ставили цель перенести наши cron-задачи в Kubernetes без перебоев в работе. Секрет успеха успешных производственных миграций заключается не в том, чтобы избежать ошибок (это невозможно), а в том, чтобы спроектировать миграцию так, чтобы уменьшить последствия ошибок.
К счастью, у нас есть множество разных cron-задач для миграции в новый кластер. Были и некоторые задачи с низким уровнем приоритета, которые мы могли бы перенести с небольшим простоем.
Перед началом миграции мы создали простой в использовании инструмент, который при необходимости позволил бы перемещать задания вперед и назад между старыми и новыми системами менее чем за 5 минут. Этот простой инструмент значительно уменьшил влияние ошибок. Если во время переезда всплыла бы, например, зависимость, которую мы не планировали, ничего страшного! Мы могли бы просто переместить задачу обратно, исправить проблему и повторить попытку позже.
Вот общая стратегия миграции, которую мы использовали: В начале проекта ым установили правило: если Kubernetes делает что-то странное или неожиданное, мы должны провести расследование, выяснить причины и внести исправления.
Расследование каждого вопроса занимает много времени, но это очень важно. Если мы не будем обращать внимания на ошибки, то при работе в производственной среде обязательно столкнемся с проблемами.
После принятия данного подхода мы обнаружили (и смогли исправить!) несколько ошибок в Kubernetes.
Вот несколько обнаруженных во время исследования проблем: Раньше мы обсуждали упражнения на игровом дне в Stripe, и мы все еще делаем их. Идея состоит в том, чтобы придумать ситуации, которые, как вы ожидаете, произойдут в производстве (например, падение сервера API Kubernetes). Затем нужно преднамеренно воспроизвести эти ситуации в производстве (в течение рабочего дня с предупреждением), чтобы вы могли их обработать.
Выполняемые упражнения к кластере часто выявляли проблемы в мониторинге или конфигурационных файлах. Мы были рады обнаружить (и контролировать!) эти проблемы на ранней стадии, а не увидеть неожиданно через шесть месяцев.
Вот несколько упражнений с дня игры, которые мы использовали: Давайте кратко рассмотрим, как мы сделали систему на основе Kubernetes простой в использовании.
Наша первоначальная цель заключалась в разработке системы для работы cron, которую наша команда смогла бы легко обслуживать. Мы стали уверены в выборе Kubernetes, далее нужно было упростить для коллег-инженеров настройку и добавление заданий в cron. Мы разработали простой формат конфигурации YAML, чтобы для использования системы пользователям не нужно разбираться во внутренних функциях Kubernetes. Формат, который мы разработали: Мы не сделали здесь ничего интересного, только написали простую программу, чтобы взять за основу этот формат и на выходе получать конфигурацию в cronjob в Формате Kubernetes, которые мы применяем с kubectl.
Мы также написали тесты, чтобы гарантировать, что имена заданий не слишком длинные (имена cron-задач не могут превышать 52 символа) и что все имена уникальны. В настоящее время мы не используем cgroups для ограничения объема памяти на большинстве cron-задач, но планируем заняться этим вопросом в будущем.
Простой формат конфигурационного файла был прост в использовании, и поскольку мы автоматически генерировали определения заданий для Chronos и Kubernetes из одного и того же исходного описания, перемещение задания между любой системой было очень простым. Это было ключевой частью надежной работы постепенной миграции. Мониторинг внутреннего состояния кластера Kubernetes оказался проще, чем предполагалось. Мы используем пакет показателей kube-state-metrics для мониторинга и небольшую программу Go veneur-prometheus, чтобы собрать метрики в Prometheus. Показатели kube-state-metrics публикуют их в качестве показателей statsd для нашей системы мониторинга.
Например, вот диаграмма количества ожидающих контейнеров в нашем кластере за последний час. Ожидание означает, что они ждут назначения рабочего узла для запуска. Вы можете видеть, что в 11 утра был всплеск. Это потому, что многие наши задания cron работают на 0-й минуте часа.  У нас также есть монитор, который проверяет, чтобы в состоянии ожидания не осталось ни одного контейнера. Мы убеждаемся, что каждый блок начинает работать на узле в течение 5 минут, иначе получим предупреждение. Процесс настройки кластера Kubernetes и переноса наших cron-задач в новый кластер занял у нас пять месяцев при участии трех инженеров, работающих полный рабочий день.
Мы инвестировали в изучение Kubernetes, поскольку ожидаем, что сможем более широко использовать Kubernetes на Stripe.
Вот некоторые принципы, которые применяются при работе с Kubernetes (или любой другой сложной распределенной системы): Оригинал: Learning to operate Kubernetes reliably. CEO в Southbridge