Прямо сейчас мы пишем новые главы самоучителя!
Эта страница находится в разработке.

Показать, что уже готово

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

  • Dockerfile (удалён)
  • werf.yaml

Воспользуемся ключевыми механизмами werf, позволяющими ускорить сборку: не будем тратить время на пересборку инфраструктуры и зависимостей, если они не изменились.

Собираем только то, что нужно

В процессе разработки изменения вносятся в файлы с неравномерной регулярностью. Код окружения, список зависимостей и код самого приложения мы меняем с разной частотой, поэтому не хочется тратить время на перерасчёт той “стадии”, что не изменилась.

Для этого в werf есть механизм стадий сборки.

Что за стадии?

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

Стадии — это этапы сборочного процесса, кирпичи, из которых в итоге собирается конечный образ. Стадия собирается из группы сборочных инструкций, указанных в конфигурации. Причем группировка этих инструкций не случайна, имеет определенную логику и учитывает условия и правила сборки. С каждой стадией связан конкретный Docker-образ.

Подробнее о том, какие стадии для чего предполагаются, можно посмотреть здесь. Если вкратце, то werf предлагает использовать для стадий следующую стратегию:

  • использовать стадию beforeInstall для инсталляции системных пакетов;
  • install — для инсталляции системных зависимостей и зависимостей приложения;
  • beforeSetup — для настройки системных параметров и установки приложения;
  • setup — для настройки приложения.

Другие подробности о стадиях описаны в документации.

Одно из основных преимуществ использования стадий в том, что мы можем перезапускать сборку не с нуля, а только с той стадии, которая зависит от изменений в определенных файлах.

Для работы механизма стадий нам нужно будет перенести код сборки из Dockerfile в werf.yaml, скорректировав синтаксис.

Сейчас в werf.yaml сборка описана так:

---
image: basicapp
dockerfile: Dockerfile
--- image: basicapp dockerfile: Dockerfile

Удалите эти строки — мы перепишем их, прописав там:

  • базовый образ (в Dockerfile это было FROM node:14-stretch)
  • рабочую папку (в Dockerfile это было WORKDIR /app)
  • сценарий добавления в финальный образ исходного кода (в Dockerfile это было COPY . .)
  • установку зависимостей

В последнем, к слову важно, что работа с apt и npm должна быть реализована в правильных стадиях. Причём важно сказать werf-и, что при изменении файла package.json нужно перезапускать стадию install (в которой будет запускаться npm ci).

---
image: basicapp
from: node:14-stretch
git:
- add: /
  to: /app
  stageDependencies:
    install:
    - package.json
shell:
  beforeInstall:
  - apt update
  - apt install -y tzdata locales
  install:
  - cd /app && npm ci
docker:
  WORKDIR: /app
--- image: basicapp from: node:14-stretch git: - add: / to: /app stageDependencies: install: - package.json shell: beforeInstall: - apt update - apt install -y tzdata locales install: - cd /app && npm ci docker: WORKDIR: /app
Что тут написано?

Здесь используется 4 корневых директивы: from — на основании какого образа будет осуществляться сборка; git — описывает импорт данных из репозитория; shell — описывает сборку стадий с помощью shell-команд; docker — инструкции для Docker.

Разумеется, наш пример очень простой. Реальные сценарии сборки гораздо сложнее:

  • иногда нужно вытащить код приложения из другого репозитория
директива `git` это позволяет

Директива git также позволяет добавлять код из удалённых Git-репозиториев, используя параметр url.

Пример:

git:
- add: /src
  to: /app
- url: https://github.com/ariya/phantomjs
  tag: 2.2.1
  add: /
  to: /src/phantomjs

Детали и особенности можно почитать в документации.

При использовании удалённых git-репозиториев важно указывать конкретный тег или коммит, чтобы получить детерминированную сборку.

  • убирать или добавлять код приложения по более сложным сценариям
можно добавлять и исключать файлы по маске

В реальной практике нужно добавлять файлы, фильтруя по названию или пути.

К примеру, в данном варианте добавляются все файлы .php и .js из каталога /src, исключая файлы с суффиксом -dev. и -test. в имени файла.

git:
- add: /src
  to: /app
  includePaths:
  - '**/*.php'
  - '**/*.js'
  excludePaths:
  - '**/*-dev.*'
  - '**/*-test.*'
  • корректировать владельцев файлов
можно указать владельцев в директиве `git`

В Linux-системах важно не забывать про установку владельца файлов.

Например, вот так изменяется владелец файла index.php на www-data:

git:
- add: /src/index.php
  to: /app/index.php
  owner: www-data
  • использовать шаблонизацию
werf использует go templates

В werf поддерживаются Go templates, поэтому легко определять переменные и записывать в них константы и часто используемые образы.

Например, сделаем 2 образа, используя один базовый образ golang:1.11-alpine:

{{ $base_image := "golang:1.11-alpine" }}

project: my-project
configVersion: 1
---

image: gogomonia
from: {{ $base_image }}
---
image: saml-authenticator
from: {{ $base_image }}

Подробнее почитать про Go-шаблоны в werf можно в документации: werf go templates.

Запускаем сборку

Ваш werf.yaml должен был принять вид:

project: werf-guided-golang
configVersion: 1
---
image: basicapp
from: node:14-stretch
git:
- add: /
  to: /app
  stageDependencies:
    install:
    - package.json
shell:
  beforeInstall:
  - apt update
  - apt install -y tzdata locales
  install:
  - cd /app && npm ci
docker:
  WORKDIR: /app
project: werf-guided-golang configVersion: 1 --- image: basicapp from: node:14-stretch git: - add: / to: /app stageDependencies: install: - package.json shell: beforeInstall: - apt update - apt install -y tzdata locales install: - cd /app && npm ci docker: WORKDIR: /app

Сделайте коммит изменений в репозитории с кодом, затем запустите converge и обратите внимание на время сборки

werf converge --repo registry.example.com/werf-guided-golang

Попробуйте менять список зависимостей (просто добавьте какой-нибудь пакет в package.json), файл с кодом (app.js) или инфраструктуру (добавьте новый аттрибут с произвольным текстом в секцию metadata: в файле deployment.yaml) и посмотрите, как быстро осуществляется сборка и где используется ранее собранный кусок образа.