• Что же такое GitOps? Его свойства и недостатки
    +1

    Клиент, который взял блокировку, обязан её периодически продлять. Другой клиент, который ждёт блокировки может заметить, что она уже давно не продлевалась (есть некоторый небольшой timeout) и перехватить её. Если первый клиент не смог продлить блокировку из-за сетевого глюка, то он в какой-то момент придёт продлевать блокировку, которую уже перехватили — он это заметит и включит "особый обработчик" данной ситуации, который в случае werf как можно быстрее crash-ит текущий процесс.


    Сами блокировки оформлены в виде отдельного проекта: https://github.com/werf/lockgate.


    Такой подход в lockgate не даёт 100% гарантию корректности для любого проекта, однако предоставляет возможность определить в своём проекте этот обработчик ситуации с перехватом блокировки. В случае werf аварийного завершения процесса в этой ситуации пока хватает, да и на практике кейс возникает очень редко.

  • Что же такое GitOps? Его свойства и недостатки
    +1

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

  • Что же такое GitOps? Его свойства и недостатки
    +4

    В начале видео, где идёт уточнение терминологии, как раз говорится про различие между интуитивным обобщённым пониманием GitOps и конкретной имплементацией с pull-моделью и обязательным промежуточным репом. Данная имплементация использует докер-образы из registry и не отвечает за их корректную сборку и тегирование. Именно о такой имплементации идёт речь в видео. Вот ссылки на почитать, чтобы понять о чём идёт речь: https://blog.argoproj.io/introducing-argo-cd-declarative-continuous-delivery-for-kubernetes-da2a73a780cd, https://www.weave.works/technologies/gitops/.

  • Организация распределенного CI/CD с помощью werf
    +2

    Небольшое дополнение к статье. В werf сейчас реализован принципиально новый подход к сборке и публикации образов в docker registry, отличный от того, что используется при docker build:


    • Werf делает push каждого собранного слоя (стадии) в registry сразу после успешной сборки, что позволяет сразу переиспользовать его в других процессах сборки на произвольных машинах. Это возможно благодаря новому алгоритму публикации и выборки стадий с оптимистичными блокировками.
    • На момент публикации финального образа по определённому имени все необходимые слои, из которых состоит этот образ, уже есть в registry. Werf по факту делает push лишь для небольшого слоя с некоторой мета-информацией и ставит на этот слой тег. Таким образом этот push происходит моментально, т.к. registry переиспользует существующие слои.

    К тому же werf по умолчанию предлагает content-based-тегирование, что позволяет ещё лучше переиспользовать уже существующие слои и избавится от лишних ребилдов и редеплоев приложения.

  • Организация распределенного CI/CD с помощью werf
    0

    Так-то оно так, но ни kaniko, ни buildah не умеют собирать по-настоящему распределённый кеш. Чтобы уже собранные слои были доступны во всех сборках.


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


    Это похоже на то, что предоставляет --cache-from в docker builder, но быстрее и эффективнее и с поддержкой ansible и инкрементальных пересборок по истории git и т.д.

  • Организация распределенного CI/CD с помощью werf
    0
    Да, сборщик werf требует доступа к локальному docker-server на хостах, где запускается.

    https://habr.com/ru/company/flant/blog/504390/
    Промахнулся.

  • Организация распределенного CI/CD с помощью werf
    0

    Да, сборщик werf требует доступа к локальному docker-server на хостах, где запускается.

  • Content-based tagging в сборщике werf: зачем и как это работает?
    0

    Можно сказать по-другому: мы выстраиваем content-based файловую систему на основе docker-образов, новое состояние в этой фс создается на основе кеша stages путем сборки новых образов, идентификаторы и пересборка тесно связаны с историей правок в git.

  • Content-based tagging в сборщике werf: зачем и как это работает?
    0

    Не так. При мерже собранный кеш становится доступен для всех остальных точно также как и изменения которые были сделаны в ветке становятся доступны всем только после merge. Если мерж был не fast-forward, то возможно произойдет пересборка связанная со слиянием изменений мастера и ветки, но опять же уже собранный кеш будет учавствовать в сборке.


    Если для ветки сделать rebase, то кеш, собранный для старого коммита потеряется и более не будет использоваться, также как теряется родительская связь между коммитами при rebase — произойдет пересборка. При дальнейшем merge кеш не теряется.


    Такая изоляция — это отчасти переложение логики гита на собираемые образы.

  • Content-based tagging в сборщике werf: зачем и как это работает?
    0
  • Content-based tagging в сборщике werf: зачем и как это работает?
    +3

    Как вариант — запоминать версию кода на этапе сборки образа. Но опять же commit-id — это неидеальный идентификатор кода, потому что его изменение не означает что код в образе изменился. При этом мог быть сделан какой-то нерелевантный коммит и сборщик не стал лишний раз пересобирать образ без надобности — в этом случае образ остался связан со старым коммитом.


    Другой вариант — не встраивать информацию о коммите в образы вообще. Зачем добавлять в образ изменчивую инфу, тем более, что commit-id не отражает его содержимое. А добавлять инфу о коммите куда-то в рантайм — Kubernetes — в процессе выката приложения. При выкате werf, например, через values может передать commit-id в шаблоны. Дальше его можно положить в какой-нибудь ConfigMap, приложение же может доставать commit-id в рантайме — читать его из ConfigMap. Тут получается и овцы сыты, и волки целы: лишних пересборок нету, приложение может получить инфу о гите.

  • Content-based tagging в сборщике werf: зачем и как это работает?
    +2

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


    Другими словами: вот есть у нас 2 образа одинаковых по контенту, но собранных для разных гит-веток. Верф изолирует эти 2 образа: создаст для каждого свой идентификатор.


    При этом в рамках одной ветки образы с общим контентом будут иметь одинаковый идентификатор.

  • Content-based tagging в сборщике werf: зачем и как это работает?
    0

    Цель: изоляция кеша стадий и итоговых образов собранных для разных веток в git. Кеш, собранный для какой-либо ветки от master не будет доступен в master до тех пор, пока эта ветка не будет смержена в master.

  • 3-way merge в werf: деплой в Kubernetes с Helm «на стероидах»
    0

    Почему? Они друг другу не должны мешать.

  • GitLab CI для непрерывной интеграции и доставки в production. Часть 2: преодолевая трудности
    0

    Это простой шаблонизатор yaml, встроенный в gitlab.


    .job_template: &job_definition  # Hidden key that defines an anchor named 'job_definition'
      image: ruby:2.1
      services:
        - postgres
        - redis
    
    test1:
      <<: *job_definition           # Merge the contents of the 'job_definition' alias
      script:
        - test1 project
    
    test2:
      <<: *job_definition           # Merge the contents of the 'job_definition' alias
      script:
        - test2 project

    https://docs.gitlab.com/ee/ci/yaml/#anchors

  • Собирать Docker-образы в werf теперь можно и по обычному Dockerfile
    +3

    Решили. Была проблема с использованием RUN --mount.


    https://github.com/flant/werf/pull/1769


    Проверить можно в бета-канале <(multiwerf use 1.0 beta).

  • Собирать Docker-образы в werf теперь можно и по обычному Dockerfile
    +1
  • Собирать Docker-образы в werf теперь можно и по обычному Dockerfile
    +1

    Понял, так тоже можно. Использовать только werf build-and-publish и werf cleanup. Вот по этому гайду https://werf.io/documentation/guides/gitlab_ci_cd_integration.html#pipeline просто пропустить стадию деплоя.

  • Собирать Docker-образы в werf теперь можно и по обычному Dockerfile
    +2

    Пока нет, не смотрели, выглядит как немного не то.


    Но интеграция с самим gitlab у нас есть и достаточно плотная:



    Например werf автоматом использует токены, которые выдает gitlab для логина в docker-registry, который также задает gitlab. Werf автоматом использует gitlab-environment если он определен.


    Так-то по возможности стараемся лишнего не делать, если это можно переложить на внешнюю CI-систему.


    Какой в gitlab есть ci конкретно для деплоя в кубы, где верф будет избыточен, можно подробнее на примере? Везде где используется kubectl apply или helm upgrade можно использовать и werf deploy — тут никаких ограничений не вносится, даже наоборот werf deploy проще использовать из-за наличия интеграции с гитлабом.

  • Собирать Docker-образы в werf теперь можно и по обычному Dockerfile
    +2

    Target можно:


    configVersion: 1
    project: myproj
    ---
    image: backend
    dockerfile: ./Dockerfile
    target: backend
    ---
    image: frontend
    dockerfile: ./Dockerfile
    target: frontend

    Поддерживается любой синтаксис стандартного Dockerfile, т.к. для билда используется docker server (который может использовать buildkit).


    После того как образы описаны в werf.yaml, собраны и опубликованы (через werf build-and-publish), их можно использовать для деплоя в кубы. Для этого надо описать chart. В описанном чарте можно ссылаться на имена образов из werf.yaml, в нашем случае например так:


    apiVersion: apps/v1beta1
    kind: Deployment
    metadata:
      name: backend
    spec:
      template:
        metadata:
          labels:
            service: backend
        spec:
          containers:
          - name: main
            command: [ ... ]
    {{ tuple "backend" . | include "werf_container_image" | indent 8 }}
            env:
    {{ tuple "backend" . | include "werf_container_env" | indent 8 }}
  • Собирать Docker-образы в werf теперь можно и по обычному Dockerfile
    0

    Werf ориентирован на kubernetes. И чтобы деплоить приложения туда. И в дальнейшем чтобы собирать образы используя runner-ы работающие в самом kubernetes.

  • Собирать Docker-образы в werf теперь можно и по обычному Dockerfile
    +4

    Планируем плотно развивать тему локальной разработки с использованием werf. Это возможно включает и поддержку docker-compose. Сейчас работаем над стабилизацией версии 1.0. Где-то в конце этого года можно ждать подвижек.

  • Собирать Docker-образы в werf теперь можно и по обычному Dockerfile
    +3

    Не оставим, но в любом случае, когда выйдет стабильный helm 3 и будет способ мигрировать старые инсталляции на новый хельм — мы перейдем на кодовую базу helm 3 и будем использовать и развивать kubedog для слежения за ресурсами в werf.


    Короче советую переходить на werf ;)

  • Как победить дракона: переписываем вашу программу на Golang
    0

    Так "верфь" и есть транслитерация слова werf, а не наоборот ;)

  • Как победить дракона: переписываем вашу программу на Golang
    +2

    Это только в теории. Есть проблемы с аутентификацией в api например. Ниже ответил развернуто.


    В k8s еще есть куча оберток над этим api. Например, shared-informer-ы для слежения за состоянием ресурсов. Эта обертка решает низкоуровневые проблемы и является стандартной для написания kubernetes-операторов. В других языках такого нет, пока сам не напишешь.

  • Как победить дракона: переписываем вашу программу на Golang
    +3

    Инфраструктура — главный аргумент. На Rust не может быть богаче инфраструктура именно для Docker и Kubernetes.


    Например, по опыту с Ruby: отсуствие нормальных клиентов для Kubernetes. У нас был самописный, чтобы достучатся до некоторых фич API типа слежения за ресурсами. Самописный клиент привел к тому, что наш dapp не мог коннектится к Google Kubernetes Engine, из-за использования там кастомной схемы аутентфикации. А времени реализовать эту схему в нашем клиенте не было. Вот такого рода проблемы.


    Когда перешли на Golang — мы просто включили стандартный клиент kubernetes и все, коннект к GKE из коробки. Если появится что-то новое — сразу будет из коробки.

  • Как победить дракона: переписываем вашу программу на Golang
    +4

    Хороший вопрос. Так не сделали, потому что подход выработался не заранее перед началом работы, а уже во время переписывания.


    Во время переписывания было удобно распределить работу параллельно по людям и каждому дать задачу типа: вот тебе компонент, ожидается бинарник с таким-то интерфейсом. При этом каких-то договоренностей о том, как устроен бинарь не было, главное чтобы делал то что надо и соответствовал интерфейсу. Так было удобнее делать работу именно параллельно с точки зрения редактирования кода. В случае когда один бинарь и над ним работает несколько человек — надо сразу определиться с "правильной" организацией кода, чтобы несколько человек не редактировало один файл. Нам же был больше нужен быстрый результат, чем экономия места.


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

  • Представляем библиотеку kubedog для слежения за ресурсами Kubernetes
    +5

    Kubectl wait можно использовать в CI/CD, но есть "нюансы".


    1) Зафейлить ci/cd pipeline как можно раньше.


    Например, есть deployment с ошибкой, он никогда не перейдет в состояние READY. Если запустить kubectl wait --for condition=Available,
    то команда завершится с ошибкой только по timeout. Kubedog увидит ошибку и может сразу зафейлить ci/cd pipeline. Для пользователя это дает быстрый фидбек.


    2) Показывать "что происходит" во время ожидания.


    Kubedog следит не только за указанным ресурсом до достижения какого-то condition, но и за всеми связанными. И получает события и логи этих связанных ресурсов. Вся инфа объединяется в единый поток и выдается наверх. Грубо говоря это аггрегатор "новостей" по указанному ресурсу.


    У нас изначально стояла задача: сделать штуку для выката, которая может сказать что "все хорошо", может сказать что "все плохо" и покажет "что происходит сейчас" во время ожидания выката.


    В случае с kubectl wait надо придумывать отдельный поток/процесс для показа логов. А чтобы показать логи надо еще узнать имена связанных ресурсов. И как это все в CI/CD по-простому сделать неясно.


    Но и логи это не все, еще есть event'ы. С ними отдельная история. В event'ах может содержаться важная пользователю информация для того, чтобы исправить ошибку.


    Мы держали в голове такую мысль: следилка должна показать достаточно информации пользователю для дебага проблем. Не надо вызывать kubectl и копатся в консоли. В идеале достаточно посмотреть на вывод CI/CD pipeline и понять где ошибка.


    3) Использовать как библиотеку.


    Kubectl wait на данный момент это pkg связанный с cli. А хочется подключить этот wait в свое приложение. Будь то helm или dapp. Понятно почему они так делают: не обобщают раньше времени. Но мы сделали библиотеку, потому что было видение сразу.


    4) Детали реализации.


    Kubedog использует informer-ы из библиотеки того же куба. Это примитив, который позволяет следить за ресурсами сутками, обрабатывает всякие низкоуровневые косяки. Например, натравил сейчас kubectl wait на древний ресурс, который у меня создан месяц назад, вылезла сразу такая ошибка:


    error: An error occurred while waiting for the condition to be satisfied: too old resource version: 847449 (1360240)

    Вот informer-ы эту ситуацию обрабатывают. Их обычно используют для написания всяких controller-ов.


    В общем это надежная такая обертка над низкоуровневым watch-ем. И за счет ее использования в kubedog нет вышеуказанной проблемы. Но это исправимо в kubectl, надо патч им предложить :).




    Обобщая. Если сделать kubectl apply + kubedog rollout track, то сразу из коробки получаем и логи, и event-ы, и ожидание до готовности, и прерывание по ошибкам.


    Честно, была идея попробовать в kubectl такие функции добавить. Это в идеале. Потому что тогда работа точно зря не пропадет. Но возможно чуть позже.

  • Сборка проектов с dapp. Часть 1: Java
    +1

    Кеш пакетов apt можно расшарить между билдами с помощью mount("/cached-dir") {from :build_dir}.
    Тут подробнее: https://flant.github.io/dapp/mount_for_advanced_build.html#%D0%BA%D1%8D%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D0%B1%D0%BE%D1%80%D0%BE%D1%87%D0%BD%D1%8B%D1%85-%D1%84%D0%B0%D0%B9%D0%BB%D0%BE%D0%B2-%D0%BC%D0%B5%D0%B6%D0%B4%D1%83-%D1%81%D0%B1%D0%BE%D1%80%D0%BA%D0%B0%D0%BC%D0%B8


    Указывать произвольную директорию нельзя, выбор только между временной директорией на каждую сборку и build-директорией, которая сохраняется между сборками. Build-директория создается в ~/.dapp/builds/<project-name> и содержит помимо mount'ов всякие кеши git'а, chef-cookbook'ов и т.п.

  • Наш опыт с Kubernetes в небольших проектах (обзор и видео доклада)
    0

    Ссылка изменилась: https://flant.github.io/dapp/secrets_for_kube.html

  • Наш опыт с Kubernetes в небольших проектах (обзор и видео доклада)
    +1

    Sensitive data кодируется симметричным ключом и попадает в repo. При выкате, если указана переменная окружения с ключом, то секретные данные становятся доступны. Эту переменную окружения можно указывать, например, как gitlab-secret-variable. Секретные значения — это либо файлы, либо helm values. Соответственно в yaml-шаблонах либо читается уже расшифрованный на момент запуска файл либо подставляется значение из values.
    Подробнее здесь: https://flant.github.io/dapp/secrets_for_deploy.html.

  • Наш опыт с Kubernetes в небольших проектах (обзор и видео доклада)
    0

    В плане самой фичи mount подойдет. Т.е. mount из host в minikube + mount из minikube в docker позволят пробросить директорию в контейнер из хост-системы. Но главная проблема не в этом, а в том, чтобы этот запущенный контейнер соответствовал тем инструкциям по сборке образа приложения, которые описываются в Dappfile. Например, при изменении Gemfile.lock надо сделать bundle install. Для этого в dapp предусмотрены стадии и для пересборки стадии можно поставить триггер на изменение файла Gemfile.lock. А в случае, если изменяется не Gemfile.lock, то при сборке новой версии происходит простое и быстрое наложение патча. Так вот, если поменялись какие-то файлы, от которых зависят инструкции по сборке каких-то стадий, то образ придется пересобрать и перезапустить контейнер приложения. Но если поменялись другие файлы приложения, то новый образ собирать не надо, если исходники уже примонтированы в запущенный контейнер.


    Однако сам minikube mount мы пробовали использовать для хранения файлов docker-registry на хост-системе, а не внутри minikube на виртуалке. Но производительность этой штуки для docker-registry неприемлема.

  • Наш опыт с Kubernetes в небольших проектах (обзор и видео доклада)
    +3

    По задумке dev-режима сборщика предполагается деплоить через helm в minikube. При этом описание helm-конфигурации для development-окружения, используемый namespace — на усмотрение пользователя.


    Есть команда dapp kube minikube setup, которая:


    • Стартует minikube
    • Поднимает в minikube docker-registry
    • Поднимает proxy в host-системе для использования docker-registry

    Предполагается такой сценарий использования:


    • Сборка образа в host-системе: dapp dimg build [--dev].
    • Загрузка образа в minikube docker-registry: dapp dimg push :minikube [--dev].
    • Запуск/обновление кластера: dapp kube deploy :minikube [--dev] [+ helm values options].

    Но для web-приложений в development-режиме (например) необходимы mount-ы исходников в запущенные образа, чтобы изменения исходников подхватывались уже запущенным web-сервером автоматом. Поддержки такого режима работы из коробки пока нет.