Файлы, упомянутые в главе

  • .helm/templates/deployment.yaml
  • .helm/templates/ingress.yaml
  • .helm/templates/service.yaml
  • .helm/values.yaml

Ранее мы уже описали инфраструктуру в виде объектов Kubernetes. Шаблонизируем эту конфигурацию с помощью Helm, его движок встроен в werf. Помимо этого, werf предоставляет возможности работы с секретными значениями, а также дополнительные Go-шаблоны для интеграции с собранными образами.

В этой главе мы научимся описывать Helm-шаблоны, используя возможности werf, а также освоим встроенные инструменты отладки. Эта глава в значительной мере теоретическая, но знания, которые здесь даны, пригодятся в реальной практике.

Что делать, если вы не работали с Helm?

Не будем вдаваться в подробности разработки YAML-манифестов с помощью Helm для Kubernetes. Если у вас есть вопросы о том, как именно описываются объекты Kubernetes, советуем посетить страницы документации Kubernetes о концепциях и документацию Helm по разработке шаблонов.

В первое время работа с Helm и конфигурацией для Kubernetes может быть очень сложной из-за нелепых мелочей вроде опечаток и пропущенных пробелов. Если вы только начали осваивать эти технологии — постарайтесь найти наставника, который поможет преодолеть эти сложности и посмотрит на ваши исходники сторонним взглядом.

В случае затруднений убедитесь, что вы:

  • понимаете, как работает indent;
  • понимаете, что такое конструкция tuple;
  • понимаете, как Helm работает с хэш-массивами;
  • очень внимательно следите за пробелами в YAML.

Подстановка переменных

В описании Deployment, Ingress и Service используется значение basicapp — лучше заменить его переменной. Воспользуемся для этого переменной с именем чарта .Chart.Name. Например, было:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: basicapp
spec:
  selector:
    matchLabels:
      app: basicapp
apiVersion: apps/v1 kind: Deployment metadata: name: basicapp spec: selector: matchLabels: app: basicapp

Стало:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Chart.Name }}
spec:
  selector:
    matchLabels:
      app: {{ .Chart.Name }}
apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Chart.Name }} spec: selector: matchLabels: app: {{ .Chart.Name }}

Конфигурирование шаблона

В реальной практике одно и то же приложение может выкатываться на различные стенды (production, test, staging и т.п.). И для разных стендов зачастую необходимо использовать разные значения.

В werf поддерживаются следующие способы:

  1. Подстановка значений из values.yaml по аналогии с Helm.
  2. Проброс значений опцией --set/--set-string по аналогии с Helm.
  3. Подстановка секретных значений из secret-values.yaml.

Использование values.yaml

Создадим файл values.yaml и будем там хранить имя файла базы данных и скорректируем объект Deployment. Острой необходимости в этом нет, но это важный инструмент, без которого невозможна разработка реальных приложений.

app:
  sqlite_file:
    _default: "app.db"
    production: "app.db"
    testing: "app.db"
app: sqlite_file: _default: "app.db" production: "app.db" testing: "app.db"

Нужные значения подставляются в helm-шаблоны:

        env:
        - name: "SQLITE_FILE"
          value: {{ pluck .Values.werf.env .Values.app.sqlite_file | first | default .Values.app.sqlite_file._default | quote }}
env: - name: "SQLITE_FILE" value: {{ pluck .Values.werf.env .Values.app.sqlite_file | first | default .Values.app.sqlite_file._default | quote }}

Конечное значение определяется на основании переменной .Values.werf.env. Позже, в главе “Работа с инфраструктурой”, мы рассмотрим, как значение этой переменной автоматически подставляется CI-системой. Вручную значение можно задать при запуске converge опцией --env:

werf converge --repo registry.mydomain.io/werf-guided-project --env production

Проброс значений через –set

Второй вариант подразумевает задание переменных через CLI. Например, в converge можно передать нужное значение

werf converge --repo registry.mydomain.io/werf-guided-project --set "global.myvariable=somevalue"

И можно будет использовать это значение в шаблонах:

        env:
        - name: "SQLITE_FILE"
          value: {{ .Values.global.myvariable | quote }}
env: - name: "SQLITE_FILE" value: {{ .Values.global.myvariable | quote }}

Этот вариант удобен для проброса, например, имени домена для каждого окружения. К этому вопросу мы вернёмся, когда будем выстраивать CI-процесс в главе “Работа с инфраструктурой”.

Подстановка секретных значений

Отдельная проблема — хранение и задание секретных переменных, например, учётных данных аутентификации для сторонних сервисов, API-ключей и т.п.

Так как werf рассматривает Git как единственный источник правды, правильно хранить секретные переменные там же. Чтобы делать это корректно, мы храним данные в шифрованном виде. Подстановка значений из этого файла происходит при рендере шаблона, который также запускается при деплое.

Чтобы воспользоваться секретными переменными:

  • сгенерируйте ключ (werf helm secret generate-secret-key);
  • определите ключ в текущей сессии консоли (например, export WERF_SECRET_KEY=634f76ead513e5959d0e03a992372b8e) или создайте файл .werf_secret_key в корне проекта (этот ключ не должен храниться в Git).

После этого можно задать секретные переменные access_key и secret_key, например, для работы с S3. Зайдите в режим редактирования секретных значений:

$ werf helm secret values edit .helm/secret-values.yaml

Откроется консольный текстовый редактор с данными в расшифрованном виде:

.helm/secret-values.yaml в расшифрованном виде копировать имя копировать текст
app:
  s3:
    access_key:
      _default: bNGXXCF1GF
    secret_key:
      _default: zpThy4kGeqMNSuF2gyw48cOKJMvZqtrTswAQ
app: s3: access_key: _default: bNGXXCF1GF secret_key: _default: zpThy4kGeqMNSuF2gyw48cOKJMvZqtrTswAQ

После сохранения значения в файле зашифруются и примут примерно такой вид:

.helm/secret-values.yaml в зашифрованном виде копировать имя копировать текст
app:
  s3:
    access_key:
      _default: 1000f82ff86a5d766b9895b276032928c7e4ff2eeb20cab05f013e5fe61d21301427
    secret_key:
      _default: 1000bee1b42b57e39a9cfaca7ea047de03043c45e39901b8974c5a1f275b98fd0ac2c72efbc62b06cad653ebc4195b680370dc9c04e88a8182a874db286d8360def6
app: s3: access_key: _default: 1000f82ff86a5d766b9895b276032928c7e4ff2eeb20cab05f013e5fe61d21301427 secret_key: _default: 1000bee1b42b57e39a9cfaca7ea047de03043c45e39901b8974c5a1f275b98fd0ac2c72efbc62b06cad653ebc4195b680370dc9c04e88a8182a874db286d8360def6