Как стать автором
Обновить

Комментарии 32

Мы пока не решили :)

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

Вроде docker из коробки сейчас умеет делать то же самое, нет?

DOCKER_BUILDKIT=1 docker build --build-arg BUILDKIT_INLINE_CACHE=1

В статье в первую очередь рассматривается гитерминизм. И werf тут в первую очередь - это gitops утилита. Докер из коробки не реализует этот подход.

Docker не обеспечит иммутабельность публикуемых образов. werf обеспечивает гарантию, что если какой-то образ или отдельный stage связанный с коммитом однажды опубликован в regsitry, то он не будет перетёрт другим образом по тому же тегу. Это нужно для обеспечения воспроизводимости образов по коммиту.

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

окей. Это очень интересный вопрос. А как решается проблема с хэш коллизиями? Ну, очевидно же, что имя образа конечного или с промежуточным слоем на большом проекте может случайно задублироваться. Даже в git была проблема с коллизиями хэшей. https://github.blog/2017-03-20-sha-1-collision-detection-on-github-com/

Вторая история - гитерминизм предполагает, что все исходные зависимости тоже полностью определены, так ведь? Тогда получается, что если я какие-то зависимости не зафиксировал (например, делаю apt upgrade в докерфайле), то при потере кэша я получу совершенно новый артефакт и весь гитерминизм сломается. Ну, реально - невозможно контролировать всю цепочку, только если не перенести ее полностью к себе (начиная с базовых образов и репозиториев для большинства пакетных менеджеров - pypi, npm, apt/yum etc.)

Попробую рассказать на примере.

Каждая стадия и конечный образ имеют content-based tag. Он состоит из двух частей: content checksum и timestamp. Два сборщика начинают собирают стадию с одним и тем же content checksum на разных билдерах. Какой-то сборщик завершает сборку быстрее, чем первый. Этот сборщик сразу после сборки стадии пытается опубликовать стадию в container registry. Для этого он проверяет, что стадия ещё не опубликована по content checksum, если уже опубликована, то сборщик выбрасывает свой собранный стейж и использует далее то что нашёл в container registry. Если стадия не опубликована, то werf берёт короткоживущий distributed lock по content checksum и опять для корректности проверяет, что стадия не появилась в container registry. Если стадии нет, то мы генерируем полный content-based-tag подставляя content checksum и текущий timestamp и публикуем стадию. После отпускаем distributed lock и стадия становится моментально доступна для всех сборщиков.

Далее там есть моменты, связанные с тем, что werf обеспечивает изоляцию сборочного кеша на основе git-истории. А это значит, что по одному и тому же content checksum в разных ветках может быть опубликована своя стадия (во-первых будет разный timestamp, во-вторых, даже если произойдёт коллизия timestamp, то werf заметит уже существующий тег и просто сгенерит timestamp ещё раз). Алгоритм подбора существующих стадий обеспечит изоляцию кеша до тех пор, пока ветка не будет смержена в текущую ветку. Как только такой мерж происходит, то и собранный кеш для смерженных коммитов начинает быть доступен в основной ветке (по факту среди нескольких образов с одним и тем же content checksum будет выбран тот, который собран раньше по timestamp).

Это всё можно назвать mvcc с оптимистичными блокировками, это реализует werf под капотом с использованием сервера синхронизации.

docker принципиально работает по другому алгоритму. Сначала он попытается спуллить все стадии из container registry. Затем соберёт все стадии локально. Затем запушит результирующие стадии и результирующий образ.

werf делает этот процесс _по одной стадии_ (собрали стадию, опубликовали стадию) и связывает кеш с коммитами, что позволяет сразу после сборки переиспользовать общий кеш.

Про вторую историю. Совсем не обязательно что зависимости строго определены. Т.к. кеш иммутабельный и не удаляется из container registry, то те версии зависимостей которые были когда-то собраны для коммита остаются закешированы навсегда. Обеспечивается воспроизводимость однажды собранного кеша для коммита. Если же зависимости необходимо апдейтнуть, то мы создаём коммит, в котором инициируем сброс соотв. стадии (для этого мы либо меняет в гите файл, на изменения которого завязана сборка стадии, либо меняем в werf.yaml спец. поле "версия кеша").

Есть ли быть точнее, то флоу должен выглядеть как-то так:

docker build \
            --cache-from $CACHE_IMAGE:latest \
            --tag $CACHE_IMAGE:latest \
            --build-arg BUILDKIT_INLINE_CACHE=1 \
            "."
docker push $CACHE_IMAGE:latest

Грубо говоря, werf делает это из коробки, но поинтереснее:

  • Вместо сборки и публикации всего образа целиком, werf делает это стадиями (слоями). После сборки слой уходит в container registry и уже может использоваться остальными сборщиками.

  • werf гарантирует воспроизводимость и неизменность кэша. Сборка одного и того же слоя несколькими сборщиками не приведёт к коллизиям и нарушению воспроизводимости остальных сборок. При публикации первый сборщик загрузит свой слой, а второй сборщик отбросит свой результат и будет использовать актуальный слой для текущей сборки.

Спасибо за статью - интересный вариант локальной работы, но, на мой взгляд, перспектива все-таки в другом сценарии - работа с удаленным кластером. В этом случае мы можем сделать как: завести под разработчика ns со всеми необходимыми компонентами (в этом случае мы не упремся в ситуацию, когда все необходимое окружение попросту НЕ ВЛЕЗАЕТ в ноутбук разраба), далее два варианта - либо запускать код локально и каким-то образом проксировать доступы до кластера (как будто отлично с этой задачей справляются решения вроде https://www.telepresence.io/), либо запускать код в удаленном поде и настраивать синхронизацию исходников (что-то вроде https://tilt.dev/)

Окей - в конце-концов есть еще https://skaffold.dev/docs/pipeline-stages/

Почему не minikube? Потому что, как я уже сказал, машинки разработчика обычно достаточно хилые по сравнению с продовыми кластерами. Но мощнее, чем тестовый кластер на фритир в оракл клауде :-) Все-таки на 6 ядер и 16-32ГБ ОЗУ можно хоть что-то развернуть. Но самое главное другое - миникуб представляет из себя только одну из возможностей для деплоя. А если в проде опеншифт? А если какая-то особая конфигурация vanilla? Да ты замучаешься подгонять манифесты. Т.е. миникуб дает базовый кубернетес, но не дает полную идентичность с production окружением за которое в статье активно ратуют... И вся модель рассыпается.

Да, вы правы! Вариаций может быть очень много. Одну из них я постарался описать в этой статье :)

Миникуб тут как один из вариантов. По сути совсем не важно в какой kubernetes деплоить. Это может быть как любой из вариантов локальных кластеров, так и варианты с удалёнными кластерами. werf'у достаточно указать кубконфиг, с которым он подключается к кластеру и docker registry, в котором хранить образы. Должно лишь соблюдаться условие что kubernetes, в который происходит деплой имеет доступ в registry, где лежит финальный образ. При этом werf позволяет финальные и промежуточные образы пушить в разные registry.

Всё-таки Кубер привносит в разработку слишком много сложности, жаль Сварм не взлетел…

swarm нафиг не уперся и слава богу, что он не взлетел... Если хочется попроще, чем кубер - есть же nomad. И для доставки-сборки они же напилили https://www.waypointproject.io/

Честно - Хашики гениальны, реально

Самая проблематика мне кажется во всем это плане ,когда нужно будет заиспользовать https. Вот тут начнется веселье с самоподписными и указанием где то их валидности. И тут действительно использование внешнего кластера лучшее решение.

А в чем собственно проблемы могут возникнуть? Если конечное окружение работает в кубе, то для него как минимум есть cert-manager.

А в чем собственно проблемы могут возникнуть? 

локально нельзя выписать летсэнкрипт, потому что нет внешнего айпи. А если он есть - нет привязки домена к этому внешнему айпи. Можно выкрутиться сервисами типа no-ip или sslip.io, но выглядит как %$#&*%&#*$&#

А локально нужен https?

Мне кажется вы теряете суть локальной разработки. Такое окружение нужно прежде всего, что бы воспроизводить функционал приложения. И https для этого совсем не нужен.

Я просто привёл пример, когда локальное окружение хуже удаленного. Не более. Но если Вы хотите поговорить, то да, возможны ситуации, когда https нужен и не самоподписанный. Чтобы функционал проверить, погонять и эффективно разрабатывать

Что мешает купить сертификат и использовать локально? Я думаю обойдётся дешевле, чем держать лишнюю ноду в кластере.

Что мешает купить сертификат и использовать локально?

а зачем? Вы первый начали про cert-manager. К тому же, если этот сертификат скоммуниздят (а вероятность этого существенно выше на машине разраба, чем на каком-никаком сервере), то денежка пропала.

Затем же, зачем вам нужен https локально.

По моему опыту, локальная нужда в https — это дурной запах, исходящий от системы конфигурации ;)

аргументируйте

Добрый день. А вы планируете дать развёрнутый ответ Виктору Фарсику на вопросы, заданные на его канале?

Виктор, имхо, был крайне убедителен. В том числе и в комментариях к видео.

У нас запланирована с ним встреча на этот четверг. Вероятнее всего обе стороны дадут комментарии по результатам.

Если в двух словах, то с его стороны это обзор продукта на примитивном примере и без хорошего погружения в werf, а с нашей — плохое позиционирование продукта (особенно вне русскоязычного сообщества).

Спасибо, очень хорошее и убедительное видео и многие позиции, озвученные Виктором, я разделяю. Надеюсь, что по результатам встречи получим апдейты от него и от Фланта

Поддерживает ли werf какое то решение из коробки для multi-repo проектов аля микросервисов? Или же конфиги нужно мержить ручками?

Можно интегрировать их с помощь git-сабмодулей в одном репозитории или посмотреть в сторону бандлов (oci образ в container registry, который содержит helm-чарт и теги собранных образов). Для выката достаточно этого образа.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий