Helm: Kubernetes package manager – обзор, начало работы

Автор: | 03/05/2020

На официальной странице Helm называет сам себя “The package manager for Kubernetes“, но на деле Helm нечто большее, чем просто менеджер пакетов для Kubernetes – скорее это система управления приложениями в Kubernetes, позволяющая выполнять их установку, отслеживать состояние, выполнять обновление, удаление.

В этом посте рассмотрим основные понятия и компоненты Helm, работу с чартами, шаблонами, переменными и репозиториями.

Пост больше обзорный, и не затрагивает многих нюансов, например – работу с версинированием релизов, зависимостями и т.д.

В отличии от самого Kubernetes – у Helm отличная документация.

Архитектура Helm

Helm оперирует пакетами приложений для запуска в Kubernetes, которые в терминологии самого Helm называются chart (схема, или чертёж), и позволяет:

  • создавать новые чарты с нуля
  • упаковавать чарты в архив (tgz)
  • вести совместную работу с чартами, используя общие репозитории
  • устанавливать и удалять чарты в кластере Kubernetes
  • управлять релизами установленных в кластере чартов

Концепты Helm

Три основных концепта Helm:

  1. chart: пакет информации, необходимой для создания приложения к кластере Kubernetes
  2. config: информация о настройках и параметрах, которые использутся chart-ом для создания инстанса приложения и управления его релизами
  3. 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 – содержит файлы шаблонов, которые будут применены к кластеру для запуска приложения, используя шаблонизатор Go
      • NOTES.txt – help-текст, который будет отображаться пользователям
      • deployment.yaml – пример манифеста с ресурсом Kubernetes Deployment
      • service.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

Устанавливаем minikube:

[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]

Содержимое его деплоймента:

[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]

В целом на этом всё.