Мониторинг и логирование внешних сервисов в кластер Kubernetes

    image

    Доброго всем.

    Я не нашел в сети обобщенного руководства по логированию и сбору метрик со сторонних сервисов в системы развернутые в Kubernetes. Публикую свое решение. Данная статья подразумевает, что у вас уже имеется рабочий Prometheus и другие службы. В качестве примера источника данных внешнего stateful-сервиса будет использоваться СУБД PostgreSQL в контейнере Docker. В компании используется пакетный менеджер Helm, ниже по тексту будут примеры на нем. Для всего решения мы готовим собственный чарт, включающий в себя вложенные чарты всех используемых сервисов.

    Логирование


    Многие компании для сбора и просмотра и централизации логов используется стэк технологий Elasticsearch + Logstash + kibana, сокращённо ELK. В нашем случае нет необходимости индексировать контент и я применил более легковесный Loki. Он доступен в виде пакета Helm, мы добавили его как subchart изменив values для ingress и pv под нашу систему.

    values.yaml
    ingress:
      enabled: true
      annotations:
         kubernetes.io/ingress.class: nginx
      hosts:
        - host: kube-loki.example.domain
          paths: 
            - /
      tls: []
    
    ....
    
    persistence:
      type: pvc
      enabled: true
      accessModes:
        - ReadWriteOnce
      size: 100Gi
      finalizers:
        - kubernetes.io/pvc-protection
      existingClaim: "pv-loki"
    


    Для отправки логов на инстанс Loki используем Loki Docker Logging Driver.

    Необходимо установить это дополнение на все Docker хосты, с которых желаете получать логи. Есть несколько способов указать демону, как использовать дополнение. Я выбор драйвера произвожу в yaml Docker Compose, который является частью Ansible playbook.

    postgres.yaml
        - name: Run containers
          docker_compose:
            project_name: main-postgres
            definition:
              version: '3.7'
              services:
                p:
                  image: "{{ postgres_version }}"
                  container_name: postgresql
                  restart: always
                  volumes:
                    - "{{ postgres_dir }}/data:/var/lib/postgresql/data"
                    - "{{ postgres_dir }}/postgres_init_scripts:/docker-entrypoint-initdb.d"
                  environment:
                    POSTGRES_PASSWORD: {{ postgres_pass }}
                    POSTGRES_USER: {{ postgres_user }}
                  ports:
                    - "{{ postgres_ip }}:{{ postgres_port }}:5432"
                  logging:
                    driver: "loki"
                    options:
                      loki-url: "{{ loki_url }}"
                      loki-batch-size: "{{ loki_batch_size }}"
                      loki-retries: "{{ loki_retries }}"
    ...
    

    где loki_url: kube-loki.example.domain/loki/api/v1/push

    Метрики


    Собираются метрики с PostgreSQL с помощью postgres_exporter для Prometheus. Продолжение вышеуказанного файла Ansible playbook.

    postgres.yaml
    ...
                pexp:
                  image: "wrouesnel/postgres_exporter"
                  container_name: pexporter
                  restart: unless-stopped
                  environment:
                    DATA_SOURCE_NAME: "postgresql://{{ postgres_user }}:{{ postgres_pass }}@p:5432/postgres?sslmode=disable"
                  ports:
                    - "{{ postgres_ip }}:{{ postgres_exporter_port }}:9187"
                  logging:
                    driver: "json-file"
                    options:
                      max-size: "5m"
    ...
    


    Для большей наглядности имен внешних stateful-сервисов пропишем через Endpoints.

    postgres-service.yaml
    apiVersion: v1
    kind: Endpoints
    metadata:
      name: postgres-exporter
    subsets:
      - addresses:
          - ip: {{ .Values.service.postgres.ip }}
        ports:
          - port: {{ .Values.service.postgres.port }}
            protocol: TCP
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: postgres-exporter
      labels:
        chart:  "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
    spec:
      ports:
        - protocol: TCP
          port: {{ .Values.service.postgres.port }}
          targetPort: {{ .Values.service.postgres.port }}
    


    Настройка Prometheus для получения данных postgres_exporter производится правкой values в subchart.

    values.yaml
    scrape_configs:
    ...
      - job_name: postgres-exporter
        static_configs:
          - targets: 
             - postgres-exporter.applicationnamespace.svc.cluster.local:9187
            labels:
              alias: postgres
    ...
    


    Для визуализации полученных данных установите соответствующий Dashboard в
    Grafana и настройте источники данных. Это так же можно сделать через values в subchart Grafana.

    Как это выглядит


    Надеюсь, что эта краткая статья помогла вам понять основные идеи, заложенные в данном решении, и сохранит время при настройке мониторинга и логирования внешних сервисов для Loki/Prometheus в кластере Kubernetes.
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

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

      +1

      Я вообще не понял смысла этой статьи. С какой целью городился огород с Service/Endpoints? Постгрес разве нельзя затащить в прометеус как отдельный эндпойнт (по внешнему имени, короче) через правку scrape config? Прометеус как развернут — как говорится дьявол в деталях — а это очень существенно. Предполагаю, что через оператор? Но тогда зачем править скрейп конфиг? ServiceMonitor и вперед. Декларативненько.


      Ну, окей, затащили мы метрики внешнего сервиса во внутрикластерный прометеус. Что с алертами делаем? И еще вопрос отказоустойчивости самого прометеуса?

        +1
        Это не про смысл, это про «хоп, хоп — и в продакшн!» :-))))
          +1
          Вы не внимательно прочитали, в самом начале статьи я писал, что все ставиться через коммунити чарт. Давайте, попробую объяснить. Вы же не будете отрицать, что Kubernetes удел не только крупных корпораций. Многие компании меньших размеров, тоже не спешно переводят свои легаси приложения на эту платформу. У компаний может быть не только одно приложение, а несколько копий для разных заказчиков в различных неймспейсах. Postgres, Redis, Kafkа, etc могут быть у каждого свои, на выделенных серверах и доступны исключительно по IP адресу, без внешних имен или иметь не человеко-читаемые имена. Мой «огород с Service/Endpoints» как я и писал, как раз для большей наглядности в Grafana. Он позволяет задать удобно-читаемое имя. Надеюсь, вам стало более понятно, для чего это было сделано в моем случае. Отдельное спасибо за ServiceMonitor. Упустил, возможно, вы правы и можно зарефакторить.
            0

            Первую половину аргументации я понимаю. Вторая часть — не полностью согласен — как минимум — вся эта история с засовыванием внешних эндпойнтов в кластер раздувает его. Увеличивает размер етсд. Увеличивает количество правил файрволла (а service именно через них работают). И в какой-то момент вы выясняете, что кластер "тормозит" по неведомой причине.
            В результате вроде бы — пока действительно с одной стороны это удобно (мы унифицируем работу с ресурсами), а с другой — мы создаем себе какие-то потенциальные фантомные боли в будущем. И моя реакция связана с тем, что вроде бы да — мы нечто сделали, но не дошли до конца — коли уж так рассуждать — дальше ServiceMonitor, а еще дальше — вообще все засунуть в кубернетес и получить "плоский" пул сетевых ресурсов.


            Отдельное спасибо за ServiceMonitor. Упустил, возможно, вы правы и можно зарефакторить.

            да, посмотрите, пожалуйста.


            что все ставиться через коммунити чарт

            тоже объясню. Есть несколько разных чартов. Есть несколько разных способов установки. Мне лично нравится prometheus-operator. Кто-то же может ставит вообще stand-alone prometheus через helm, потому что хочет все крутить руками. Какого-то общего и стандартного способа установки нет, все-таки кубернетес — это конструктор. А от способа установки зависит то, как будешь настраивать прометеус....


            Postgres, Redis, Kafkа, etc могут быть у каждого свои, на выделенных серверах и доступны исключительно по IP адресу, без внешних имен или иметь не человеко-читаемые имена.

            а еще может быть… а еще могут инстансы, которые попилены между несколькими клиентами или проектами (разделяемые). Такой DBaaS в 0-й стадии развития. Еще интересный вопрос — удалось ли Вам завести Service не через IP, а через доменное имя (предполагаю, что нет).


            Вы же не будете отрицать, что Kubernetes удел не только крупных корпораций.

            это вообще холиварный вопрос. Потому что "кубернетес — это просто" и "кубернетес — это сложно" — оба утверждения будут справедливы. Но вероятнее всего, что маленькие вообще отдадут поддержку этой машинерии либо на аутсорсеров (типа Фланта, айти-суммы), либо возьмут кубер в облаке (где бОльшая часть проблем уже решена). А если самому готовить, то Вы абсолютно правы, что нужно иметь человеческий ресурс на поддержку/обслуживание этой платформы )

              0
              Теперь я вас не очень понимаю, что именно вы пытаетесь до меня донести? Есть реальная компания, в которой свои устои. В ней ни кто не хочет революций, эволюция всех устраивает. Выбрали эволюционировать в Kubernetes. Знаю ли я про DNS? Знаю.  В курсе ли я про Type ExternalName? В курсе и пробовал. Желает ли моя компания «поддержку … аутсорсеров»? Не могу знать! :)
              Мое решение вполне рабочее, вместо IP и абракадабр сотрудники моей компании в единой точке Grafana, видят осмысленные названия и логи при расследовании инцидентов.
              Я с вами полностью согласен, что «все-таки кубернетес — это конструктор». Отмечу, что это справедливо и для многих других продуктов, в том числе и для Prometheus.
              От себя, буду благодарен, если от вас получу URL на материалы, по которым вами сделаны выводы о увеличенном размере etcd, увеличенном количестве правил файрволла, приводящим к тому, что кластер «тормозит»  при описании внешних Service/Endpoint против описания, когда stateful-сервисы «все засунуты в кубернетес». Учиться и познавать новое ведь никогда не поздно.

              ЗЫ: Без обид.
              Сейчас же минусы статьи и некоторые комментарии, выглядят как попытка наказать музыканта, который исполнил произведение другого композитора. И который выбрал флейту и поле вместо органа и зала, за не имением последних. Но по мнению знатоков органной музыки исполнение полное …
                0
                ...
                Сейчас же минусы статьи и некоторые комментарии, выглядят как попытка наказать музыканта, который исполнил произведение другого композитора.

                я то тут причем? Думаете, специально нагнал минусующих — вот реально заняться нечем.


                по которым вами сделаны выводы о увеличенном размере etcd

                логика? Потому что с проблемами на маленьких кластерах вы и так и так не столкнетесь скорее всего, но действительно каждый объект типа Service создает пачку правил файрволла (если мы говорим о просто прописать внешний урл в scrape_config против завести внутреннее имя для внешнего сервиса) — это в самой доке кубернетеса написано и каких-либо дополнительных ссылок на это не требуется.

            0

            Вопрос без подвоха, правда интересно: А в чём проблема с алертами и отказоустойчивостью при таком подходе к прокидыванию внешних сервисов в прометеус внутри кластера? По вашему прометеус должен быть только вне кластера?


            Статья, вроде, не претендует на полноту раскрытия вопроса настройки прометеуса в продакшне.

              0
              А в чём проблема с алертами и отказоустойчивостью при таком подходе к прокидыванию внешних сервисов в прометеус внутри кластера?

              проблемы как таковой нет. Просто те же алерты мне, например, удобнее писать в PrometheusRule. Кому-то может удобнее конфигурацию как-то шаблонизировать.


              отказоустойчивостью при таком подходе к прокидыванию внешних сервисов в прометеус внутри кластера

              как минимум две реплики прометеуса, по понятным причинам, нужно


              по остальному см. также мой комментарий автору

            0
            Для отправки логов на инстанс Loki используем Loki Docker Logging Driver.

            еще очень интересный вопрос — у вас после установки этого плагина работает команда docker logs? Поясню — для наших dev/ops очень критично в удобном виде смотреть логи на удаленных серверах, если мало ли центральное хранилище сдохло/тормозит/etc., либо для отладки. Мне известно только два варианта получить работоспособную docker logs команду — либо штатный драйвер json-file (или journald драйвер), либо перекатываться на docker ee

              +1
              Да, логи по «docker logs» и в Grafana идентичны и вывод в консоле работает.
                0
                вывод в консоле работает

                попробую, тогда отпишусь )

                  +1

                  А можете пруф?
                  Не поймите неправильно, сам сейчас с этим борюсь. Настроил по статье — daemon.json натравил на Локи сервер. Так вот, doker logs пуст.
                  И с этим можно жить, когда уже пайплайны отработаны, но у меня есть тесты, на основе которых (allure) формируется ответ и стату джобы в дженкинсе.
                  Хочу поиграться с указанием драйвера не в конфиге докера, а в композ-файле. По типу, сервисы драйвер: Локи, тесты — дефолт

                    0
                    Я понял из документации, что через daemon.json настраивается логгирование по умолчанию для демона хоста. Мне это не нужно и поэтому указываю в Docker Compose только для конкретных приложений. Попробуйте вообще ничего не писать в daemon.json.
                      0

                      Все так )


                      Настроил по статье — daemon.json натравил на Локи сервер. Так вот, doker logs пуст.

                      я именно поэтому выразил сомнение в верности действия (установка плагина Loki + переключение на него), дал аргументы, почему это может быть плохо.
                      Кратко история такая:


                      1. есть daemon.json — в нем можно переопределить драйвер для логов для всех новых контейнеров по умолчанию
                      2. но тем не менее остается возможность при создании контейнера указать другое значение (будь то через docker run --log-driver ... или через docker-compose)
                      3. но использовать на одной машине разные драйвера — не очень удобно
                        +1

                        Немного проанализирова ситуацию, пришел к выводу, что Loki — отличный инструмент. Делает что нужно, довольно гибкий в настройках, легкий.
                        Для себя решил, что он — то с чего нужно начинать внедрять сборку логов (при условии использования Prometheus stack).


                        Касательно вариантов сборов логов:


                        1. Плагин + конфигурация в deamon.json шлет вывод docker logs напрямую на удаленный сервер, что ломает вывод данной команды.
                        2. Плагин + указание log-driver в docker-compose.yaml (или при запуске docker run), не решает проблему, просто позволяет отправлять только избранные логи контейнеров.
                        3. Promtail + считывание логов из директории /var/lib/docker/containers//log (можно посмотреть в статье от Badoo https://m.habr.com/ru/company/badoo/blog/507718/)

                        1 и 2й варианты, по сути равнозначны. Подходят для пробы, а также, когда уже вся сборка настроена, протестирована и повторяема (подход "Cattle")
                        3й вариант — позволит не ломать ручной метод работы с контейнерами (подход "Pet"), более того, есть возможность собирать логи не только из докера.


                        Сам скроняюсь к первому варианту, но пока что пытаюсь решить проблему с "пересечением" лейблов (т.к. у меня 2 проекта по 3 энва, и имена сервисов совпадают), нужно либо добавлять инструкцию в Композ файл, либо писать правила для Promtail

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

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