ADG Оставить заявку
Блог DevOps 6 мин чтения

Helm 2 и ChartMuseum: управление пакетами Kubernetes в продакшне

Helm 2 с Tiller в кластере стал стандартом деплоя: внутренний ChartMuseum как репозиторий chart-ов, версионирование и rollback через helm upgrade/rollback.

Контекст момента

Helm 2 (октябрь 2016) и ChartMuseum - управление пакетами Kubernetes: chart-репозиторий, версионирование, rollback и интеграция с CI/CD

В феврале мы писали как настроили деплой микросервисов через GitLab CI с голым kubectl set image. Работает, но чем больше сервисов - тем больнее. У пятнадцати сервисов со своими ConfigMap-ами, Secret-ами, Ingress-ами и Deployment-ами ручное управление манифестами превращается в занятие «поправь в одном, забудь в трёх других». Helm решает именно это, и мы его наконец-то взяли в работу по-настоящему.

Что такое Helm и почему именно сейчас

Helm - пакетный менеджер для Kubernetes. Chart - это набор шаблонизированных манифестов с описанием зависимостей. helm install разворачивает всё одной командой; helm upgrade накатывает новую версию; helm rollback возвращает к предыдущей. Концептуально как apt или yum, только для K8s-ресурсов.

Helm 2 вышел в октябре прошлого года. До этого Helm 1 (он же Kubernetes Deployment Manager) был совсем другим инструментом - Google-проект, несовместимый с тем что сейчас. Helm 2 - перезапуск с нуля совместно с командой Deis, и это уже нечто рабочее. У нас он стоит в нескольких кластерах с марта, часть - уже можно назвать продакшном без кавычек.

Архитектура Helm 2: клиент helm на машине инженера или в CI-runner-е, и Tiller - серверная часть, под в кластере в namespace kube-system. Tiller принимает запросы от клиента и применяет манифесты к API-серверу. Tiller хранит историю релизов в ConfigMap-ах.

Почему нужен собственный ChartMuseum

Официальный репозиторий chart-ов - stable от Kubernetes - это хорошо для общеупотребительного софта вроде Prometheus или nginx-ingress. Но приложения клиента там нет, и не будет. Chart надо где-то хранить.

Вариант «просто папка с chart-ами в Git» работает для одного человека. При CI-пайплайне, когда runner должен скачать chart нужной версии, нужен HTTP-репозиторий с index.yaml - стандартный формат Helm.

ChartMuseum - это именно такой сервер. Разворачивается как Docker-контейнер, хранит chart-ы в S3-совместимом хранилище (или локально), отдаёт index.yaml, принимает helm push через HTTP. Запустить его проще чем настроить Nexus под Helm или городить nginx с руками собранным index.yaml.

У нас ChartMuseum живёт в том же кластере, в отдельном namespace helm-registry. Хранилище - отдельный persistent volume. Доступен только изнутри кластера и из CI-runner-ов через VPN.

Как выглядит CI-пайплайн с Helm

Пайплайн стал трёхступенчатым:

build -> push image -> helm package + helm push -> helm upgrade

Шаг «helm package + helm push». Chart лежит в репозитории сервиса в папке chart/. В .gitlab-ci.yml после сборки образа:

helm package chart/ --version $CI_PIPELINE_ID --app-version $CI_COMMIT_SHA
helm push myservice-$CI_PIPELINE_ID.tgz $CHARTMUSEUM_URL

Версия chart-а - номер пайплайна, appVersion - SHA коммита. Это позволяет однозначно связать версию chart-а с кодом.

Шаг «helm upgrade». В job deploy:

helm upgrade myservice $CHARTMUSEUM_URL/myservice \
  --install \
  --version $CI_PIPELINE_ID \
  --namespace production \
  --set image.tag=$CI_COMMIT_SHA \
  --set ingress.host=$DEPLOY_HOST \
  -f values-production.yaml

Флаг --install означает «если релиза нет - создать, если есть - обновить». Это решает проблему которая была с голым kubectl set image: первый деплой не отличается от последующих.

values-production.yaml хранится в репозитории. Секреты - нет: они передаются через --set и берутся из Vault, как мы описывали раньше.

Namespace-стратегия

На одном кластере у нас несколько проектов и два окружения - staging и production. Namespace-стратегия простая:

  • staging - один namespace для staging всех проектов одного клиента
  • production - один namespace для production
  • monitoring - Prometheus, Grafana, alertmanager
  • helm-registry - ChartMuseum

Имена релизов Helm уникальны в рамках всего кластера, не namespace-а. Поэтому релизы называем projectname-staging и projectname-production, чтобы избежать коллизий.

Tiller имеет права cluster-admin - это грубо, и мы это понимаем. После того как прочитали про RBAC в Kubernetes 1.6, в плане - ограничить Tiller правами только на нужные namespace. Пока не сделано: решение рабочее, кластер не публичный, риск оцениваем как приемлемый для текущего этапа.

Rollback: как это выглядит реально

Это, пожалуй, главное что Helm даёт сверх голого kubectl. Команда:

helm rollback myservice-production 0

Где 0 - предыдущая ревизия (можно указать конкретный номер). Helm берёт ConfigMap с историей релиза и применяет предыдущие манифесты. Это включает и Deployment (значит и версию образа), и ConfigMap сервиса, и всё остальное что было в chart-е.

На практике rollback занимает секунды - столько же сколько helm upgrade. При инциденте это ощутимо: не надо помнить SHA предыдущего коммита, не надо искать в логах пайплайна что за образ был до обновления.

История ревизий видна через helm history myservice-production. На каждой записи - статус (DEPLOYED / SUPERSEDED / FAILED), дата, описание (можно задавать через --description). Это работает как минимальный аудит-лог деплоев.

Что скрипит

Управление секретами в chart-ах - нерешённая задача. helm upgrade --set db.password=... передаёт секрет через аргумент командной строки, и он виден в helm history (в ConfigMap-е с историей). Есть плагин helm-secrets на базе sops, но мы его ещё не пробовали. Пока что секреты создаём как K8s Secret отдельно от Helm - chart предполагает что Secret уже есть, и только ссылается на него через secretKeyRef.

Версионирование chart-а и сервиса - когда chart меняется вместе с кодом, всё просто. Когда надо обновить только chart (например, поправить Ingress-аннотацию) без изменения кода - надо вручную задавать версию и помнить что appVersion не поменялась. Небольшое трение, но есть.

Tiller как единая точка отказа - если под Tiller-а упал или перезапускается, helm upgrade зависает. На практике Tiller стабилен, но ситуация неприятная: в момент деплоя Tiller недоступен, runner ждёт таймаута. Решения пока нет кроме мониторинга доступности Tiller-а.

Итог

Переход на Helm + ChartMuseum убрал две основные боли: «где манифест нужной версии» и «как откатиться». Пайплайн стал чуть длиннее, но зато деплой и rollback - одна команда с историей. Для сопровождения нескольких кластеров это меняет операционную картину - меньше ручного отслеживания «что где задеплоено».

Оставшиеся вопросы - управление секретами в chart-ах и тонкая настройка RBAC для Tiller-а. Первое важнее, займёмся на следующей итерации.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.