diff --git a/docs/_data/sidebars/_documentation.yml b/docs/_data/sidebars/_documentation.yml index 6e99df9608..d9a8e9dc40 100644 --- a/docs/_data/sidebars/_documentation.yml +++ b/docs/_data/sidebars/_documentation.yml @@ -173,12 +173,15 @@ entries: - title: Сборка f: - - title: Обзор (НОВИНКА) + - title: Обзор (NEW) url: /usage/build_draft/overview.html - - title: Конфигурация образов (НОВИНКА) + - title: Конфигурация образов (NEW) url: /usage/build_draft/images.html + - title: Сборочный процесс (NEW) + url: /usage/build_draft/building.html + - title: Процесс сборки url: /usage/build/build_process.html @@ -205,7 +208,7 @@ entries: - title: В Kubernetes url: /usage/build/run_in_containers/use_kubernetes.html - - title: Сборка образов с помощью Stapel (ОБНОВЛЕНИЕ) + - title: Сборка образов с помощью Stapel (NEW) f: - title: Обзор url: /usage/build_draft/stapel/overview.html diff --git a/docs/pages_ru/usage/build_draft/all_in_one.md b/docs/pages_ru/usage/build_draft/all_in_one.md index 5dd2d57a2b..6a26ce2ea3 100644 --- a/docs/pages_ru/usage/build_draft/all_in_one.md +++ b/docs/pages_ru/usage/build_draft/all_in_one.md @@ -1,230 +1,21 @@ -# Vision - -- [Vision](#vision) - - [Обзор](#обзор) - - [Конфигурация образов](#конфигурация-образов) - - [Сборочный процесс](#сборочный-процесс) - - [Параллельная сборка](#параллельная-сборка) - - [Послойное кеширование в container registry](#послойное-кеширование-в-container-registry) - - [Автотегирование / тегирование](#автотегирование--тегирование) - - [Синхронизация](#синхронизация) - - [Сборочный бэкенд](#сборочный-бэкенд) - - [Buildah](#buildah) - - [Системные требования](#системные-требования) - - [Включение Buildah](#включение-buildah) - - [Драйвер хранилища](#драйвер-хранилища) - - [Ulimits](#ulimits) - - [Работа в контейнерах](#работа-в-контейнерах) - - [Организация хранилища](#организация-хранилища) - - [Хранилище](#хранилище) - - [Именование стадий](#именование-стадий) - - [Первичный репозиторий](#первичный-репозиторий) - - [Вторичный репозиторий](#вторичный-репозиторий) - - [Кэширующий репозиторий](#кэширующий-репозиторий) - - [Финальный репозиторий](#финальный-репозиторий) - - [Примеры организации хранилища стадий](#примеры-организации-хранилища-стадий) - - [1. Стандарт](#1-стандарт) - - [2. Дополнительный кэш в локальной сети](#2-дополнительный-кэш-в-локальной-сети) - - [3. Полная оптимизация](#3-полная-оптимизация) - - [Stapel](#stapel) -## Обзор - -Чтобы доставить приложение в кубы как правило нужно собрать один или несколько образов приложения. - -От пользователя требуется предоставить сборочные инструкции в виде Dockerfile или альтернативного сборочного синтаксиса stapel. - -Предоставляется простой интерфейс для встараивания в CI/CD pipeline или для локального использования: команда `werf build [--repo REPO]`. Далее werf из коробки без специальной конфигурации берёт на себя всю работу по сборке, предоставляя следующие фичи: - -* оркестрация одновременной/параллельной сборки всех образов приложения; -* общий кеш промежуточных слоёв и образов в Container Registry, доступный с любых раннеров; -* оптимальная схема тегирования, основанная на содержимом образа, предотвращающая лишние пересборки и downtime приложения при дальнейшем выкате; -* система обеспечения воспроизводимости и неизменности образов для коммита: однажды собранные образы для коммита более не будут пересобраны (в рамках политик очистки — см. очистка); +- [Обзор](#обзор) +- [Конфигурация образов](#конфигурация-образов) +- [Сборочный процесс](#сборочный-процесс) +- [Организация хранилища](#организация-хранилища) +- [Stapel](#stapel) -После прочтения данного раздела пользователь узнает как описать инструкции сборки образов, как работает механизм сборки, какие есть варианты конфигурации сборочного механизма и варианты организации хранилища под нужды проекта. +## Обзор ## Конфигурация образов - - ## Сборочный процесс -TODO: как это работает, как конфигурируется: parallel, buildah/docker, режимы buildah, синхронизация+конфигурация - -### Параллельная сборка - -Параллельная сборка в werf регулируется двумя параметрами `-p, --parallel` и `--parallel-tasks-limit`. По умолчанию параллельная сборка включена и собирается не более 5 образов одновременно. - -После построение дерева зависимостей образов, werf разбивает сборку на этапы. Каждый этап содержит набор независимых образов, которые могут собираться параллельно. - -```shell -┌ Concurrent builds plan (no more than 5 images at the same time) -│ Set #0: -│ - ⛵ image common-base -│ - 🛸 artifact jq -│ - 🛸 artifact libjq -│ - 🛸 artifact kcov -│ -│ Set #1: -│ - ⛵ image base-for-go -│ -│ Set #2: -│ - 🛸 artifact terraform-provider-vsphere -│ - 🛸 artifact terraform-provider-gcp -│ - 🛸 artifact candictl -│ - ⛵ image candictl-tests -│ - 🛸 artifact helm -│ - 🛸 artifact controller -│ -│ Set #3: -│ - ⛵ image base -│ -│ Set #4: -│ - ⛵ image tests -│ - ⛵ image app -└ Concurrent builds plan (no more than 5 images at the same time) -``` - -### Послойное кеширование в container registry - -TODO -Оптимальное использование CR: собрано один раз, больше не пересобирается, конечные образы, слои - -### Автотегирование / тегирование - -TODO - -### Синхронизация - -TODO: как работает по умолчанию, как настроить свой сервер - -### Сборочный бэкенд - -werf поддерживает использование Docker Server или Buildah в качестве бекенда для сборки образов. Buildah поддерживает полноценную работу в контейнерах и послойную сборку Dockerfile-ов с кешированием всех промежуточных слоёв в container registry. - -Более подробную информацию о Buildah можно получить в разделе [Режим сборки с использованием Buildah.]({{ "/advanced/buildah_mode.html" | true_relative_url }}) - -#### Buildah - -> ПРИМЕЧАНИЕ: werf поддерживает сборку образов с _использованием Docker-сервера_ или _с использованием Buildah_. Поддерживается сборка как Dockerfile-образов, так и stapel-образов через Buildah. - -Для сборки без Docker-сервера werf использует встроенный Buildah в rootless-режиме. - -##### Системные требования - -TODO: перенести в установку или уже там есть — проверить (?) - -Требования к хост-системе для запуска werf в Buildah-режиме без Docker/Kubernetes можно найти в [инструкциях по установке](/installation.html). А для запуска werf в Kubernetes или в Docker-контейнерах требования следующие: -* Если ваше ядро Linux версии 5.13+ (в некоторых дистрибутивах 5.11+) **рекомендуется** режим работы через модуль ядра `overlay`: - * Убедитесь, что модуль ядра `overlay` загружен с `lsmod | grep overlay`. - * Убедитесь, что настройка ядра `CONFIG_USER_NS=y` включена в вашем ядре с помощью `grep CONFIG_USER_NS /boot/config-VERSION`. - * При использовании ядра в debian-системах команда `sysctl kernel.unprivileged_userns_clone` должна вернуть `1`. В ином случае выполните: - ```shell - echo 'kernel.unprivileged_userns_clone = 1' | sudo tee -a /etc/sysctl.conf - sudo sysctl -p - ``` - * Команда `sysctl user.max_user_namespaces` должна вернуть по меньшей мере `15000`. В ином случае выполните: - ```shell - echo 'user.max_user_namespaces = 15000' | sudo tee -a /etc/sysctl.conf - sudo sysctl -p - ``` -* Если ядро более старое или у вас не получается активировать модуль ядра `overlay`, то установите `fuse-overlayfs`, который обычно доступен в репозиториях вашего дистрибутива. В крайнем случае может быть использован драйвер хранилища `vfs`. - -##### Включение Buildah - -Buildah включается установкой переменной окружения `WERF_BUILDAH_MODE` в один из вариантов: `auto`, `native-chroot`, `native-rootless`. Большинству пользователей для включения режима Buildah достаточно установить `WERF_BUILDAH_MODE=auto`. - -* `auto` — автоматический выбор режима в зависимости от платформы и окружения; -* `native-chroot` работает только в Linux и использует `chroot`-изоляцию для сборочных контейнеров; -* `native-rootless` работает только в Linux и использует `rootless`-изоляцию для сборочных контейнеров. На этом уровне изоляции werf использует среду выполнения сборочных операций в контейнерах (runc, crun, kata или runsc). - -> ПРИМЕЧАНИЕ: На данный момент Buildah доступен только для пользователей Linux и Windows с включённой подсистемой WSL2. Для пользователей MacOS на данный момент предлагается использование виртуальной машины для запуска werf в режиме Buildah. - -##### Драйвер хранилища - -werf может использовать драйвер хранилища `overlay` или `vfs`: - -* `overlay` позволяет использовать файловую систему OverlayFS. Можно использовать либо встроенную в ядро Linux поддержку OverlayFS (если она доступна), либо реализацию fuse-overlayfs. Это рекомендуемый выбор по умолчанию. -* `vfs` обеспечивает доступ к виртуальной файловой системе вместо OverlayFS. Эта файловая система уступает по производительности и требует привилегированного контейнера, поэтому ее не рекомендуется использовать. Однако в некоторых случаях она может пригодиться. - -Как правило, достаточно использовать драйвер по умолчанию (`overlay`). Драйвер хранилища можно задать с помощью переменной окружения `WERF_BUILDAH_STORAGE_DRIVER`. - -##### Ulimits - -По умолчанию Buildah режим в werf наследует системные ulimits при запуске сборочных контейнеров. Пользователь может переопределить эти параметры с помощью переменной окружения `WERF_BUILDAH_ULIMIT`. - -Формат `WERF_BUILDAH_ULIMIT=type:softlimit[:hardlimit][,type:softlimit[:hardlimit],...]` — конфигурация лимитов, указанные через запятую: -* "core": maximum core dump size (ulimit -c) -* "cpu": maximum CPU time (ulimit -t) -* "data": maximum size of a process's data segment (ulimit -d) -* "fsize": maximum size of new files (ulimit -f) -* "locks": maximum number of file locks (ulimit -x) -* "memlock": maximum amount of locked memory (ulimit -l) -* "msgqueue": maximum amount of data in message queues (ulimit -q) -* "nice": niceness adjustment (nice -n, ulimit -e) -* "nofile": maximum number of open files (ulimit -n) -* "nproc": maximum number of processes (ulimit -u) -* "rss": maximum size of a process's (ulimit -m) -* "rtprio": maximum real-time scheduling priority (ulimit -r) -* "rttime": maximum amount of real-time execution between blocking syscalls -* "sigpending": maximum number of pending signals (ulimit -i) -* "stack": maximum stack size (ulimit -s) - -### Работа в контейнерах - -TODO - ## Организация хранилища В данной статье описано, как устроено хранилище собираемых образов в werf, какие бывают типы хранилища, какие функции выполняют эти хранилища, а также различные варианты организации хранилища в проекте. -### Хранилище - -werf собирает образы, состоящие из одной или нескольких стадий. Все стадии собираемых образов сохраняются в так называемое **хранилище стадий** по мере сборки. Хранилище хранит стадии и метаданные проекта. Эти данные могут храниться локально на хост-машине, либо в container registry. - -Большинство команд werf требуют указания места размещения _хранилища_ с помощью ключа `--repo` или переменной окружения `WERF_REPO`. - -Есть два вида хранилища стадий: **локальное** и **репозиторий** (container registry). - -* Локальное хранилище стадий может быть использовано _только для локальной разработки_. В качестве локального хранилища выступает docker server или buildah storage. Локальное хранилище стадий будет задействовано, например, если вызвать команду `werf build` без аргумента `--repo`. -* Во всех остальных случаях (т.е. кроме локальной разработки) в качестве хранилища стадий всегда выступает репозиторий в container registry. Если запустить сборку с хранилищем стадий в репозитории (например, `werf build` с параметром `--repo ghcr.io/example/myrepo`), то werf сначала проверит наличие требуемых стадий в локальном хранилище и скопирует оттуда подходящие стадии, чтобы не пересобирать эти стадии заново. - - **ЗАМЕЧАНИЕ** Каждый проект должен использовать в качестве хранилища уникальный адрес репозитория, который используется только этим проектом. - -Стадии будут [именоваться по-разному](#именование-стадий) в зависимости от типа используемого хранилища. - -При использовании container registry для хранения стадий, локальный docker-server на всех хостах, где запускают werf, используется как кеш. Этот кеш может быть очищен автоматически самим werf-ом, либо удалён с помощью других инструментов (например `docker rmi`) без каких-либо последствий. - -Предполагается, что хранилище стадий инсталляции не может быть удалено или очищено сторонними средствами без негативных последствий для работы werf *(например, см. [первичный репозиторий](#первичный-репозиторий))*. Исключение составляют некоторые типы хранилищ, которые могут быть безопасно удалены в любой момент времени *(например, см. [кэширующий репозиторий](#кэширующий-репозиторий))*. - - -#### Именование стадий - -Стадии в _локальном хранилище_ именуются согласно следующей схемы: `PROJECT_NAME:STAGE_DIGEST-TIMESTAMP_MILLISEC`. Например: - -``` -myproject 9f3a82975136d66d04ebcb9ce90b14428077099417b6c170e2ef2fef-1589786063772 274bd7e41dd9 16 seconds ago 65.4MB -myproject 7a29ff1ba40e2f601d1f9ead88214d4429835c43a0efd440e052e068-1589786061907 e455d998a06e 18 seconds ago 65.4MB -myproject 878f70c2034f41558e2e13f9d4e7d3c6127cdbee515812a44fef61b6-1589786056879 771f2c139561 23 seconds ago 65.4MB -myproject 5e4cb0dcd255ac2963ec0905df3c8c8a9be64bbdfa57467aabeaeb91-1589786050923 699770c600e6 29 seconds ago 65.4MB -myproject 14df0fe44a98f492b7b085055f6bc82ffc7a4fb55cd97d30331f0a93-1589786048987 54d5e60e052e 31 seconds ago 64.2MB -``` - -Стадии в _удалённом хранилище_ именуются согласно следующей схемы: `CONTAINER_REGISTRY_REPO:STAGE_DIGEST-TIMESTAMP_MILLISEC`. Например: - -``` -localhost:5000/myproject-stages d4bf3e71015d1e757a8481536eeabda98f51f1891d68b539cc50753a-1589714365467 7c834f0ff026 20 hours ago 66.7MB -localhost:5000/myproject-stages e6073b8f03231e122fa3b7d3294ff69a5060c332c4395e7d0b3231e3-1589714362300 2fc39536332d 20 hours ago 66.7MB -localhost:5000/myproject-stages 20dcf519ff499da126ada17dbc1e09f98dd1d9aecb85a7fd917ccc96-1589714359522 f9815cec0867 20 hours ago 65.4MB -localhost:5000/myproject-stages 1dbdae9cc1c9d5d8d3721e32be5ed5542199def38ff6e28270581cdc-1589714352200 6a37070d1b46 20 hours ago 65.4MB -localhost:5000/myproject-stages f88cb5a1c353a8aed65d7ad797859b39d357b49a802a671d881bd3b6-1589714347985 5295f82d8796 20 hours ago 65.4MB -localhost:5000/myproject-stages 796e905d0cc975e718b3f8b3ea0199ea4d52668ecc12c4dbf85a136d-1589714344546 a02ec3540da5 20 hours ago 64.2MB -``` - -- `PROJECT_NAME` — имя проекта; -- `CONTAINER_REGISTRY_REPO` — репозиторий, заданный опцией `--repo`; -- `STAGE_DIGEST` — дайджест стадии. Дайджест является идентификатором содержимого стадии и также зависит от истории правок в git репозитории, которые привели к такому содержимому. -- `TIMESTAMP_MILLISEC` — уникальный идентификатор, который генерируется в процессе [процедуры сохранения стадии]({{ "internals/build_process.html#сохранение-стадий-в-хранилище" | true_relative_url }}) после того как стадия была собрана. +### Типы хранилища #### Первичный репозиторий @@ -473,29 +264,6 @@ application(); $.noConflict(); -<< как это работает - - - - - ---- - ->> Организация хранилища - - - -<< Организация хранилища - - - - - - - - ->> Как это работает - # Процесс сборки Сборочный процесс werf для образов, описанных в [werf.yaml]({{ "reference/werf_yaml.html" | true_relative_url }}), подразумевает [последовательную сборку стадий]({{ "internals/stages_and_storage.html" | true_relative_url }}#конвеер-стадий) для описанных образов. @@ -608,13 +376,8 @@ werf использует алгоритм оптимистичных блоки << Как это работает - - - - >> Конфигурация сборщика - << Конфигурация сборщика @@ -678,109 +441,6 @@ werf использует `--synchronization=https://synchronization.werf.io` п >> Дизайн стапеля - - - - -## Артефакты - -### Что такое артефакты? - -***Артефакт*** — это специальный образ, используемый в других артефактах или отдельных образах, описанных в конфигурации. Артефакт предназначен преимущественно для отделения ресурсов инструментов сборки от процесса сборки образа приложения. Примерами таких ресурсов могут быть — программное обеспечение или данные, которые необходимы для сборки, но не нужны для запуска приложения, и т.п. - -Используя артефакты, вы можете собирать неограниченное количество компонентов, что позволяет решать, например, следующие задачи: -- Если приложение состоит из набора компонент, каждый со своими зависимостями, то обычно вам приходится пересобирать все компоненты каждый раз. Вам бы хотелось пересобирать только те компоненты, которым это действительно нужно. -- Компоненты должны быть собраны в разных окружениях. - -Импортирование _ресурсов_ из _артефактов_ указывается с помощью [директивы import]({{ "advanced/building_images_with_stapel/import_directive.html" | true_relative_url }}) в конфигурации в [_секции образа_]({{ "reference/werf_yaml.html#секция-image" | true_relative_url }}) или _секции артефакта_. - -### Конфигурация - -Конфигурация _артефакта_ похожа на конфигурацию обычного _образа_. Каждый _артефакт_ должен быть описан в своей секции конфигурации. - -Инструкции, связанные со стадией _from_ (инструкции указания [базового образа]({{ "advanced/building_images_with_stapel/base_image.html" | true_relative_url }}) и [монтирования]({{ "advanced/building_images_with_stapel/mount_directive.html" | true_relative_url }})), а также инструкции [импорта]({{ "advanced/building_images_with_stapel/import_directive.html" | true_relative_url }}) точно такие же как и при описании _образа_. - -Стадия добавления инструкций Docker (`docker_instructions`) и [соответствующие директивы]({{ "advanced/building_images_with_stapel/docker_directive.html" | true_relative_url }}) не доступны при описании _артефактов_. _Артефакт_ — это инструмент сборки, и все что от него требуется, это — только данные. - -Остальные _стадии_ и инструкции описания артефактов рассматриваются далее подробно. - -#### Именование - -
-```yaml -artifact: string -``` -
- -_Образ артефакта_ объявляется с помощью директивы `artifact`. Синтаксис: `artifact: string`. Так как артефакты используются только самим werf, отсутствуют какие-либо ограничения на именование артефактов, в отличие от ограничений на [именование обычных _образов_]({{ "reference/werf_yaml.html#секция-image" | true_relative_url }}). - -Пример: -```yaml -artifact: "application assets" -``` - -#### Добавление исходного кода из git-репозиториев - -
- - - - - -
- -В отличие от обычных _образов_, у _конвейера стадий артефактов_ нет стадий _gitCache_ и _gitLatestPatch_. - -> В werf для _артефактов_ реализована необязательная зависимость от изменений в git-репозиториях. Таким образом, по умолчанию werf игнорирует какие-либо изменения в git-репозитории, кэшируя образ после первой сборки. Но вы можете определить зависимости от файлов и папок, при изменении в которых образ артефакта будет пересобираться - -Читайте подробнее про работу с _git-репозиториями_ в соответствующей [статье]({{ "advanced/building_images_with_stapel/git_directive.html" | true_relative_url }}). - -#### Запуск инструкций сборки - -
- - - - - -
- -У артефактов точно такое же как и у обычных образов использование директив и пользовательских стадий — _beforeInstall_, _install_, _beforeSetup_ и _setup_. - -Если в директиве `stageDependencies` в блоке git для _пользовательской стадии_ не указана зависимость от каких-либо файлов, то образ кэшируется после первой сборки, и не будет повторно собираться пока соответствующая _стадия_ находится в _stages storage_. - -> Если необходимо повторно собирать артефакт при любых изменениях в git, нужно указать _stageDependency_ `**/*` для соответствующей _пользовательской_ стадии. Пример для стадии _install_: -```yaml -git: -- to: / - stageDependencies: - install: "**/*" -``` - -Читайте подробнее про работу с _инструкциями сборки_ в соответствующей [статье]({{ "advanced/building_images_with_stapel/assembly_instructions.html" | true_relative_url }}). - -### Использование артефактов - -В отличие от [*обычного образа*]({{ "advanced/building_images_with_stapel/assembly_instructions.html" | true_relative_url }}), у *образа артефакта* нет стадии _git latest patch_. Это сделано намеренно, т.к. стадия _git latest patch_ выполняется обычно при каждом коммите, применяя появившиеся изменения к файлам. Однако *артефакт* рекомендуется использовать как образ с высокой вероятностью кэширования, который обновляется редко или нечасто (например, при изменении специальных файлов). - -Пример: нужно импортировать в артефакт данные из git, и пересобирать ассеты только тогда, когда изменяются влияющие на сборку ассетов файлы. Т.е. в случае, изменения каких-либо других файлов в git, ассеты пересобираться не должны. - -Конечно, существуют случаи когда необходимо включать изменения любых файлов git-репозитория в _образ артефакта_ (например, если в артефакте происходит сборка приложения на Go). В этом случае необходимо указать зависимость относительно стадии (сборку которой необходимо выполнять при изменениях в git) с помощью `git.stageDependencies` и `*` в качестве шаблона. Пример: - -```yaml -git: -- add: / - to: /app - stageDependencies: - setup: - - "*" -``` - -В этом случае любые изменения файлов в git-репозитории будут приводить к пересборке _образа артефакта_, и всех _образов_, в которых определен импорт этого артефакта. - -**Замечание:** Если вы используете какие-либо файлы и при сборке _артефакта_ и при сборке [*обычного образа*]({{ "advanced/building_images_with_stapel/assembly_instructions.html" | true_relative_url }}), правильный путь — использовать директиву `git.add` при описании каждого образа, где это необходимо, т.е. несколько раз. **Не рекомендуемый** вариант — добавить файлы при сборке артефакта, а потом импортировать их используя директиву `import` в другой образ. - - # Интеграция с SSH-агентом werf необходим ssh-ключ пользователя в следующих случаях: diff --git a/docs/pages_ru/usage/build_draft/building.md b/docs/pages_ru/usage/build_draft/building.md index 3c7eb1b8b2..d2a2cd7513 100644 --- a/docs/pages_ru/usage/build_draft/building.md +++ b/docs/pages_ru/usage/build_draft/building.md @@ -3,4 +3,373 @@ title: Сборочный процесс permalink: usage/build_draft/building.html --- - +Запуск сборки в werf осуществляется базовой командой `werf build`. + +Команда сборки `werf build` поддерживает работу в локальном режиме без Container Registry, либо в режиме с публикацией образов в Container Registry. + +Также сборку могут автоматически осуществлять и другие команды, которые требуют наличия собранных образов в Container Registry, чтобы выполнять свою задачу. Например, выкат приложения через `werf converge`, или запуск произвольной команды в отдельном собранном образе через `werf kube-run`, или рендер манифестов для деплоя в Kubernetes, которые также используют имена собранных образов `werf render` (опционально). + +> **ЗАМЕЧАНИЕ:** Парадигма сборки и публикации образов в werf отличается от парадигмы предлагаемой сборщиком docker, в котором есть 2 команды: build и push. В werf есть только команда build, которая собирает образы локально, либо собирает и публикует образы в указанный Container Registry. В секции [послойное кеширование в Container Registry](#послойное-кеширование-в-container-registry) подробно рассмотрен алгоритм работы сборки и чем обусловлено использование такой парадигмы. + +## Параллельная сборка + +По умолчанию все образы описанные в `werf.yaml` будут собираться параллельно на одном сборочном хосте. При этом если между образами есть какие-то зависимости, то werf автоматически их высчитывает и осуществляет сборку образов в правильном порядке. После построение дерева зависимостей образов, werf разбивает сборку на этапы. Каждый этап содержит набор независимых образов, которые могут собираться параллельно. + +Рассмотрим следующий пример: + +```Dockerfile +# backend/Dockerfile +FROM node as backend +WORKDIR /app +COPY package*.json /app/ +RUN npm ci +COPY . . +CMD ["node", "server.js"] +``` + +```Dockerfile +# frontend/Dockerfile + +FROM ruby as application +WORKDIR /app +COPY Gemfile* /app +RUN bundle install +COPY . . +RUN bundle exec rake assets:precompile +CMD ["rails", "server", "-b", "0.0.0.0"] + +FROM nginx as assets +WORKDIR /usr/share/nginx/html +COPY configs/nginx.conf /etc/nginx/conf.d/default.conf +COPY --from=application /app/public/assets . +COPY --from=application /app/vendor . +ENTRYPOINT ["nginx", "-g", "daemon off;"] +``` + +```yaml +image: backend +dockerfile: Dockerfile +context: backend +--- +image: frontend +dockerfile: Dockerfile +context: frontend +target: application +--- +image: frontend-assets +dockerfile: Dockerfile +context: frontend +target: assets +``` + +Имеется 3 образа `backend`, `frontend` и `frontend-assets`. Образ `frontend-assets` зависит от `frontend`, потому что он импортирует скомпилированные ассеты из `frontend`. + +Формируются следующие наборы для сборки: + +```shell +┌ Concurrent builds plan (no more than 5 images at the same time) +│ Set #0: +│ - ⛵ image backend +│ - ⛵ image frontend +│ +│ Set #1: +│ - ⛵ frontend-assets +└ Concurrent builds plan (no more than 5 images at the same time) +``` + +Параллельная сборка в werf регулируется двумя параметрами `--parallel=true` и `--parallel-tasks-limit=5`. По умолчанию параллельная сборка включена и собирается не более 5 образов одновременно. + +Отметим что при использовании промежуточных стадий Dockerfile палаллельность их сборки также определяется на основе дерева зависимостей стадий между собой. Также если стадия из одного и того же Dockerfile переиспользуется в разных образах объявленных в `werf.yaml`, то werf обеспечит однократную сборку этой общей стадии без лишних пересборок. + +## Хранилище + +werf собирает образы, состоящие из набора слоёв. Все слои собираемых образов сохраняются в так называемое **хранилище** по мере сборки. + +Большинство команд werf требуют указания места размещения хранилища с помощью ключа `--repo` или переменной окружения `WERF_REPO`. + +Есть два вида хранилища: локальное и репозиторий (Container Registry). + +**Локальное хранилище** стадий будет задействовано, если вызвать команду `werf build` без аргумента `--repo`. Его можно использовать лишь в рамках локальной машины в ограниченном наборе команд (`werf build` и `werf run`). Такой режим применим, например, для локальной разработки без выката в Kubernetes. В качестве локального хранилища выступает docker server или buildah storage ([см. сборочный бэкенд](#сборочный-бэкенд)). + +Для выката приложения в Kubernetes werf предполагает использование режима сборки с публикацией образов в Container Registry — т.н. **хранилище в репозитории**. Такой режим включается при использовании команды `werf build --repo REPO`. В указанный репозиторий сохраняются следующие данные: +* итоговые образы вместе с кешом промежуточных стадий; +* служебные метаданные, необходимые для оптимизации сборки, корректной работе алгоритма очистки registry и пр. + +> **ЗАМЕЧАНИЕ:** Если запустить сборку с хранилищем стадий в репозитории, то werf сначала проверит наличие требуемых стадий в локальном хранилище и скопирует оттуда подходящие стадии, чтобы не пересобирать эти стадии заново. + +Каждый проект должен использовать в качестве хранилища уникальный адрес репозитория, который используется только этим проектом. + +Предполагается, что хранилище в репозитории для проекта не будет удалено или очищено сторонними средствами без негативных последствий для пользователей CI/CD построенного на основе werf. + +По умолчанию рекомендуется использовать стандартное хранилище в репозитории. В разделе [организация хранилища стадий]({{ "/usage/build_draft/storage.html" | true_relative_url }}) подробно рассмотрены вопросы организации и кастомизации хранилища под нужды проекта. + +## Послойное кеширование в Container Registry + +В werf реализован алгоритм сборки Dockerfile, который позволяет *уменьшить среднее время сборок* коммитов проекта, а также *обеспечить воспроизводимость собранных образов* для любого коммита проекта (воспроизводимость на любом этапе CI/CD и при откате приложения к произвольному предыдущему коммиту). + +В изначальный дизайн алгоритма сборки заложено сохранение сборочного кеша в Container Registry, поэтому из коробки, без специальных настроек обеспечивается: +* Переиспользование сборочного кеша в распределённом окружении (когда сборка осуществляется с разных хостов). +* Атомарное сохранение как промежуточных слоёв так и итоговых образов в Container Registry. +* Гарантия неизменности однажды опубликованных слоёв и итоговых образов в Container Registry. + +Алгоритм реализован за счёт отступления от стандартной для docker парадигмы разделения стадий build и push, и переходу к одной стадии build, совмещающей сборку и публикацию слоёв. Стандартный подход сборки и публикации образов и слоёв через docker может выглядеть следующим образом: +1. Скачивание сборочного кеша из Container Registry (опционально). +2. Локальная сборка всех промежуточных слоёв образа с использованием локального кеша слоёв. +3. Публикация собранного образа. +4. Публикация локального сборочного кеша в Container Registry (опционально). + +Алгоритм сборки образов в werf работает по-другому: +1. Если очередной собираемый слой уже есть в Container Registry, то его сборка и скачивание не происходит. +2. Если очередной собираемый слой отсутствует в Container Registry, то скачивается предыдущий слой, базовый для сборки текущего. +3. Новый слой собирается на локальной машине и публикуется в Container Registry. +4. В момент публикации автоматически разрешаются конфликты между сборщиками с разных хостов, которые пытаются опубликовать один и тот же слой. В этом случае гарантированно будет опубликован только один слой и все остальные сборщики будут обязаны переиспользовать именно его. (Такое возможно за счёт [использования встроенного сервиса синхронизации](#синхронизация-сборщиков)). +5. И т.д. до тех пор пока не будут собраны все слои образа. + +## Тегирование образов + +По умолчанию werf автоматизирует процесс тегирования собираемых образов. Любая команда werf, которая требует образов для выполнения своей работы автоматически рассчитывает теги образов для текущего git-коммита, проверяет наличие требуемых тегов в хранилище в репозитории, дособирает нехватающие образы если их там не оказалось. + +По умолчанию **тег — это некоторый идентификатор в виде хэша**, включающий в себя контрольную сумму инструкций и файлов сборочного контекста. Например: + +``` +registry.example.org/group/project d4bf3e71015d1e757a8481536eeabda98f51f1891d68b539cc50753a-1589714365467 7c834f0ff026 20 hours ago 66.7MB +registry.example.org/group/project e6073b8f03231e122fa3b7d3294ff69a5060c332c4395e7d0b3231e3-1589714362300 2fc39536332d 20 hours ago 66.7MB +``` + +Такой тег будет меняться только при изменении входных данных для сборки образа. Таким образом один тег может быть переиспользован для разных git-коммитов, werf берёт на себя: +- расчёт таких тегов; +- атомарную публикацию образов по этим тегам в хранилище; +- передачу тегов в Helm-чарт. + +Образы в репозитории именуются согласно следующей схемы: `CONTAINER_REGISTRY_REPO:DIGEST-TIMESTAMP_MILLISEC` + +- `CONTAINER_REGISTRY_REPO` — репозиторий, заданный опцией `--repo`; +- `DIGEST` — это контрольная сумма от: + - сборочных инструкций описанных в Dockerfile или werf.yaml; + - файлов сборочного контекста, используемых в тех или иных сборочных инструкциях. +- `TIMESTAMP_MILLISEC` — временная отметка, которая проставляется в процессе [процедуры сохранения слоя в Container Registry](#послойное-кеширование-в-container-registry) после того как стадия была собрана. + +Сборочный алгоритм также дополнительно гарантирует нам, что образ под таким тегом является уникальным и этот тег никогда не будет перезаписан образом с другим содержимым. + +### Тегирование промежуточных слоёв + +Образы состоят из набора слоёв, каждый слой имеет уникальное имя-идентификатор, а в качестве финального образа используется последний слой . +TODO + +### Получение тегов + +Чтобы выгрузить теги всех образов для текущего состояния может использоваться опция `--report-path` для команд `werf build`, `werf converge` и пр.: + +```shell +# по умолчанию формат json +werf build --report-path=images.json --repo REPO + +# поддерживается формат envfile +werf converge --report-path=images.env --report-format=envfile --repo REPO + +werf render --report-path=images.json --repo REPO +``` + +> **ЗАМЕЧАНИЕ:** Получить теги заранее, не вызывая сборочный процесс, на данный момент невозможно, можно получить лишь теги уже собранных ранее образов. + +Получить теги образов также можно через сервисные значения, передаваемые из сборочного процесса в Helm-чарт, следующей командой: + +```shell +werf helm get-autogenerated-values --repo REPO +``` + +### Кастомизация тегов + +Несмотря на использование автоматических тегов по умолчанию, имеется возможность добавить дополнительные теги для собираемых образов и использовать их в процессе выката Helm-чарта. Для этого используются опции `--add-custom-tag` — для добавления произвольного количества тегов-алиасов, и опция `--use-custom-tag` — для выбора определённого тега, который будет использоваться в именах образов в Helm-чарте (опция `--use-custom-tag` также неявно добавляет тег-алиас и включает его использование). + +```shell +werf build --repo REPO --add-custom-tag main + +# можно добавить несколько тегов-алиасов +werf build --repo REPO --add-custom-tag main --add-custom-tag latest --add-custom-tag prerelease + +# можно добавить несколько тегов и использовать тег "main" для образов в Helm-чарте +werf converge --repo REPO --add-custom-tag latest --add-custom-tag prerelease --use-custom-tag main +``` + +> **ЗАМЕЧАНИЕ:** При использовании опций создаются **дополнительные теги алиасы**, ссылающиеся на автоматические теги-хэши. Полное отключение создания автоматических тегов не предусматривается. + +## Синхронизация сборщиков + +Сервер синхронизации — это сервисный компонент werf, который предназначен для координации нескольких процессов werf и выполняет роль _менеджера блокировок_. Блокировки требуются для корректной публикации новых образов в Container Registry и реализации алгоритма сборки, описанного в разделе [послойное кеширование в Container Registry](#послойное-кеширование-в-container-registry). + +Все команды, использующие параметры хранилища (`--repo=...`) также имеют опцию указания адреса менеджера блокировок, который задается опцией `--synchronization=...` или переменной окружения `WERF_SYNCHRONIZATION=...`. Существует 3 возможных опции для указания типа используемой синхронизации: +1. Локальный хост. Включается опцией `--synchronization=:local`. Локальный _менеджер блокировок_ использует файловые блокировки, предоставляемые операционной системой. +2. Kubernetes. Включается опцией `--synchronization=kubernetes://NAMESPACE[:CONTEXT][@(base64:CONFIG_DATA)|CONFIG_PATH]`. _Менеджер блокировок_ в Kubernetes использует ConfigMap по имени проекта `cm/PROJECT_NAME` (тот же самый что и для кеша хранилища) для хранения распределённых блокировок в аннотациях этого ConfigMap. werf использует [библиотеку lockgate](https://github.com/werf/lockgate), которая реализует распределённые блокировки с помощью обновления аннотаций в ресурсах Kubernetes. +3. Http. Включается опцией `--synchronization=http[s]://DOMAIN`. + - Есть публичный сервер синхронизации доступный по домену `https://synchronization.werf.io`. + - Собственный http сервер синхронизации может быть запущен командой `werf synchronization`. + +werf использует `--synchronization=:local` (локальный _кеш хранилища_ и локальный _менеджер блокировок_) по умолчанию, если используется локальное хранилище (`werf build` без параметра `--repo`). + +werf использует `--synchronization=https://synaskjdfchronization.werf.io` по умолчанию, если используется удалённое хранилище (`--repo=CONTAINER_REGISTRY_REPO`). + +Пользователь может принудительно указать произвольный адрес компонентов для синхронизации, если это необходимо, с помощью явного указания опции `--synchronization=:local|(kubernetes://NAMESPACE[:CONTEXT][@(base64:CONFIG_DATA)|CONFIG_PATH])|(http[s]://DOMAIN)`. + +**ЗАМЕЧАНИЕ:** Множество процессов werf, работающих с одним и тем же проектом обязаны использовать одинаковое хранилище и адрес сервера синхронизации. + +### Запуск сервера синхронизации + +TODO + +## Сборочный бэкенд + +werf поддерживает использование Docker Server или Buildah в качестве бекенда для сборки образов. Buildah поддерживает полноценную работу в контейнерах и послойную сборку Dockerfile-ов с кешированием всех промежуточных слоёв в container registry. + +TODO + +### Buildah + +> ПРИМЕЧАНИЕ: На данный момент Buildah доступен только для пользователей Linux и Windows с включённой подсистемой WSL2. Для пользователей MacOS на данный момент предлагается использование виртуальной машины для запуска werf в режиме Buildah. + +Для сборки без Docker-сервера werf использует Buildah в rootless-режиме. Buildah встроен в бинарник werf. Требования к хост-системе для запуска werf с бэкендом uildah можно найти в [инструкциях по установке](/installation.html). + +Buildah включается установкой переменной окружения `WERF_BUILDAH_MODE` в один из вариантов: `auto`, `native-chroot`, `native-rootless`. Большинству пользователей для включения режима Buildah достаточно установить `WERF_BUILDAH_MODE=auto`. + +#### Уровень изоляции сборки + +По умолчанию в режиме `auto` werf автоматически выбирает уровень изоляции в зависимости от платформы и окружения. + +Поддерживается 2 варианта изоляции сборочных контейнеров: +1. Chroot — вариант без использования container runtime, включается переменной окружения `WERF_BUILDAH_MODE=native-chroot`. +2. Rootless — вариант с использованием container runtime (в системе должен быть установлен crun, или runc, или kata, или runsc), включается переменной окружения `WERF_BUILAH_MODE=native-rootless`. + +#### Драйвер хранилища + +werf может использовать драйвер хранилища `overlay` или `vfs`: + +* `overlay` позволяет использовать файловую систему OverlayFS. Можно использовать либо встроенную в ядро Linux поддержку OverlayFS (если она доступна), либо реализацию fuse-overlayfs. Это рекомендуемый выбор по умолчанию. +* `vfs` обеспечивает доступ к виртуальной файловой системе вместо OverlayFS. Эта файловая система уступает по производительности и требует привилегированного контейнера, поэтому ее не рекомендуется использовать. Однако в некоторых случаях она может пригодиться. + +Как правило, достаточно использовать драйвер по умолчанию (`overlay`). Драйвер хранилища можно задать с помощью переменной окружения `WERF_BUILDAH_STORAGE_DRIVER`. + +#### Ulimits + +По умолчанию Buildah режим в werf наследует системные ulimits при запуске сборочных контейнеров. Пользователь может переопределить эти параметры с помощью переменной окружения `WERF_BUILDAH_ULIMIT`. + +Формат `WERF_BUILDAH_ULIMIT=type=softlimit[:hardlimit][,type=softlimit[:hardlimit],...]` — конфигурация лимитов, указанные через запятую: +* "core": maximum core dump size (ulimit -c) +* "cpu": maximum CPU time (ulimit -t) +* "data": maximum size of a process's data segment (ulimit -d) +* "fsize": maximum size of new files (ulimit -f) +* "locks": maximum number of file locks (ulimit -x) +* "memlock": maximum amount of locked memory (ulimit -l) +* "msgqueue": maximum amount of data in message queues (ulimit -q) +* "nice": niceness adjustment (nice -n, ulimit -e) +* "nofile": maximum number of open files (ulimit -n) +* "nproc": maximum number of processes (ulimit -u) +* "rss": maximum size of a process's (ulimit -m) +* "rtprio": maximum real-time scheduling priority (ulimit -r) +* "rttime": maximum amount of real-time execution between blocking syscalls +* "sigpending": maximum number of pending signals (ulimit -i) +* "stack": maximum stack size (ulimit -s) + +## Работа в контейнерах + +werf поддерживает разные варианты сборки образов при запуске в контейнерах. Рекомендуемым вариантом является использование сборочного бекэнда Buildah, т.к. он не требует внешних зависимостей и прост в настройке. При использовании бекэнда Docker Server будет необходим доступ к серверу Docker и с этим будет связана сложность корректной настройки, а также в этом варианте не будут доступны все возможности werf (см. подробнее далее). + + +Для использования overlayfs в пользовательском режиме без root: + +```shell +docker run \ + --security-opt seccomp=unconfined --security-opt apparmor=unconfined \ + registry.werf.io/werf/werf:latest WERF_COMMAND +``` + +Если ядро не предоставляет overlayfs для пользовательского режима без root, то следует использовать fuse-overlayfs: + +```shell +docker run \ + --device /dev/fuse \ + --security-opt seccomp=unconfined --security-opt apparmor=unconfined \ + registry.werf.io/werf/werf:latest WERF_COMMAND +``` + +Рекомендуется использовать образ `registry.werf.io/werf/werf:1.2-stable`, также доступны следующие образы: +- `registry.werf.io/werf/werf:latest` — алиас для `registry.werf.io/werf/werf:1.2-stable`; +- `registry.werf.io/werf/werf:1.2-{alpha|beta|ea|stable|rock-solid}` все образы основаны на alpine, выбираем только канал стабильности; +- `registry.werf.io/werf/werf:1.2-{alpha|beta|ea|stable|rock-solid}-{alpine|ubuntu|fedora}` — выбираем канал стабильности и базовый дистрибутив. + +При использовании этих образов автоматически будет использоваться бэкенд Buildah. Опций для переключения на использование бекэнда Docker Server не предоставляется. + +### Работа через Docker Server (не рекомендуется) + +> **ЗАМЕЧАНИЕ:** Для этого метода официальных образов с werf не предоставляется, самостоятельно соберите образ с werf, либо перенастройте образ на базе `registry.werf.io/werf/werf` на использование бэкенда Docker Server вместо Buildah. + +Для использования локального docker-сервера необходимо примонтировать docker-сокет в контейнер и использовать привилегированный режим: + +```shell +docker run \ + --privileged \ + --volume $HOME/.werf:/root/.werf \ + --volume /tmp:/tmp \ + --volume /var/run/docker.sock:/var/run/docker.sock \ + IMAGE WERF_COMMAND +``` + +— этот метод поддерживает сборку Dockerfile-образов или stapel-образов. + +Для работы с docker-сервером по tcp можно использовать следующую команду: + +```shell +docker run --env DOCKER_HOST="tcp://HOST:PORT" IMAGE WERF_COMMAND +``` + +— такой метод поддерживает только сборку Dockerfile-образов. Образы stapel не поддерживаются, поскольку сборщик stapel-образов использует монтирование директорий из хост-системы в сборочные контейнеры. + +### Устранение проблем + +#### `fuse: device not found` + +Полностью данная ошибка может выглядеть следующим образом: + +``` +error mounting new container: error mounting build container "53f916e7a334a4bb0d9dbc38a0901718d40b99765002bb7f2f2e5464b1db4294": error creating overlay mount to /home/build/.local/share/containers/storage/overlay/49e856f537ba58afdc09137291133994cd1305e40df72c4fab43077cbd405477/merged, mount_data=",lowerdir=/home/build/.local/share/containers/storage/overlay/l/Z5GEVIFIIQ7H262DYUTX3YOVR6:/home/build/.local/share/containers/storage/overlay/l/PJBBW6UNUNGI37IX6R3LDNPX3J:/home/build/.local/share/containers/storage/overlay/l/MUYSUONLQVE4CJMQVDCH2UBAVQ:/home/build/.local/share/containers/storage/overlay/l/67JHKJDCKBTI4R3Q5S5YG44AD3:/home/build/.local/share/containers/storage/overlay/l/3S72G4SWKDXILGANUOCESP5LDK,upperdir=/home/build/.local/share/containers/storage/overlay/49e856f537ba58afdc09137291133994cd1305e40df72c4fab43077cbd405477/diff,workdir=/home/build/.local/share/containers/storage/overlay/49e856f537ba58afdc09137291133994cd1305e40df72c4fab43077cbd405477/work,volatile": using mount program /usr/bin/fuse-overlayfs: fuse: device not found, try 'modprobe fuse' first +fuse-overlayfs: cannot mount: No such file or directory +: exit status 1 +time="2021-12-06T11:30:20Z" level=error msg="exit status 1" +``` + +Решение: включите fuse device для контейнера, в котором запущен werf ([подробности](#ядро-linux-без-поддержки-overlayfs-в-режиме-rootless-и-использование-непривилегированного-контейнера)). + +#### `flags: 0x1000: permission denied` + +Полностью данная ошибка может выглядеть следующим образом: + +``` +time="2021-12-06T11:23:23Z" level=debug msg="unable to create kernel-style whiteout: operation not permitted" +time="2021-12-06T11:23:23Z" level=debug msg="[graphdriver] trying provided driver \"overlay\"" +time="2021-12-06T11:23:23Z" level=debug msg="overlay: mount_program=/usr/bin/fuse-overlayfs" +Running time 0.01 seconds +Error: unable to get buildah client: unable to create new Buildah instance with mode "native-rootless": unable to get storage: mount /home/build/.local/share/containers/storage/overlay:/home/build/.local/share/containers/storage/overlay, flags: 0x1000: permission denied +time="2021-12-06T11:23:23Z" level=error msg="exit status 1" +``` + +Решение: отключите профили AppArmor и seccomp с помощью параметров `--security-opt seccomp=unconfined` и `--security-opt apparmor=unconfined`, добавьте специальные аннотации в Pod ([подробности](#ядро-linux-без-поддержки-overlayfs-в-режиме-rootless-и-использование-непривилегированного-контейнера)). + +#### `unshare(CLONE_NEWUSER): Operation not permitted` + +Полностью данная ошибка может выглядеть следующим образом: + +``` +Error during unshare(CLONE_NEWUSER): Operation not permitted +ERRO[0000] error parsing PID "": strconv.Atoi: parsing "": invalid syntax +ERRO[0000] (unable to determine exit status) +``` + +Решение: отключите профили AppArmor и seccomp с помощью параметров `--security-opt seccomp=unconfined` и `--security-opt apparmor=unconfined`, добавьте специальные аннотации в Pod или используйте привилегированный контейнер ([подробности](#режимы-работы)). + +#### `User namespaces are not enabled in /proc/sys/kernel/unprivileged_userns_clone` + +Решение: +```bash +# Включить непривилегированные user namespaces: +echo 'kernel.unprivileged_userns_clone = 1' | sudo tee -a /etc/sysctl.conf +sudo sysctl -p +```