На официальной странице 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]
В целом на этом всё.