Рады анонсировать новую Open Source-разработку компании «Флант» для DevOps-специалистов и не только — kubedog. Это написанная на Go библиотека и CLI на её основе для отслеживания событий ресурсов Kubernetes и сбора их логов.


На данный момент библиотека поддерживает слежение за следующими ресурсами: Pod (и Container), Job, Deployment, StatefulSet и DaemonSet. События и логи передаются через callback’и.

CLI в kubedog имеет два режима работы:

  • rollout track — слежение за ресурсом до достижения состояния Ready и выход в случае ошибки для удобного использования в CI/CD;
  • follow — печать событий и логов на экран без выхода, аналогично tail -f.

Проблема


Зачем мы стали писать новую библиотеку, если подобные проекты уже существуют (см. «Работу с логами» в этом обзоре)? Kubedog используется в нашей DevOps-утилите dapp для слежения за ходом выката Helm-чартов. Сам Helm не умеет следить за состоянием ресурсов, которые он же добавляет, а передача логов не предусмотрена на уровне GRPC-взаимодействия между Helm и tiller. По этому поводу есть наш issue 3481, в рамках которого нами же было реализовано отслеживание добавленных ресурсов… Однако проект Helm сейчас неохотно добавляет новые функции в Helm 2, поскольку все силы сосредоточены на новой версии Helm 3. По этой причине мы решили выделить kubedog в отдельный проект.

Что же нужно от библиотеки слежения за ресурсами?

  • Получать логи Pod’ов, которые принадлежат ресурсу — например, Deployment’у.
  • Реагировать на изменение состава Pod’ов, которые принадлежат ресурсу: добавлять получение логов от новых Pod’ов, отключать логи из Pod’ов старых ReplicaSet’ов.
  • Слежение за Event’ами, в которых приходят расшифровки разных ошибок. Например, Pod не удаётся создать из-за неизвестного образа или Pod создан, но указанной в шаблоне команды нет в образе.
  • И ещё одно требование — отслеживание перехода ресурса из режима rollout в режим ready. И у каждого ресурса свои условия для этого.

Как легко догадаться, в kubedog мы постарались учесть всё вышеперечисленное.

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

Существующие решения


kubespy


> GitHub

  • Умеет следить только за Deployment и Service, реагирует на новые Pod’ы.
  • Есть режим слежения за описанием ресурса и его статусом и вывод изменений в виде json diff.
  • Есть цветное табличное представление изменений, где видно статус ReplicaSet’ов и conditions.
  • Не показывает логи Pod’ов.
  • Написан на Go, но в качестве библиотеки применить нельзя.

kubetail


> GitHub

  • Bash-скрипт, который вызывает kubectl.
  • Умеет показывать логи существующих Pod’ов.
  • Новые Pod’ы не обнаруживает, если происходит выкат, то kubetail нужно перезапускать.

stern


> GitHub

  • Показывает логи Pod’ов, отфильтрованных по pod-query.
  • Обнаруживает новые Pod’ы.
  • Строки логов раскрашиваются для лучшего восприятия.
  • Показывает события добавления и удаления Pod’ов с именами контейнеров в них.
  • Не следит за Events, поэтому не показывает причину ошибок Pod’ов.
  • Написан на Go, но в качестве библиотеки использовать не получится.

kail


> GitHub

  • Умеет показывать логи одновременно из разных пространств имён по разным ресурсам .
  • Не следит за Events, не показывает причины ошибок, например, для Deployment.
  • Не раскрашивает логи Pod’ов.
  • Написан на Go, но в качестве библиотеки использовать не получится.

k8stail


> GitHub

  • Выборка Pod’ов по namespace и лейблам.
  • Следит за появлением новых, за удалением.
  • Не следит за Events, не покажет ошибки.
  • На Go, но не библиотека.

kubedog


> GitHub

  • CLI работает в двух режимах: бесконечное слежение и слежение до перехода ресурса в статус READY.
  • Следит за одним ресурсом.
  • Реагирует на изменения ресурса, подписывается на логи новых Pod’ов.
  • Умеет следить за Deployment, StatefulSet, DaemonSet, Job или отдельным Pod’ом.
  • Написан на Go, можно использовать как библиотеку для добавления в свою программу слежения за статусом ресурсов и получения логов от контейнеров.

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

Итак, kubedog!


Суть работы kubedog в следующем: для указанного ресурса запустить Watcher’ы на Event’ы и на Pod’ы, принадлежащие ресурсу, а при появлении Pod’а запустить сборщик его логов. Всё, что происходит с ресурсом, транслируется клиенту с помощью вызова callback’ов.

Рассмотрим на примере DaemonSet, что доступно для кода, использующего библиотеку. Интерфейс callback’ов для Deployment, StatefulSet и DaemonSet одинаков* — это ControllerFeed:

type ControllerFeed interface {
    Added(ready bool) error
    Ready() error
    Failed(reason string) error
    EventMsg(msg string) error
    AddedReplicaSet(ReplicaSet) error
    AddedPod(ReplicaSetPod) error
    PodLogChunk(*ReplicaSetPodLogChunk) error
    PodError(ReplicaSetPodError) error
}

* Исключение составляет AddedReplicaSet, который имеет смысл только для Deployment (для слежения за DaemonsSet можно не определять этот метод).

