Kubernetes 1.7 – Создание собственного Helm чарта (chart)
Итак, вы установили собственный Kubernetes кластер, а также установили Helm. Но как теперь запускать при помощи этой связки свои приложения?
Это руководство проведет вас через процесс создания вашего первого чарта, объяснит, что входит в архивы и инструменты, которые вы будете использовать для их разработки. В конце этого вы будете понимать преимущества использования Helm для доставки ваших собственных приложений в ваш кластер.
Для типичного облачного приложения с трехуровневой архитектурой приведенная ниже диаграмма иллюстрирует, как его можно описать в терминах объектов Kubernetes. В этом примере каждый уровень состоит из объекта развертывания (Deployment и (Service), а также может дополнительно определять объекты ConfigMap или Secret. Каждый из этих объектов обычно определяется в отдельном конфигурационном YAML файле, который передается для развертывания или обновления в Kubernetes при помощи kubectl.
Helm чарт содержит в себе каждое YAML определение каждого объекта вашего приложения, обеспечивает единый механизм конфигурации во время развертывания и позволяет вам определять метаданные и\или документацию, которые могут быть полезны при совместной работе над архивами. Helm может быть полезен в различных сценариях:
- Поиск и использование популярного программного обеспечения, упакованного как Helm чарт
- Распространение своего приложения через репозиторий Helm
- Создание воспроизводимых сборок ваших приложений для Kubernetes
- Интеллектуальное управление объектами в Kubernetes
- Управление выпуском архивов Helm
Давайте рассмотрим второй и третий сценарии, создав небольшой Helm чарт.
Герерация Helm чарта
Лучший способ начать работу с новым чартом – это использовать команду helm create, чтобы получить пример-заглушку, на базе которого можно будет построить свое приложение. Используйте эту команду для создания нового чарта с именем my-awsome-chart в новой директории:
$ helm create my-awsome-chart
Helm создаст новую директорию с именем названием my-awsome-chart со структурой, показанной ниже. Давайте рассмотрим наш новый чарт, чтобы разобраться в том, как он работает.
$ tree my-awsome-chart
my-awsome-chart
├── charts
├── Chart.yaml
├── templates
│ ├── deployment.yaml
│ ├── _helpers.tpl
│ ├── ingress.yaml
│ ├── NOTES.txt
│ └── service.yaml
└── values.yaml
Шаблоны (templates)
Самой важной частью созданного чарта является директория templates. В ней Helm ищет YAML описания для ваших сервисов (Services), развертываний (Deployment) и других объектов Kubernetes. Если у вас уже есть определения для ваших приложений, все, что вам нужно сделать, это заменить созданные файлы YAML на ваши собственные. В результате вы получите рабочий чарт, который может быть развернут с помощью команды helm install.
Стоит отметить, что Helm обрабатывает каждый файл в директории templates с помощью механизма рендеринга шаблонов Go. Helm расширяет язык шаблонов, добавляя в него ряд полезных функций для написания чартов. Откройте файл service.yaml, чтобы посмотреть, как это выглядит.
$ cd my-awsome-chart/
$ cat templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "name" . }}
chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.externalPort }}
targetPort: {{ .Values.service.internalPort }}
protocol: TCP
name: {{ .Values.service.name }}
selector:
app: {{ template "name" . }}
release: {{ .Release.Name }}
Это базовое определение Сервиса (Service) при помощи шаблона. При деплое этого чарта Helm на основании этого файла сгенерирует описание сервиса, которое будет больше похоже на правильно определенный Сервис. Давайте выполним запуск команды helm install (ключ --dry-run) с включенным режимом отладки (ключ --debug):
$ helm install --dry-run --debug .
...
# Source: my-awsome-chart/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: doltish-mink-my-awsome-chart
labels:
app: my-awsome-chart
chart: my-awsome-chart-0.1.0
release: doltish-mink
heritage: Tiller
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app: my-awsome-chart
release: doltish-mink
Значения (values)
Шаблон service.yaml использует специфичные для Helm объекты: .Chart и .Values. Первый предоставляет собой метаданные о чарте для ваших определений, т.к. имя или версия чарта. Последний объект .Values является ключевым элементом любого чарта Helm и используется для отображения конфигурации, которая должна быть установлена в процессе развертывания чарта. Значения по умолчанию для этого объекта определены в файле values.yaml. Попробуйте изменить значение по умолчанию, например, для service.internalPort и выполните еще один запуск команды Helm с ключами --dry-run и --debug. Вы увидите, что targetPort в Сервисе и containerPort в информации о развертывании изменяется. Значение service.internalPort используется для обеспечения правильной работы объектов Serviceand Deployment. Использование шаблонов таким образом может значительно уменьшить ваши изначальные шаблоны и упростить определения ваших Kubernetes объектов.
Более того, если вы захотите изменить конфигурацию по умолчанию в процессе запуска без редактирования файла определений, вы можете переопределить эти переменные непосредственно в командной строке:
$ helm install --dry-run --debug . --set service.internalPort=8080
Метаданные (metadata)
Как уже упоминалось ранее, Helm чарт состоит из метаданных, которые используются для описания того, что из себя представляет ваше приложение, определения ограничений на минимальную требуемую версию Kubernetes и\или версию Helm, а также управления версией вашего чарта. Все эти метаданные находятся в файле Chart.yaml. Документация Helm подробно описывает различные опции внутри этого файла.
Деплой вашего Helm чарта
Чарт, сгенерированный на предыдущем шаге, предназначен для запуска сервера nginx, который предоставляется при помощи Cервиса (Service) Kubernetes. По умолчанию чарт создаст сервис типа ClusterIP, поэтому nginx будет доступен только внутри кластера. Чтобы получить доступ к нему извне, нам необходимо будет использовать тип публикации NodePort. Мы также можем установить имя релиза Helm, чтобы было легче к нему обращаться. Давайте развернем наш nginx чарт, используя команду helm install:
$ helm install --name example . --set service.type=NodePort
NAME: example
LAST DEPLOYED: Mon Aug 14 10:28:48 2017
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/Service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
example-my-awsome-chart 10.102.172.137 80:32664/TCP 0s
==> v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
example-my-awsome-chart 1 1 1 0 0s
NOTES:
1. Get the application URL by running these commands:
export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services example-my-awsome-chart)
export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
Результат установки Helm чарта показывает полезную сводку состояния релиза, какие объекты были созданы, а также файл NOTES.txt, чтобы подсказать, что делать дальше. Запустите предлагаемые выводом команды, чтобы получить URL-адрес для доступа к службе nginx и проверить установку в своем браузере.
Если все пошло хорошо, вы увидите страницу приветствия nginx, как показано выше. Поздравляю! Вы только что развернули свой первый Helm сервис, упакованный в виде Helm чарта!
Изменение Helm чарта для деплоя произвольного сервиса
Сгенерированный чарт создает объект Deployment, предназначенный для запуска образа, предоставленного значениями по умолчанию. Это означает, что все, что нам нужно сделать для запуска другой службы – это изменить образ по-умолчанию в values.yaml.
Далее мы обновим Helm чарт и запустим приложение списка дел, доступное на Docker Hub. В values.yaml обновите образ так, чтобы ссылаться на образ списка дел:
image:
repository: prydonius/todo
tag: 1.0.0
pullPolicy: IfNotPresent
Когда вы разрабатываете собственный Helm чарт, рекомендуется предварительно запускать его через линтер (linter), чтобы следить за тем, что он соответствует лучшим практиками. Запустите команду helm lint, чтобы увидеть, как работает linter:
$ helm lint .
==> Linting .
[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, no failures
Линтер не зафиксировал каких-либо серьезных проблемы с нашим чартом, поэтому мы готовы двигаться дальше. Однако, в качестве примера, вот что может сделать линтер, если вы сделали что-то неправильно (Не повторяйте этот шаг):
$ echo "malformed" > mychart/values.yaml
helm lint ./mychart
==> Linting mychart
[INFO] Chart.yaml: icon is recommended
[ERROR] values.yaml: unable to parse YAML
error converting YAML to JSON: yaml: line 34: could not find expected ':'
Error: 1 chart(s) linted, 1 chart(s) failed
На этот раз линтер сообщает нам, что он не смог правильно проанализировать файл values.yaml, а также подсказывает номер строки, чтобы легко найти и исправить допущенную ошибку.
Когда чарт снова станет валидным, мы можем запустить команду helm install, чтобы развернуть приложение списка дел:
$ helm install --name example2 . --set service.type=NodePort
NAME: example2
LAST DEPLOYED: Mon Aug 14 11:36:58 2017
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/Service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
example2-my-awsome-chart 10.97.10.113 80:31336/TCP 1s
==> v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
example2-my-awsome-chart 1 1 1 0 1s
NOTES:
1. Get the application URL by running these commands:
export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services example2-my-awsome-chart)
export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
Как и в прошлый раз вы можете проверить деплой вашего приложения, выполнив подсказываемые вам команды, и открыв полученную ссылку в браузере:
Если вы уже упаковывали в контейнеры ваши приложения, вы можете легко запустить их с помощью чарта, обновив значения по умолчанию или шаблон развертывания.
Упаковка чарта и подготовка к распространению
До сих пор в этой статье мы использовали команду helm install для деплоя локального распакованного чарта. Однако, если вы хотите поделиться своими чртами с вашей командой или сообществом, имейте в виду, что все остальные устанавливают чарты tar архива. Мы можем использовать команду helm package для создания такого архива:
$ cd ..
$ helm package ./my-awsome-chart
Helm создаст архив с именем my-awsome-chart-0.1.0.tgz в нашей рабочей директории, используя имя и версию из метаданных, определенных в файле Chart.yaml. Пользователь может установить ваше приложение из этого архива, передав имя архива в качестве параметра для установки:
$ helm install --name example3 my-awsome-chart-0.1.0.tgz --set service.type=NodePort
Репозитории
Для облегчения обмена архивами Helm имеет встроенную поддержку их установки с HTTP-сервера. Helm читает размещенный на сервере индекс хранилища, который описывает, какие архивы чартов доступны, и где они расположены. Так работает стабильный репозиторий по умолчанию.
Мы можем использовать команду helm serve для запуска локального репозитория для распространения нашего чарта.
$ helm serve
Regenerating index. This may take a moment.
Now serving you on 127.0.0.1:8879
Теперь в другой вкладке консоли можно посмотреть на содержимое нашего локального репозитория и попробовать установить только что созданный нами сервис:
$ helm search local
NAME VERSION DESCRIPTION
local/my-awsome-chart 0.1.0 A Helm chart for Kubernetes
$ helm install --name example4 local/my-awsome-chart --set service.type=NodePort
Если вам интересно, как установить общедоступный Helm репозиторий, воспользуйтесь официальной документацией.
Зависимости
С развитием вашего приложения или сервиса ваш чарт также будет становиться сложнее. В какой-то момент вы обнаружите, что вам нужна дополнительная зависимость, например база данных. Helm позволяет указать суб-чарты (sub-charts), которые будут созданы как часть одной и той же версии. Чтобы определить зависимость, создайте файл requirements.yaml в корневой директории вашего чарта:
$ cat > ./my-awsome-chart/requirements.yaml <<EOF
dependencies:
- name: mariadb
version: 0.6.0
repository: https://kubernetes-charts.storage.googleapis.com
EOF
Так же, как файл с зависимостями python приложения (requirements.txt), файл requirements.yaml позволяет вам управлять зависимостями чарта и их версиями. При обновлении зависимостей создается файл блокировки, так чтобы последующая выборка зависитмостей использовала уже известную версию. Выполните следующую команду, чтобы скачать зависимость MariaDB, которую мы определили:
$ helm dep update ./my-awsome-chart
Hang tight while we grab the latest from your chart repositories...
...Unable to get an update from the "local" chart repository (http://127.0.0.1:8879/charts):
Get http://127.0.0.1:8879/charts/index.yaml: dial tcp 127.0.0.1:8879: getsockopt: connection refused
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈Happy Helming!⎈
Deleting outdated charts
Saving 1 charts
Downloading mariadb from repo https://kubernetes-charts.storage.googleapis.com
$ ls ./my-awsome-chart/charts/
mariadb-0.6.0.tgz
Helm нашел подходящую версию в стабильном репозитории и скачал ее в директорию chartsнашего чарта. Теперь давайте установим наш чарт и увидим, что объекты MariaDB также создаются:
$ helm install --name example5 ./my-awsome-chart --set service.type=NodePort
NAME: example5
LAST DEPLOYED: Mon Aug 14 12:09:05 2017
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
example5-my-awsome-chart 1 1 1 0 1s
example5-mariadb 1 1 1 0 1s
==> v1/Secret
NAME TYPE DATA AGE
example5-mariadb Opaque 2 2s
==> v1/ConfigMap
NAME DATA AGE
example5-mariadb 1 2s
==> v1/PersistentVolumeClaim
NAME STATUS VOLUME CAPACITY ACCESSMODES STORAGECLASS AGE
example5-mariadb Pending 2s
==> v1/Service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
example5-mariadb 10.100.87.94 3306/TCP 2s
example5-my-awsome-chart 10.106.213.6 80:32379/TCP 1s
NOTES:
1. Get the application URL by running these commands:
export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services example5-my-awsome-chart)
export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
Одним из преимуществ Helm является его огромный набор чартов, которые вы можете установить с помощью одной команды. В роли автора такого чарта вы можете помочь создать стабильный репозиторий, улучшив существующие чарты или предоставив новые для общего пользования. Посмотрите на текущий репозиторий приложений на https://kubeapps.com.