При чтении конфигурации werf.yaml
, werf использует встроенный движок шаблонов Go (text/template), а также расширяет набор функций с помощью Sprig и функций werf.
При организации конфигурации она может быть разбита на отдельные файлы в директории шаблонов.
Встроенные возможности шаблонизатора Go
Для эффективной работы мы рекомендуем изучить все возможности шаблонизатора или хотя бы ознакомиться со следующими разделами:
Функции Sprig
Библиотека Sprig предоставляет более 70 функций:
- Строковые функции.
- Математические функции.
- Функции кодирования.
- Работа с данными в формате ключ/значение (dict).
- Работа с файловыми путями.
- Остальное.
werf не поддерживает функцию expandenv
и имеет свою собственную реализацию для функции env.
Функции werf
Различные окружения
.Env
Переменная .Env
позволяет организовывать конфигурацию для нескольких сред (testing, staging, production и т.п.) и переключаться между ними с помощью опции --env=<environment_name>
.
В helm шаблонах таким же образом может использоваться переменная
.Values.werf.env
.
Информация о текущем коммите
.Commit.Hash
{{ .Commit.Hash }}
возвращает SHA текущего коммита. Если есть возможность, лучше избегать использование .Commit.Hash
, т. к. это может приводить к ненужным пересборкам слоев.
.Commit.Date
{{ .Commit.Date.Human }}
возвращает дату текущего коммита в человекопонятной форме.
{{ .Commit.Date.Unix }}
возвращает дату текущего коммита в формате Unix epoch.
Пример: пересобирать образ целиком каждый месяц
image: app
from: ubuntu
git:
- add: /
to: /app
stageDependencies:
install:
- "*"
fromCacheVersion: {{ div .Commit.Date.Unix (mul 60 60 24 30) }}
shell:
beforeInstall:
- apt-get update
- apt-get install -y nodejs npm
install:
- npm ci
Шаблонизация
include
Функция include
позволяет переиспользовать общие части конфигурации, а также разбивать конфигурацию на несколько файлов.
Синтаксис:
{{ include "<TEMPLATE_NAME>" <VALUES> }}
Пример: использование общих кусков конфигурации
project: my-project
configVersion: 1
---
image: app1
from: alpine
ansible:
beforeInstall:
{{- include "(component) ruby" . }}
---
image: app2
from: alpine
ansible:
beforeInstall:
{{- include "(component) ruby" . }}
{{- define "(component) ruby" }}
- command: gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
- get_url:
url: https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer
dest: /tmp/rvm-installer
- name: "Install rvm"
command: bash -e /tmp/rvm-installer
- name: "Install ruby 2.3.4"
raw: bash -lec {{`{{ item | quote }}`}}
with_items:
- rvm install 2.3.4
- rvm use --default 2.3.4
- gem install bundler --no-ri --no-rdoc
- rvm cleanup all
{{- end }}
tpl
Функция tpl
позволяет обрабатывать строки как Go-шаблоны.
Синтаксис:
{{ tpl "<STRING>" <VALUES> }}
<STRING>
— контент файла проекта, значение переменной окружения либо произвольная строка.<VALUES>
— значения шаблона. При использовании текущего контекста,.
, в шаблоне можно использовать все шаблоны и значения (в том числе, описанные в файлах директории шаблонов).
Пример: использование файлов проекта в качестве шаблонов werf.yaml
{{ $_ := set . "BaseImage" "node:14.3" }}
project: app
configVersion: 1
---
{{ range $path, $content := .Files.Glob "**/werf-partial.yaml" }}
{{ tpl $content $ }}
{{ end }}
{{- define "common install commands" }}
- npm install
- npm run build
{{- end }}
image: backend
from: {{ .BaseImage }}
git:
- add: /backend
to: /app/backend
shell:
install:
- cd /app/backend
{{- include "common install commands" . | indent 2 }}
image: frontend
from: {{ .BaseImage }}
git:
- add: /frontend
to: /app/frontend
shell:
install:
- cd /app/frontend
{{- include "common install commands" . | indent 2 }}
Переменные окружения
env
Функция env
читает переменную окружения.
Синтаксис:
{{ env "<ENV_NAME>" }}
{{ env "<ENV_NAME>" "default_value" }}
По умолчанию, использование функции
env
запрещено гитерминизмом (подробнее об этом в статье)
Файлы проекта
.Files.Get
Функция .Files.Get
получает содержимое определенного файла проекта.
Синтаксис:
{{ .Files.Get "<FILE_PATH>" }}
По умолчанию, использование файлов, которые имеют незакоммиченные изменения, запрещено гитерминизмом (подробнее об этом в статье)
Пример: использование определённого файла в stapel-образе без использования директивы git (shell)
project: my-project
configVersion: 1
---
image: app
from: alpine
shell:
setup:
- |
head -c -1 <<'EOF' > /etc/nginx/nginx.conf
{{ .Files.Get ".werf/nginx.conf" | indent 4 }}
EOF
Пример: использование определённого файла в stapel-образе без использования директивы git (ansible)
project: my-project
configVersion: 1
---
image: app
from: alpine
ansible:
setup:
- name: "Setup /etc/nginx/nginx.conf"
copy:
content: |
{{ .Files.Get ".werf/nginx.conf" | indent 8 }}
dest: /etc/nginx/nginx.conf
.Files.Glob
Функция .Files.Glob
позволяет работать с файлами проекта и их содержимым по глобу.
Функция поддерживает shell pattern matching и **
. Результаты вызова функции можно объединить, используя sprig-функцию merge (к примеру, {{ $filesDict := merge (.Files.Glob "glob1") (.Files.Glob "glob2") }}
)
Синтаксис:
{{ .Files.Glob "<GLOB>" }}
По умолчанию, использование файлов, которые имеют незакоммиченные изменения, запрещено гитерминизмом (подробнее об этом в статье)
Пример: использование файлов по глобу в stapel-образе без использования директивы git (shell)
project: my-project
configVersion: 1
---
image: app
from: alpine
shell:
install: mkdir /app
setup:
{{ range $path, $content := .Files.Glob "modules/*/images/*/{Dockerfile,werf.inc.yaml}" }}
- |
head -c -1 <<EOF > /app/{{ base $path }}
{{ $content | indent 4 }}
EOF
{{ end }}
Пример: использование файлов по глобу в stapel-образе без использования директивы git (ansible)
project: my-project
configVersion: 1
---
image: app
from: alpine
ansible:
install:
- raw: mkdir /app
setup:
{{ range $path, $content := .Files.Glob "modules/*/images/*/{Dockerfile,werf.inc.yaml}" }}
- name: "Setup /app/{{ base $path }}"
copy:
content: |
{{ $content | indent 8 }}
dest: /app/{{ base $path }}
{{ end }}
Другие
required
Функция required
проверяет наличие значения у определённой переменной. Если значение пусто, то рендеринг шаблона завершится ошибкой с заданным пользователем сообщением.
Синтаксис:
value: {{ required "<ERROR_MSG>" <VALUE> }}
fromYaml
Функция fromYaml
декодирует YAML-документ в структуру.
Синтаксис:
value: {{ fromYaml "<STRING>" }}
Пример: чтение YAML-файла и использование полученного значения
{{- $values := .Files.Get "werf_values.yaml" | fromYaml -}} # или fromYaml (.Files.Get "werf_values.yaml")
from: {{- $values.image.from }}
Директория шаблонов
Файлы шаблонов могут храниться в зарезервированной директории (по умолчанию .werf
) с расширением .tmpl
(поддерживается произвольная вложенность .werf/**/*.tmpl
).
Все файлы шаблонов и основная конфигурация определяют общий контекст:
- Файл шаблонов является полноценным шаблоном и может использоваться функцией include по относительному пути (
{{ include "directory/partial.tmpl" . }}
). - Шаблон определённый с помощью
define
в одном файле шаблонов доступен в любом другом, включая основную конфигурацию.
Пример: использование файлов шаблонов
project: my-project
configVersion: 1
---
image: app
from: java:8-jdk-alpine
shell:
beforeInstall:
- mkdir /app
- adduser -Dh /home/gordon gordon
import:
- artifact: appserver
add: '/usr/src/atsea/target/AtSea-0.0.1-SNAPSHOT.jar'
to: '/app/AtSea-0.0.1-SNAPSHOT.jar'
after: install
- artifact: storefront
add: /usr/src/atsea/app/react-app/build
to: /static
after: install
docker:
ENTRYPOINT: ["java", "-jar", "/app/AtSea-0.0.1-SNAPSHOT.jar"]
CMD: ["--spring.profiles.active=postgres"]
---
{{ include "artifact/appserver.tmpl" . }}
---
{{ include "artifact/storefront.tmpl" . }}
artifact: appserver
from: maven:latest
git:
- add: '/app'
to: '/usr/src/atsea'
shell:
install:
- cd /usr/src/atsea
- mvn -B -f pom.xml -s /usr/share/maven/ref/settings-docker.xml dependency:resolve
- mvn -B -s /usr/share/maven/ref/settings-docker.xml package -DskipTests
artifact: storefront
from: node:latest
git:
- add: /app/react-app
to: /usr/src/atsea/app/react-app
shell:
install:
- cd /usr/src/atsea/app/react-app
- npm install
- npm run build
Пример: использование шаблонов, описанных в файле шаблонов
{{ $_ := set . "RubyVersion" "2.3.4" }}
{{ $_ := set . "BaseImage" "alpine" }}
project: my-project
configVersion: 1
---
image: rails
from: {{ .BaseImage }}
ansible:
beforeInstall:
{{- include "(component) mysql client" . }}
{{- include "(component) ruby" . }}
install:
{{- include "(component) Gemfile dependencies" . }}
{{- define "(component) Gemfile dependencies" }}
- file:
path: /root/.ssh
state: directory
owner: root
group: root
recurse: yes
- name: "Setup ssh known_hosts used in Gemfile"
shell: |
set -e
ssh-keyscan github.com >> /root/.ssh/known_hosts
ssh-keyscan mygitlab.myorg.com >> /root/.ssh/known_hosts
args:
executable: /bin/bash
- name: "Install Gemfile dependencies with bundler"
shell: |
set -e
source /etc/profile.d/rvm.sh
cd /app
bundle install --without development test --path vendor/bundle
args:
executable: /bin/bash
{{- end }}
{{- define "(component) mysql client" }}
- name: "Install mysql client"
apt:
name: "{{`{{ item }}`}}"
update_cache: yes
with_items:
- libmysqlclient-dev
- mysql-client
- g++
{{- end }}
{{- define "(component) ruby" }}
- command: gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
- get_url:
url: https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer
dest: /tmp/rvm-installer
- name: "Install rvm"
command: bash -e /tmp/rvm-installer
- name: "Install ruby {{ .RubyVersion }}"
raw: bash -lec {{`{{ item | quote }}`}}
with_items:
- rvm install {{ .RubyVersion }}
- rvm use --default {{ .RubyVersion }}
- gem install bundler --no-ri --no-rdoc
- rvm cleanup all
{{- end }}