company_banner

Представляем k8s-image-availability-exporter для обнаружения пропавших образов в Kubernetes



    Рады представить свой новый Open Source-проект. На этот раз мы сделали совсем небольшую, казалось бы, утилиту, но столь полезную буквально для любой инсталляции Kubernetes. В чем же её суть? K8s-image-availability-exporter — это Prometheus exporter, позволяющий проактивно предупредить пользователя об образах, которые прописаны в объектах Kubernetes (например, поле image в Deployment), но отсутствуют в реестре контейнеров (Docker Registry и т.п.).

    Введение


    Kubernetes — крайне динамическая система. Оперируя инфраструктурой в K8s-кластере, мы предполагаем, что в любой момент времени pod’ы — да что там pod'ы: целые узлы! — могут быть удалены. Чтобы убедиться в этом, мы применяем различные подходы chaos engineering, в основном убивая случайные узлы Kubernetes с тем, чтобы увидеть, готовы ли клиентские приложения к пересозданию pod’ов.

    Для корректной работы приложения в таких динамических условиях Kubernetes надо соблюдать минимальные правила: создание PodDisruptionBudgets, деплой сразу нескольких реплик приложения, корректная конфигурация podAffinity, nodeAffinity и т.д.

    Однако, несмотря на такие очевидные политики, мы не всегда можем повлиять на их применение. Реальность же такова, что нам пришлось (и не один раз!) встретиться с проблемами, когда у клиента по какой-то причине приложение запущено в единственной реплике. Оно работает так месяцами и почти не деплоится. Его редкие выкаты проводятся без нашего участия и, конечно, без werf (эта утилита смогла бы сделать всё сама). В то же время реестр настроен на автоматическое удаление всех старых образов.И вот однажды, когда по какой-то причине потребуется пересоздать pod, случится непоправимое.

    Недавно — после того, как типовая операция перезаказа узла K8s привела к часовому простою, поскольку искали человека, который вообще сможет собрать приложение, — мы и решили написать k8s-image-availability-exporter. Идея утилиты — в автоматизации, позволяющей предотвратить последствия подобных ситуаций вне зависимости от соблюдения организационных политик и других «случайных» факторов.

    Реализация


    Общий алгоритм реализации сводится к следующему:

    • Запускаем 5 информеров. Таким образом, в памяти держится копия состояния всех следующих объектов кластера: Deployment, StatefulSet, DaemonSet, CronJobs и Secrets.
    • Все образы в PodTemplate’ах группируем и размещаем в очередь (priority queue).
    • Каждые 15 секунд (настраивается через опцию --check-period) достаём из очереди порцию наиболее долго не проверявшихся образов и смотрим их наличие в registry. Количество образов динамически варьируется так, чтобы за 10 минут проверить все возможные образы кластера.

      • Если в PodSpec присутствует imagePullSecrets, достаём нужные нам Secrets.
      • С полученными Secrets (если есть imagePullSecrets) или без них заходим в реестр образов (container registry) и проверяем, есть ли там нужный образ.

    В результате проделанной работы экспортируются следующие виды метрик (под ТИП подразумевается deployment, statefulset, daemonset и cronjob):

    • k8s_image_availability_exporter_ТИП_available — ненулевое значение говорит об успешной проверке образа;
    • k8s_image_availability_exporter_ТИП_bad_image_format — ненулевое значение указывает на некорректный формат поля image;
    • k8s_image_availability_exporter_ТИП_absent — ненулевое значение говорит об отсутствии манифеста образа в реестре контейнеров;
    • k8s_image_availability_exporter_ТИП_registry_unavailable — ненулевое значение показывает на общую недоступность реестра (возможно, из-за сетевых проблем);
    • k8s_image_availability_exporter_deployment_registry_v1_api_not_supported — ненулевое значение указывает на первую версию Docker Registry API (такие образы лучше игнорировать с помощью аргумента --ignored-images);
    • k8s_image_availability_exporter_ТИП_authentication_failure — ненулевое значение свидетельствует об ошибке аутентификации в реестре контейнеров (проверьте imagePullSecrets);
    • k8s_image_availability_exporter_ТИП_authentication_failure — ненулевое значение свидетельствует об ошибке авторизации в реестре контейнеров (проверьте imagePullSecrets);
    • k8s_image_availability_exporter_ТИП_unknown_error — ненулевое значение говорит об ошибке, не поддающейся встроенной классификации (получите дополнительную информацию в логах экспортера);
    • k8s_image_availability_exporter_completed_rechecks_total — инкрементируется в каждом цикле проверки наличия образов в реестре.

    Последний штрих — предусмотрен настраиваемый список образов, которые нужно игнорировать при этом мониторинге (--ignored-images).

    Код написан на Go, распространяется на условиях свободной лицензии Apache 2.0 и доступен на GitHub. Если есть предложения по его улучшению или замечания по использованию утилиты — будем рады!

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

    Как начать пользоваться?


    Достаточно трёх шагов:

    1. git clone https://github.com/flant/k8s-image-availability-exporter.git
    2. kubectl apply -f deploy/
    3. Настроить интеграцию с Prometheus: scraping и alerting rules.

    Подробнее (включая примеры готовых конфигураций для Prometheus) — см. в README.

    Итоги


    Теперь — с k8s-image-availability-exporter — мы получаем алерты о том, что у каких-либо из запущенных Kubernetes-контроллеров пропал(и) образ(ы) контейнеров в registry. Это позволяет решить проблему до того, как она себя проявит.

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

    P.S.


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

    Флант
    DevOps-as-a-Service, Kubernetes, обслуживание 24×7

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

      +2

      Идея хорошая.


      Каждые 15 секунд (настраивается через опцию --check-period) достаём из очереди порцию наиболее старых образов и проверяем их наличие в registry.

      не понял — что значит старых образов? Т.е. у утилиты какой-то внутренний кэш? Или имеется в виду — образы, из которых запущены самые старые подов-деплойментов?

        +2
        Возможно, стоит перефразировать. Самый старый timestamp последней проверки.
        Сейчас поправлю, спасибо!
        +1
          template:
            metadata:
              annotations:
                prometheus.io/port: "8080"
                prometheus.io/scrape: "true"
        


        Поправьте deployment, пожалуйста, и примеры. Если прометеус оператор установлен, он подхватит такой деплоймент. Если его нет — хуже не будет.
          +4

          https://github.com/coreos/kube-prometheus/pull/16#issuecomment-305953469


          The annotation is not supported by the operator. ServiceMonitors should be
          used instead.
          The annotation is very limited by its nature and there's no
          feasible way to support anything beyond "scrape on" and a single port. A
          per-service scrape interval, multi-port pods, authentication, honorLabels,
          and more are all not possible. It also provides no meaningful way to assign
          services to be scraped by different Prometheus instances.
          ServiceMonitors allow all these without exposing any complex relabelling
          and there's really no practical reason for sticking with the annotation.

          Представляется, что использование этой аннотации избыточно. Используйте соответствующие CRD. Если есть альтернативное мнение — давайте обсудим.

            0
            О как, не знал) Наш форк оператора просто поддерживает много чего, чего нет из коробки.

            Протестил вашу штуку — всё отлично. У нас правда свой аналог есть — который чистит лишнее по заданным правилам, ориентируясь по метрикам использования images от k8s api.
              +4
              gecube не у нас работает, но мы его знаем и уважаем, потому что он всегда читает и критикует наши статьи.
          +1

          А не проще сразу же манифесты для prometheus-operator положить в deploy/ или даже упаковать всё это в хелм-чарт ?

          +2
          git pull
          на git checkout поменяйте в статье
            +1

            git clone
            Поправил, спасибо.

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое