Обзор
werf
поддерживает импорт конфигурационных файлов из внешних источников с помощью механизма includes.
Это удобно, когда у вас много однотипных приложений и вы хотите сопровождать и использовать конфигурацию централизованно.
Что можно импортировать
Поддерживается импорт следующих типов файлов:
- Основной файл конфигурации (
werf.yaml
), шаблоны (.werf/**/*.tmpl
), а также произвольные файлы, которые используются при шаблонизации. - Helm-чарты и отдельные файлы.
Dockerfile
и.dockerignore
.
Что нельзя импортировать
Механизм не позволяет импортировать файлы сборочного контекста, а также следующие конфигурационные файлы:
werf-includes.yaml
werf-includes.lock
werf-giterminism.yaml
Как работает механизм includes
- Вы описываете внешние источники и импортируемые файлы в
werf-includes.yaml
. - Фиксируете версии внешних источников с помощью команды
werf includes update
, которая создаётwerf-includes.lock
. Lock-файл необходим для воспроизводимости сборок и развертываний. - Все команды
werf
(например,werf build
,werf converge
) будут учитывать этот lock-файл и работать с конфигурацией в соответствии с правилами наложения.
Правила наложения
Если один и тот же файл существует в нескольких местах, применяются следующие правила:
- Локальные файлы проекта всегда имеют приоритет над импортируемыми.
- Если файл присутствует в нескольких
includes
, будет использоваться версия из источника, который расположен ниже по спискуincludes
вwerf-includes.yaml
(от общего к частному).
Пример применения правил наложения
Допустим в локальном репозитории есть файл c
, а также следующая конфигурация:
# werf-includes.yaml
includes:
- git: repo1 # импортирует a, b, c
branch: main
add: /
to: /
- git: repo2 # импортирует b, c
branch: main
add: /
to: /
Тогда результат наложения будет выглядеть так:
.
├── a # из repo1
├── b # из repo2
├── c # из локального репо
Подключение конфигурации из внешних источников
Ниже приведён пример конфигурации внешних источников (полное описание директив вы можете найти на соответствующей странице werf-includes.yaml):
# werf-includes.yaml
includes:
- git: https://github.com/werf/werf
branch: main
add: /docs/examples/includes/common
to: /
includePaths:
- .werf
После конфигурации необходимо зафиксировать версии внешних зависимостей. Для этого можно использовать команду werf includes update
, после вызова которой, в корне проекта будет создан файл werf-includes.lock
:
includes:
- git: https://github.com/werf/werf
branch: main
commit: 21640b8e619ba4dd480fedf144f7424aa217a2eb
ВАЖНО. Согласно политикам гитерминизма, файлы
werf-includes.yaml
иwerf-includes.lock
должны быть закомичены. При конфигурации и отладке для удобства предлагается использовать флаг--dev
.
Пример использования внешних источников при конфигурации однотипных приложений
Предположим вы решили централизованно обслуживать конфигурацию приложений в вашей организации, сохраняя общую конфигурацию в одном источнике и конфигурацию под каждый тип проекта в других (в одном или нескольких Git-репозиториях — на ваше усмотрение).
Конфигурация типового проекта в таком случае могла бы выглядеть так:
- Проект:
backend:
limits:
cpu: 100m
memory: 256Mi
frontend:
limits:
cpu: 50m
memory: 48Mi
// dummy
const express = require('express');
const app = express();
app.get('/api/hello', (req, res) => {
res.json({ message: 'Hello from backend!' });
});
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Backend running on port ${port}`);
});
{
"name": "backend",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^4.18.2"
}
}
<!DOCTYPE html>
<html>
<head><title>Frontend</title></head>
<body>
<h1>Hello from Frontend</h1>
<button onclick="callApi()">Call Backend</button>
<p id="output"></p>
<script>
async function callApi() {
const res = await fetch('$BACKEND_URL');
const data = await res.json();
document.getElementById('output').innerText = data.message;
}
</script>
</body>
</html>
includes:
- git: https://github.com/werf/werf
branch: main
commit: 792c7631d2abbae8dc0acb252905f740d98c7585
includes:
- git: https://github.com/werf/werf
branch: main
add: /docs/examples/includes/werf-common
to: /
- git: https://github.com/werf/werf
branch: main
add: /docs/examples/includes/common_js
to: /
project: myapp
configVersion: 1
build:
platform:
- linux/amd64
imageSpec: {{ include "imagespec" (dict "appName" "myapp") | nindent 4 }}
cleanup: {{ include "cleanup" (dict "mainBranchName" "main") | nindent 2 }}
---
{{ include "image-backend" (dict) }}
---
{{ include "image-frontend" (dict "backendUrl" "http://backend:3000") }}
- Источник с общей конфигурацией:
{{- define "cleanup" }}
{{- $mainBranchName := default "main" .mainBranchName}}
keepImagesBuiltWithinLastNHours: 1
keepPolicies:
- references:
branch: /.*/
limit:
last: 20
in: 168h
operator: And
imagesPerReference:
last: 1
in: 168h
operator: And
- references:
branch: "{{ $mainBranchName }}"
imagesPerReference:
last: 1
{{- end }}
{{- define "imagespec" }}
{{- $appName := default "defaultapp" .appName}}
clearHistory: true
config:
labels:
example.io/app: "{{ $appName }}"
{{- end }}
- Источник со специфичной для вашего типа проекта конфигурацией:
**/dummy.ini
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: backend
image: {{ $.Values.werf.image.backend }}
ports:
- containerPort: 3000
resources:
requests:
cpu: {{ $.Values.backend.limits.cpu }}
memory: {{ $.Values.backend.limits.memory}}
limits:
cpu: {{ $.Values.backend.limits.cpu }}
memory: {{ $.Values.backend.limits.memory }}
- name: frontend
image: {{ $.Values.werf.image.frontend }}
ports:
- containerPort: 80
resources:
requests:
cpu: {{ $.Values.frontend.limits.cpu }}
memory: {{ $.Values.frontend.limits.memory}}
limits:
cpu: {{ $.Values.frontend.limits.cpu }}
memory: {{ $.Values.frontend.limits.memory }}
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
selector:
app: myapp
ports:
- name: http
port: 80
backend:
limits:
cpu: 100m
memory: 256Mi
frontend:
limits:
cpu: 50m
memory: 48Mi
{{- define "image-backend" }}
image: backend
dockerfile: backend.Dockerfile
{{- end }}
{{- define "image-frontend" }}
{{- $backendUrl := default "http://example.org" .backendUrl }}
image: frontend
dockerfile: frontend.Dockerfile
args:
BACKEND_URL: "{{ $backendUrl }}"
{{- end }}
FROM node:18-alpine
WORKDIR /app
COPY backend/ /app/
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
FROM nginx:alpine
ARG BACKEND_URL
ENV BACKEND_URL=${BACKEND_URL}
WORKDIR /usr/share/nginx/html
COPY frontend/index.html .
RUN envsubst < index.html > index.tmp.html && \
mv index.tmp.html index.html
Обновление includes
Детерминированное
Существует два способа обновления версий includes:
- Командой
werf includes update
. Данная команда обновит всеincludes
наHEAD
соответствующего референса (branch
илиtag
). - Редактирование файла
werf-includes.lock
вручную или с помощью таких как инструментов какdependabot
,renovate
и прочих.
Автообновление (не рекомендовано)
Если необходимо использовать последние HEAD
-версии без lock-файла, можно использовать опцию --allow-includes-update
, а так же явно разрешить ее использование в werf-giterminism.yaml
:
includes:
allowIncludesUpdate: true
ВАЖНО. Мы не рекомендуем использование данного подхода, так как он может нарушать воспроизводимость сборок и развертываний.
Отладка
Получение списка файлов проекта с учётом источников
werf includes ls-files .helm
Пример вывода:
PATH SOURCE
.helm/Chart.yaml https://github.com/werf/werf
.helm/charts/backend/Chart.yaml https://github.com/werf/werf
.helm/charts/backend/templates/deployment.yaml https://github.com/werf/werf
.helm/charts/backend/templates/service.yaml https://github.com/werf/werf
.helm/charts/frontend/Chart.yaml https://github.com/werf/werf
.helm/charts/frontend/templates/deployment.yaml https://github.com/werf/werf
.helm/charts/frontend/templates/service.yaml https://github.com/werf/werf
.helm/requirements.lock https://github.com/werf/werf
.helm/values.yaml local
Получение содержимого файла проекта с учётом источников
werf includes get-file .helm/charts/backend/templates/deployment.yaml
Пример вывода:
apiVersion: apps/v1
kind: Deployment
metadata:
name:
annotations:
werf.io/weight: "30"
spec:
selector:
matchLabels:
app:
template:
metadata:
labels:
app:
spec:
containers:
- name: backend
image:
ports:
- containerPort: 3000
resources:
requests:
cpu:
memory:
limits:
cpu:
memory:
Использование локальных репозиториев
Допускается использование локальных репозиториев в качестве источника для include. Порядок работы с такими репозиториями ничем не отличается от работы с удалёнными.
# werf-includes.yaml
includes:
- git: /local/repo
branch: main
add: local-dev
to: /
includePaths:
- /.helm