Пояснения к другим методам интерфейса:

  • Added соответствует событию watch.Added наблюдателя за выбранным ресурсом;
  • Ready вызывается, когда ресурс перешёл в состояние Ready (например, для DaemonSet это момент, когда количество обновлённых и доступных Pod’ов совпало с «желаемым» количеством Pod’ов);
  • Failed — этот метод вызывается в случае удаления ресурса или в случае получения Event’а с причиной и описанием ошибки (например, FailedCreate);
  • EventMsg вызывается для каждого полученного Event’а от ресурса или его Pod’ов: это события о создании ресурса, о закачке образа и т.д. В том числе и сообщения об ошибке;
  • AddedPod — метод, которым можно ловить моменты создания новых Pod’ов;
  • PodLogChunk вызывается, когда от Kubernetes API приходит очередной кусок логов;
  • PodError будет вызван в случае ошибки Pod’а.

Каждый callback может вернуть ошибку типа StopTrack и слежение будет завершено. Так, например, сделано в rollout tracker — Ready возвращает StopTrack и CLI завершает свою работу.

Для облегчения определения callback’ов есть структура ControllerFeedProto, при создании объекта которой можно определить нужный callback метод.

Вот так, например, будет выглядеть бесконечный вывод логов DaemonSet’а без дополнительной информации о событиях и состоянии:

// kubedog может подключаться как снаружи Kubernetes'а, так и внутри
// см. https://github.com/flant/kubedog/blob/master/pkg/kube/kube.go
kubeClient, err := kubernetes.NewForConfig(config)
if err != nil {
  return err
}

feed := &tracker.ControllerFeedProto{
  PodLogChunkFunc: func(chunk *tracker.ReplicaSetPodLogChunk) error {
    for _, line := range chunk.LogLines {
     fmt.Printf(">> po/%s %s: %s\n", chunk.PodName, chunk.ContainerName, line)
    }
    return nil
  },
}

// Опциями можно задать timeout ответа от API сервера и время, начиная с которого показывать логи. Если время пусто, то логи будут выведены все, начиная от старта Pod'а.
opts := tracker.Options{
  Timeout:      time.Second * time.Duration(300),
  LogsFromTime: time.Now(),
}

tracker.TrackDaemonSet(dsName, dsNamespace, kubeClient, feed, opts)

Последний вызов — блокирующий: он запускает бесконечный цикл получения событий от Kubernetes и вызов соответствующих callback’ов. Программно прервать этот цикл можно с помощью возврата StopTrack из callback’а.

Примеры применения


Применение kubedog в качестве библиотеки можно увидеть в утилите dapp. Здесь запускаются готовые rollout Tracker’ы для проверки ресурсов, которые создаёт или обновляет Helm.

Kubedog CLI способен помочь с выкатом в системе CI/CD, причём вне зависимости от того, что используется: kubectl, Helm или что-то другое. Ведь можно запустить kubectl apply, а следом — kubedog rollout track, и в логах выката будет видно ошибку, если с ресурсом что-то не то. Такое применение kubedog поможет сократить время на диагностику проблем с выкатом.

Что дальше?


В наших планах развивать библиотеку в сторону поддержки большего количества ресурсов — например, очень хочется следить за Service и Ingress. Помимо этого предполагается провести работу по классификации reason в Event’ах, чтобы точнее определять момент, когда можно считать, что выкат ресурса не удался. Ещё один вектор развития библиотеки — слежение за несколькими ресурсами сразу, например, по labelSelector или по имени namespace. Также хочется поддерживать разные аннотации, которые могут изменять характер слежения, например, за хукам Helm’а, но это пока больше актуально для dapp.

В ближайшем будущем фокус будет именно на библиотеке, но и для CLI планируются улучшения: более удобные команды и флаги, раскраска логов, сообщения про удаление Pod’ов, как в stern. Также мы рассматриваем возможность создания интерактивного режима с таблицей состояния Deployment и событиями в одном окне и с логами — в другом.

Как попробовать?


Сборки kubedog CLI под Linux и macOS доступны на bintray.

Очень ждём ваших отзывов и issues в GitHub!

P.S.


Читайте также в нашем блоге:

Комментарии (5)


  1. m1kola
    24.12.2018 23:11
    +1

    Как библиотека — выглядит хорошо с первого взгляда: обертка с простым и понятный интерфейсом (проще чем использовать client-go). Как CLI — мне кажется, вы повторяете то что уже есть в kubectl. Поправьте меня, если я ошибаюсь, но:


    • Для слежения за состоянием можно использовать kubectl wait
    • Для слежение за логами в стиле tail -f есть флаг -f/--follow в kubectl logs
    • kubectl apply + kubedog rollout track, выглядит как тоже самое что kubectl apply --wait=true

    Подумайте над тем чтобы предложить свою помощь в улучшении kubectl ребятам из sig-cli ;)


    1. tkir
      25.12.2018 01:00
      +1

      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 такие функции добавить. Это в идеале. Потому что тогда работа точно зря не пропадет. Но возможно чуть позже.


      1. m1kola
        25.12.2018 02:37
        +1

        Спасибо. Это пояснение отлично дополняет статью.


        Kubectl wait на данный момент это pkg связанный с cli. А хочется подключить этот wait в свое приложение.

        Кстати, несколько месяцев назад (после разбивки kubectl команд на пакеты) на одном из sig-cli митингов обсуждалось нужно ли делать пакеты вроде экспортируемыми или нет. Вроде как пришли к тому что некоторые пакеты будут "повышаться" в общий пакет (на подобии cli-runtime), но конкретных планов по реализации этого я не видел.


        1. diafour Автор
          25.12.2018 09:13

          Ещё вариант оформить kubedog плагином к kubectl — это какая-то прям элементарная вещь из разряда переименовать бинарь.


  1. eps
    25.12.2018 10:43
    +1

    Kubedog

    image