Знакомьтесь — Kapitan. Он поможет вам навести красоту и порядок в конфигурации Kubernetes.
Kapitan зарабатывает репутацию на отзывах довольных пользователей, и потому обходится без обширной документации и дорогого маркетинга. У нас достаточно звезд и пара упоминаний от блогеров и проповедников Kubernetes. Kapitan даже стал главным героем целой главы в книге. Что самое главное, он привлек внимание нескольких перспективных компаний, ведь Kapitan как никто другой умеет распутывать конфигурацию, завязанную морским узлом.
На kubernetes.slack.com #kapitan успел собрать небольшое, но преданное сообщество (присоединяйтесь!), поэтому мы гордимся своей работой :)
Многие до сих пор считают, что Kapitan — это смесь jsonnet и jinja, но они упускают суть.
В этом посте я расскажу, как Kapitan управляет деплоями Kubernetes, но вообще-то он способен не только на это. Это важно: Kapitan универсален и не зациклен на одном Kubernetes. Kubernetes — это просто один из множества вариантов использования.
Это не руководство (хотя руководства я тоже обещаю). Просто хочу рассказать, зачем мы его сделали и какие проблемы с деплоями конфигураций Kubernetes он должен решать.
Что мне не нравилось
Я начал экспериментировать с Kubernetes в 2015 и сразу влюбился.
Правда, есть несколько недостатков, с которыми я не хочу мириться:
- Контекст. Как по мне, это одна из самых сложных для понимания концепций Kubernetes — и одна из самых опасных. Контекст относится к клиенту, в нем трудно разобраться, он путано называется и создает неразбериху при запуске команд kubectl. Терпеть не могу контексты в kubectl!
- Многословная вложенная конфигурация (yaml!). Пришлось попотеть, чтобы разобраться в каждом уровне конфигурации yaml в манифесте. Какой смысл повторять ярлыки по два–три раза в нескольких местах?
- Бардак с императивными и декларативными командами. Новичков в Kubernetes побуждают учить императивные команды, хотя понятно же, что нормальные люди их не используют. По-моему, так только сложнее вписать Kubernetes в правильную стратегию деплоя для своей компании. Спойлер: нет никакой единой «правильной стратегии».
- Конфигурация рантайма. Прав Джесси Суэнь (Jesse Suen), когда советует не передавать параметры конфигурации в командную строку helm (или kubectl и иже с ними). С параметрами одна и та же команда может каждый раз выполняться по-разному.
- Конфигурация приложения. Мы научились управлять манифестами yaml в Kubernetes, мы молодцы. Вот только под и деплой — это пустая посудина. На ней еще должно плыть приложение со всей своей конфигурацией.
- Разработчики хотят праздника, а рабочий процесс в Kubernetes до сих пор какой-то невнятный. Фанаты Kubernetes заставляют всех прямо там и девелопить. А надо ли? Послушаемся Келси Хайтауэра (Kelsey Hightower)!
- Операторы. К ним у меня смешанные чувства, так что пока оставим эту тему :) Скажу только, что ими часто злоупотребляют.
- Идемпотентность. Вернее, ее отсутствие. Если сложить все недостатки выше, мы получаем недостаточно идемпотентные рабочие процессы, что печально для Kubernetes.
Что делать?
Я пытался решить эти проблемы и собрал маленькую систему шаблонизации, которая использовала j2cli и пару bash-скриптов, чтобы управлять конфигурациями Kubernetes.
Система засовывала все в файл environmentA.yaml и использовала его в шаблоне Jinja2. Деплоить приложения в стиле микросервисов из нескольких компонентов можно было простой командой:
bin/apply.sh environments/environmentA.yaml
Круто! В yaml было все о деплое. Очень удобно, ведь я мог использовать тот же файл как источник информации для чего-нибудь другого. Скажем, для… bash-скриптов!
Я додумался, как импортировать в скрипты значения из yaml, чтобы выполнять подобные команды:
bin/create_kafka_topics.sh environments/environmentA.yaml
А потом все разом вышло из-под контроля:
- Я ничего не мог поделать со структурой в файле yaml. Получалась мешанина из одинаковых полей, значений, спутанной конфигурации.
- Никогда не узнаешь, как поведет себя деплой в среде, пока не попробуешь. Часто это было связано с изменениями в шаблонах jinja2 из-за нового значения инвентаря (допустим, feature_X), который не работал в средах, где эта функция не определена.
- Такая же беда со скриптами: не попробуешь — не узнаешь.
- Иногда Kubernetes менялся так быстро, что меня доставало постоянно менять манифесты под разные версии, особенно возиться с аннотациями к значениям.
- Внешний фактор: команда разработчиков перешла с файлов конфигурации на параметры командной строки. Такое мелкое изменение спутало нам все карты, и пришлось задуматься о новом решении.
- Самое главное: шаблонизация yaml с Jinja (или шаблонами Go) — это НЕ ВЕСЕЛО! У нас тогда была загадка: «Что выглядит, как текст, читается, как текст, пахнет, как текст, но не текст?». Или, как метко выразился Ли Бриггз (Lee Briggs): «Какого рожна мы шаблонизируем yaml?»
Kapitan: становление
Мы собрали весь свой горький опыт и вместе с Рикардо Амаро (Ricardo Amaro) стали фантазировать об идеальной системе управления конфигурацией. Тогда у нас еще не было четкой картинки, но мы знали, что любим и что не любим.
Любим:
- Git.
- Шаблонизацию в общем: данные/значения отдельно от шаблонов.
- Отдельные значения для разных аспектов (приложение, Kubernetes, рантайм...).
- Объектно-ориентированный подход.
- Упрощенный yaml как интерфейс, куда спрятать сложности Kubernetes.
- Четкое понимание, что творится и зачем.
- Повторное использование значений в разных компонентах.
- А еще у скриптов должен быть доступ к значениям.
Не любим:
- Контексты kubectl.
- Движки текстовых шаблонов для создания yaml.
- Подсчет отступов:
{{ toYaml .Values.resources | indent 10 }}
. - Магию: все должно быть четко и ясно. Никаких фокусов.
- Ручное управление паролями и секретами приложения.
- Подход Tiller: мы хотели контролировать применение манифестов.
- Подход git-crypt: секреты на диске не зашифрованы.
- Конвейер шаблонов прямо в kubectl.
- Передачу параметров командной строки.
И тогда случилось две вещи:
- Мы открыли для себя jsonnet Дейва Каннингема (Dave Cunningham) для шаблонизации yaml/json на объектно-ориентированном языке.
- Густаво Буриола (Gustavo Buriola) показал нам reclass, и без него мы бы далеко не уехали.
Рикардо Амаро взялся за работу, и скоро вся команда засела за Kapitan — одни работали над основным функционалом, другие — над его использованием в наших внутренних проектах. Управление секретами, поддержка gpg\kms, пользовательские функции: теперь Kapitan — это полноценный продукт, который делает больше, чем обещал.
Кто такой Kapitan?
Kapitan пытается решить все (ну или почти все) проблемы, о которых я говорил.
С технической точки зрения Kapitan очень прост:
- Инвентарь: иерархическая коллекция значений, описывающих деплой, на базе yaml. На основе reclass. Как Hiera.
- Шаблонизаторы: сейчас это Jinja2, Jsonnet, Kadet. Они берут инвентарь и создают файлы (yaml, json, документация или bash-скрипты).
- Секреты: шаблонизируйте секреты, и Kapitan ими займется.
Мы вовсю используем jsonnet для шаблонизации манифестов и Jinja — для всего остального.
Иногда люди жалуются, что файл jsonnet совсем не похож на такой же yaml, поэтому им сложно перейти на jsonnet.
Мы попытались решить эту проблему с помощью Kadet, обернув yaml в Python. Возьмите за основу свой любимый yaml и прибавьте к нему Python.
Считайте, что это экзоскелет Python для yaml! Как-нибудь расскажу об этом.
В рабочем процессе Kapitan сразу показывает характер:
- Свобода выбора: мы не навязываем никакие рабочие процессы и технологии, но обычно работаем по описанным ниже принципам. Вообще-то Kapitan можно использовать как угодно. Вы не обязаны использовать git, не должны компилировать в нем файлы и даже можете обойтись без jsonnet! Делайте что хотите.
- GitOps до мозга костей: все в git, все в master-ветке, которая отражает наш замысел.
- Декларативность: Kapitan приветствует компиляцию шаблонов манифестов в конкретных представлениях. И вы компилируете свои скрипты.
- Контролируемый контекст: мы используем скомпилированные скрипты, чтобы упрощать себе работу, например, когда задаем контексты и конфигурируем кластеры.
Конфигурация Kubernetes:compiled/target_A/setup/setup.sh
Применение изменений:compiled/target_A/setup/apply.sh
- Идемпотентность: Kapitan позволяет менять шаблоны и инвентарь для рефакторинга кода. Скомпилированные манифесты и код не изменятся без вашей команды, так что вам нечего бояться при рефакторинге.
- Причина и следствие: мы за рабочий процесс, где изменения инвентаря или шаблонов и скомпилированные файлы входят в один мерж-реквест. Так проверяющий сможет оценить ваши изменения и их фактические последствия. Полезно знать, повлияет изменение в шаблоне на один, два или несколько целевых объектов.
- И наконец: Kapitan не привязан к Kubernetes. Он просто создает файлы. Деплоем изменений занимается kubectl. Мы только даем оболочку для команд, чтобы они выполнялись согласованно.
Оно мне надо?
Давайте проясним: вам, наверное, Kapitan (еще) не нужен.
Но все зависит от того, что вы пытаетесь сделать и насколько сложная у вас система.
Kapitan — это мощный инструмент, требующий инвестиций. Используйте его в сложных сценариях, где придется деплоить кучу приложений в куче кластеров.
Если у вас стандартные приложения, вы только изучаете Kubernetes или и так довольны своим рабочим процессом, то сойдет и Helm или его нынешняя альтернатива.
Я себе представляю Helm как apt-get для Kubernetes, а Kapitan — что-то типа Puppet.
В следующем посте я приведу конкретные примеры и подробно опишу инвентарь. Пишите, о чем вы хотите узнать или с чем вы согласны/не согласны в этом посте.
Спасибо Яцеку Гружевскому (Jacek Gruzewski).