Helm 2.8: stable-репозиторий закрывает типовые задачи, но Tiller беспокоит
Внедряем Helm 2.8 для управления деплоем в Kubernetes: stable charts работают, но широкие права Tiller - реальная проблема для production-кластеров.
Helm 2.8 - стабилизация chart-репозиториев и улучшенный Tiller RBAC
Helm 2.8 вышел в конце февраля, и мы наконец взялись за его нормальную обкатку на клиентских кластерах. Задача у нас конкретная: перестать деплоить приложения через голые kubectl apply -f и ворох самодельных bash-скриптов и перейти на что-то управляемое. Helm выглядит очевидным кандидатом - вопрос насколько stable-репозиторий реально закрывает потребности и что делать с Tiller.
Что принесла 2.8
Сам релиз без сенсаций. Две вещи, которые нас интересовали в первую очередь:
- Улучшения в
helm upgrade --wait. Флаг ждёт пока все поды из деплоя перейдут в Ready перед тем как отдать управление. В предыдущих версиях это работало ненадёжно - команда могла завершиться успешно пока поды ещё раскатывались. В 2.8 механика стала аккуратнее, хотя timeout по умолчанию всё ещё пять минут и его часто приходится поднимать. - Chart testing и стабилизация репозитория. Команда Helm проделала работу по унификации chart-ов в stable и incubator - появился официальный процесс ревью, CI-тесты для chart-ов. Это видно по качеству: chart-ы стали чуть предсказуемее.
Плюс привычные мелочи: улучшенный вывод helm status, доработки в helm lint, несколько исправлений в логике rollback.
Stable-репозиторий: что реально работает
Честно говоря, мы ожидали больше возни. stable-репозиторий в 2.8 неплохо покрывает типовой стек:
- nginx-ingress - ставится с первого раза, параметры через values достаточно гибкие чтобы не лезть патчить chart руками. Аннотации для ingress-объектов пробрасываются нормально.
- Prometheus и grafana - отдельные chart-ы, разворачиваются без сюрпризов. Интеграция между ними через values нормальная, хотя придётся потратить час на понимание какие именно значения за что отвечают.
- PostgreSQL - chart от stable достаточен для dev/test. Для production мы бы смотрели внимательнее на параметры persistence и resource limits - defaults явно рассчитаны на что-то скромное.
- redis - аналогично, sentinel-режим есть, но требует внимательной настройки.
Incubator честнее - chart-ы там разного уровня зрелости, некоторые явно написаны «чтобы было». Прежде чем брать что-то из incubator в production - читать chart руками, не надеяться на автопилот.
Главная ценность stable-репозитория не в том что он идеален, а в том что он даёт отправную точку. Вместо написания деплойментов, сервисов и configmap-ов с нуля - берёшь chart, смотришь какие values поддерживает, и либо используешь их либо делаешь fork и дорабатываешь под себя. Экономит время.
Tiller: вот где болит
Архитектура Helm 2 такая: Tiller - это серверный компонент, который живёт в кластере и от своего имени применяет манифесты через Kubernetes API. Проблема в том, что по умолчанию Tiller устанавливается с правами cluster-admin. Это значит что Tiller может делать в кластере буквально что угодно.
Для тестового кластера - ладно. Для production - это неприятно. Любой кто может взаимодействовать с Tiller получает возможность влиять на весь кластер, даже если у самого пользователя Kubernetes ограниченные права.
Официальный ответ на это - RBAC для Tiller. В 2.8 документация и helm init стали чуть лучше объяснять как это настраивать:
apiVersion: v1
kind: ServiceAccount
metadata:
name: tiller
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: tiller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: tiller
namespace: kube-system
Затем helm init --service-account tiller. Это стандартная рекомендация - создать отдельный ServiceAccount и привязать к нему роль.
Но подождите: мы только что привязали cluster-admin к ServiceAccount Tiller. Мы ничего не улучшили с точки зрения прав - Tiller по-прежнему может всё. Разница только в том что теперь это явно задокументировано в YAML, а не происходит по умолчанию. Это лучше чем совсем без ServiceAccount, но проблему не решает.
Более правильный подход - namespace-ограниченный Tiller: отдельный Tiller на каждый namespace, с правами только на этот namespace. Технически это возможно, но тогда теряется часть удобства: у вас несколько Tiller-экземпляров, и helm нужно явно указывать с каким работать через --tiller-namespace. Это неудобно и люди об этом забывают.
На наших managed-кластерах мы пока остановились на компромиссе: Tiller с cluster-admin, но в отдельном namespace, с ограниченным сетевым доступом и мониторингом кто и что через него деплоит. Неидеально, честно признаём.
Release management: что работает хорошо
Отвлечёмся от безопасности - там где Helm реально удобен, это управление релизами. helm history, helm rollback, helm diff (плагин) - это то с чем голые манифесты не конкурируют.
Типичный сценарий: деплоим новую версию приложения, что-то идёт не так, делаем helm rollback app 2 и через тридцать секунд кластер откатился к предыдущему состоянию. Причём Helm помнит историю - helm history app показывает все ревизии с временными метками и статусами. Для разбора инцидентов это полезно.
helm diff - отдельная радость. Плагин показывает что именно изменится в кластере перед применением upgrade - diff манифестов. Ревью деплоев стало понятнее.
Где мы сейчас
На двух клиентских кластерах Helm уже в работе. Типовые компоненты (nginx-ingress, prometheus, grafana) - через stable chart-ы, собственные приложения - через самописные chart-ы в git-репозитории.
Вопрос с Tiller остаётся открытым. Мы следим за дискуссиями в сообществе - там активно обсуждаются альтернативные подходы, в том числе идеи убрать Tiller из архитектуры совсем и сделать Helm чисто клиентским инструментом. Пока это обсуждения, не релизы - но направление понятно и разумное.
Пока работаем с тем что есть: Helm 2.8 решает реальные проблемы управления деплоем, но с Tiller нужно осознанно работать, а не принимать defaults как данность.