На официальной странице Helm называет сам себя «The package manager for Kubernetes«, но на деле Helm нечто большее, чем просто менеджер пакетов для Kubernetes — скорее это система управления приложениями в Kubernetes, позволяющая выполнять их установку, отслеживать состояние, выполнять обновление, удаление.
В этом посте рассмотрим основные понятия и компоненты Helm, работу с чартами, шаблонами, переменными и репозиториями.
Пост больше обзорный, и не затрагивает многих нюансов, например — работу с версинированием релизов, зависимостями и т.д.
В отличии от самого Kubernetes — у Helm отличная документация.
Содержание
Архитектура Helm
Helm оперирует пакетами приложений для запуска в Kubernetes, которые в терминологии самого Helm называются chart (схема, или чертёж), и позволяет:
- создавать новые чарты с нуля
- упаковавать чарты в архив (tgz)
- вести совместную работу с чартами, используя общие репозитории
- устанавливать и удалять чарты в кластере Kubernetes
- управлять релизами установленных в кластере чартов
Концепты Helm
Три основных концепта Helm:
- chart: пакет информации, необходимой для создания приложения к кластере Kubernetes
- config: информация о настройках и параметрах, которые использутся chart-ом для создания инстанса приложения и управления его релизами
- release: работающий инстанс chart-а, связанный с определённым config-ом
Компоненты Helm
Helm можно разделить на две основных части — клиент, и набор библиотек.
- Helm client: утилита командной строки (весь Helm написан на Go), отвечает за локальную разработку чартов, взаимодействие с репозиториями чартов, управление релизами, и взаимодействие с библиотекой Helm — отправка новых чартов для установки, управление релизами запущенных приложений
- Helm library: предоставляет логику работы Helm, отвечает за взаимодействие с API Kubernetes-кластера, управляет чартами и их конфигами, релизами, установкой чартов в кластер, их обновление и удаление
Helm Charts
Итак, chart, чарт — набор файлов, описывающий определённый набор ресурсов Kubernetes, с помощью которого можно выполнить запуск пода с одним сервисом, например веб-сервер, или полноценное приложение, включающее в себя и веб-сервер, и приложения фронтента, бекнда, баз данных, систем кеширования и т.д.
Структура файлов
Чарты организованы в виде каталогов и файлов, где имя каталога верхнего уровня, содержащего другие директории и файлы будет именем такого чарта.
Например:
[simterm]
$ tree example-chart/ example-chart/ |-- Chart.yaml |-- charts |-- templates | |-- NOTES.txt | |-- _helpers.tpl | |-- deployment.yaml | |-- hpa.yaml | |-- ingress.yaml | |-- service.yaml | |-- serviceaccount.yaml | `-- tests | `-- test-connection.yaml `-- values.yaml
[/simterm]
Тут:
example-chart— каталог, имя чартаChart.yaml— файл с метаданными чарта, описывающий что это за чарт, содержащий информацию о версиях, зависимостях, авторе чарта и так далееcharts: чарт может содержать subcharts — они будут располагатьсяв этом каталогеtemplates— содержит файлы шаблонов, которые будут применены к кластеру для запуска приложения, используя шаблонизатор GoNOTES.txt— help-текст, который будет отображаться пользователямdeployment.yaml— пример манифеста с ресурсом Kubernetes Deploymentservice.yaml— пример манифеста с ресурсом Kubernetes Service
values.yaml— содержит значения по-умолчанию для шаблонов — Services, Deployments, и т.д.
Хватит теории — вперёд, к практике!
Подготовка окружения
Используем Minikube, kubectl, и Helm v3.
- minikube v1.9
- Kubernetes v1.18
- kubectl v1.18.2
- helm-3.2.0
Minikube — кластер Kubernetes
[simterm]
$ sudo pacman -S minikube
[/simterm]
Создаём кластер:
[simterm]
$ minikube start 😄 minikube v1.9.2 on Arch rolling ... 🌟 Enabling addons: default-storageclass, storage-provisioner 🏄 Done! kubectl is now configured to use "minikube"
[/simterm]
Проверяем:
[simterm]
$ kubectl cluster-info Kubernetes master is running at https://192.168.99.100:8443 KubeDNS is running at https://192.168.99.100:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
[/simterm]
Ноды кластера:
[simterm]
$ kubectl get nodes NAME STATUS ROLES AGE VERSION minikube Ready master 4m16s v1.18.0
[/simterm]
Установка Helm
Arch Linux — из репозитория:
[simterm]
$ sudo pacman -S helm
[/simterm]
macOS — Homebrew:
[simterm]
$ brew install helm
[/simterm]
Debian, etc — с помощью Snap:
[simterm]
$ sudo apt install snapd $ sudo snap install helm --classic
[/simterm]
И отличнейшная подсказка по helm help:
Создание Helm Chart
Далее — создадим свой чарт, обновим в нём шаблоны, и задеплоим какое-то приложение в Kubernretes.
Создаём новый чарт:
[simterm]
$ helm create example-chart Creating example-chart
[/simterm]
Его содержимое мы уже видели выше:
[simterm]
$ tree example-chart/ example-chart/ |-- Chart.yaml |-- charts |-- templates | |-- NOTES.txt | |-- _helpers.tpl | |-- deployment.yaml | |-- hpa.yaml | |-- ingress.yaml | |-- service.yaml | |-- serviceaccount.yaml | `-- tests | `-- test-connection.yaml `-- values.yaml 3 directories, 10 files
Содержимое его деплоймента:
[simterm]
$ cat example-chart/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "example-chart.fullname" . }}
labels:
{{- include "example-chart.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
...
[/simterm]
И Values:
[simterm]
$ cat example-chart/values.yaml # Default values for example-chart. # This is a YAML-formatted file. # Declare variables to be passed into your templates. replicaCount: 1 ...
[/simterm]
Тут всё достаточно очевидно — для replicas: {{ .Values.replicaCount }} в templates/deployment.yaml будет использовано значение replicaCount: 1 из values.yaml.
Но мы эти шаблоны использовать не будем — а напишем свой велосипед чарт.
Удаляем их:
[simterm]
$ rm -rf example-chart/templates/*
[/simterm]
Далее добавим свой ConfigMap.
Добавление template
Создадим файл example-chart/templates/configmap.yaml, а в нём — содержимое для файла index.html:
apiVersion: v1 kind: ConfigMap metadata: name: nginx-configmap data: index.html: "Hello, World
chart linter
Перед установкой чарта имеет смысл выполнить проверку синтаксиса чарта — используем helm lint:
[simterm]
$ helm lint example-chart/ ==> Linting example-chart/ [INFO] Chart.yaml: icon is recommended 1 chart(s) linted, 0 chart(s) failed
[/simterm]
chart install
Ещё раз проверим — на какой кластер настроен наш kubectl:
[simterm]
$ kubectl config current-context minikube
[/simterm]
Для установки выполняем helm install, которому первым аргументом передаём имя релиза, потом опции, и путь к файлам чарта.
Перед выполнением реальных действий имеет смысл выполнить «тестовый прогон» — используем --dry-run, и добавим --debug для деталей:
[simterm]
$ helm install example-chart --dry-run --debug example-chart/
install.go:159: [debug] Original chart version: ""
install.go:176: [debug] CHART PATH: /home/setevoy/Work/RTFM/example-chart
NAME: example-chart
LAST DEPLOYED: Sun May 3 13:17:07 2020
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
{}
COMPUTED VALUES:
affinity: {}
autoscaling:
enabled: false
maxReplicas: 100
minReplicas: 1
targetCPUUtilizationPercentage: 80
fullnameOverride: ""
image:
pullPolicy: IfNotPresent
repository: nginx
tag: ""
...
---
# Source: example-chart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-configmap
data:
index.html: "Hello, World"
[/simterm]
Ошибок нет — устанавливаем его:
[simterm]
$ helm install example-chart example-chart/ NAME: example-chart LAST DEPLOYED: Sun May 3 13:20:52 2020 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None
[/simterm]
Проверяем его статус:
[simterm]
$ helm get manifest example-chart --- # Source: example-chart/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: nginx-configmap data: index.html: "Hello, World"
[/simterm]
helm вывел информацию о ресурсах и файлах, которые были применены к релизу.
Проверим с kubectl:
[simterm]
$ kubectl describe cm nginx-configmap
Name: nginx-configmap
Namespace: default
Labels: app.kubernetes.io/managed-by=Helm
Annotations: meta.helm.sh/release-name: example-chart
meta.helm.sh/release-namespace: default
Data
====
index.html:
----
Hello, World
[/simterm]
chart uninstall
Аналогично, для удаления используем helm uninstall и имя релиза:
[simterm]
$ helm uninstall example-chart release "example-chart" uninstalled
[/simterm]
Template переменные
Хорошо — всё работает, но сейчас все данные в нашем ConfigMap статичны.
Изменим это — включим в работу шаблонизатор.
Для helm достпен набор предопределённых значений, например — Release.Name, см. полный список в документации.
Редактируем шаблон нашего ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
index.html: "Hello, World"
И добавим своих переменных — удаляем текущий файл values.yaml:
[simterm]
$ rm example-chart/values.yaml
[/simterm]
И создаём его заново, но с одним полем — user: "Username":
user: "Username"
А затем используем переменную user в шаблоне:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
index.html: "Hello, {{ .Values.user }}"
Тут через .Values мы указываем обращение к нашему values,yaml, из которого helm должен подтянуть значение переменной user.
Применяем:
[simterm]
$ helm install example-chart example-chart/ NAME: example-chart LAST DEPLOYED: Sun May 3 13:35:49 2020 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None
[/simterm]
Проверяем:
[simterm]
$ kubectl get cm NAME DATA AGE example-chart-configmap 1 31s
[/simterm]
И содержимое:
[simterm]
$ kubectl describe cm example-chart-configmap
Name: example-chart-configmap
Namespace: default
Labels: app.kubernetes.io/managed-by=Helm
Annotations: meta.helm.sh/release-name: example-chart
meta.helm.sh/release-namespace: default
Data
====
index.html:
----
Hello, Username
[/simterm]
chart upgrade
Что, если мы хотим изменить значение Username?
Можно удалить релиз, и задеплоить заново, передав новое значение либо через редактирование values.yaml, либо через --set:
[simterm]
$ helm uninstall example-chart release "example-chart" uninstalled $ helm install example-chart example-chart/ --set user=NewUser
[/simterm]
Проверяем:
[simterm]
$ kubectl describe cm example-chart-configmap ... Data ==== index.html: ---- Hello, NewUser
[/simterm]
Другой вариант — вызвать helm upgrade, передать имя релиза и новое значение:
[simterm]
$ helm upgrade example-chart example-chart/ --set user=AnotherOneUser Release "example-chart" has been upgraded. Happy Helming! ...
[/simterm]
Результат:
[simterm]
$ kubectl describe cm example-chart-configmap ... Data ==== index.html: ---- Hello, AnotherOneUser
[/simterm]
helm package
Что бы передать наш чарт другим пользователем — можно его упаковать в tgz-файл.
Используем helm package, который создаст файл вида имя-чарта-версия-чарта.tgz.
Версию helm получит из метаданных чарта:
[simterm]
$ cat example-chart/Chart.yaml | grep version: version: 0.1.0
[/simterm]
Упаковываем:
[simterm]
$ helm package example-chart/ Successfully packaged chart and saved it to: /home/setevoy/Work/RTFM/example-chart-0.1.0.tgz
[/simterm]
И содержимое архива:
[simterm]
$ tar tf example-chart-0.1.0.tgz example-chart/Chart.yaml example-chart/values.yaml example-chart/templates/configmap.yaml example-chart/.helmignore
[/simterm]
Helm репозитории
Для передачи чартов используем helm-репозитории.
Раньше можно было запустить локальный репоизторий с помощью helm serve, но в Helm v3 его выпилили.
Для работы с репозиториями в V3 используем helm repo.
По-умолчанию в список репозиториев сразу добавляется репозиторий от Google:
[simterm]
$ helm repo list NAME URL stable https://kubernetes-charts.storage.googleapis.com/
[/simterm]
Running local Helm repo
Для того, что бы создать свой репозиторий — достаточно выполнить helm package чарта, после чего сгенерировать файл index.yaml в каталоге, который хранит архив.
В качестве бекенда для репозиториев может быть что угодно — от Github Pages, до AWS S3, см. The Chart Repository Guide.
Тут пример локального репозитория.
Создаём каталог, переносим в него архив:
[simterm]
$ mkdir helm-local-repo $ mv example-chart-0.1.0.tgz helm-local-repo/
[/simterm]
Инициализируем репозиторий:
[simterm]
$ helm repo index helm-local-repo/
[/simterm]
Содержимое:
[simterm]
$ tree helm-local-repo/ helm-local-repo/ |-- example-chart-0.1.0.tgz `-- index.yaml
[/simterm]
Что бы получить к нему доступ — запустим простой NGINX:
[simterm]
$ sudo docker run -ti -v $(pwd)/helm-local-repo/:/usr/share/nginx/html -p 80:80 nginx
[/simterm]
Проверяем подключение:
[simterm]
$ curl localhost/index.yaml
apiVersion: v1
entries:
example-chart:
- apiVersion: v2
appVersion: 1.16.0
created: "2020-05-03T14:04:44.896115358+03:00"
description: A Helm chart for Kubernetes
digest: afa314247a03c4c85f339bda665659f3ab13a5e8656336e14ed37ed7f31b5352
name: example-chart
type: application
urls:
- example-chart-0.1.0.tgz
version: 0.1.0
generated: "2020-05-03T14:04:44.895678349+03:00"
[/simterm]
Добавляем этот репозиторий в список зарегистрированных в локальном Helm:
[simterm]
$ helm repo add example-chart http://localhost "example-chart" has been added to your repositories
[/simterm]
Проверяем:
[simterm]
$ helm repo list NAME URL stable https://kubernetes-charts.storage.googleapis.com/ example-chart http://localhost
[/simterm]
Пробуем поиск чарта:
[simterm]
$ helm search repo example NAME CHART VERSION APP VERSION DESCRIPTION example-chart/example-chart 0.1.0 1.16.0 A Helm chart for Kubernetes
[/simterm]
Устанавливаем его:
[simterm]
$ helm install example-chart-from-repo example-chart/example-chart NAME: example-chart-from-repo LAST DEPLOYED: Sun May 3 14:15:51 2020 NAMESPACE: default STATUS: deployed
[/simterm]
Проверяем в Kubernretes:
[simterm]
$ kubectl get cm NAME DATA AGE example-chart-configmap 1 34m example-chart-from-repo-configmap 1 22s
[/simterm]
В целом на этом всё.






