Prometheus + Loki + Grafana: отслеживаем состояния k8s и запущенных в нём приложении
Введение
Мониторинг состояния серверов и приложении является одной из основных задач DevOps-инженера. Логирование помогает обнаружить проблемы, возникающие в запущенных сервисах, а также понять что на самом деле случилось в случае возникновения проблем. Методы и инструменты для мониторинга выбираются исходя из сервера, на котором разворачиваются приложения. В этой статье я бы хотел описать процесс развертвывания системы мониторинга и логирования в Kubernetes, начиная с установки кубера на свой сервер и заканчивая импортом готового дашборда.
Что и где будем отслеживать
Не важно где и как вы развернули свой K8s кластер — PaaS решение от облачного провайдера, на ВМ или даже на своём собственном ПК. Для статьи я решил развернуть кубер на своем ноутбуке. Для этого я воспользуюсь k3s — «мини» kubernetes. Установить k3s легче простого — он состоит из одного файла размером 70 мегабайт.
Перед началом
Возможно, что Loki является не самым идеальным инструментом для сбора логов. Тут я имею ввиду ELK стек (Elasticsearch+Kibana+Logstash). Дело в том, что один только Elasticsearch у меня потреблял по 8Гб оперативной памяти, что является очень высоким значением. Помимо этого, были некоторые проблемы с установкой Docker образа Elasticsearch, связанного с моей локацией. Loki, скорее всего, менее гибок, чем стек ELK, но является оптимальным решением, если у вас ограниченный бюджет.
Для дальнейшей работы нам понадобятся следующие инструменты:
kubectl
helm
Установка k3s
Если у вас уже развернут Kubernetes, то вы можете смело пропустить этот шаг. И так, начнем! Для начала установим исполняемый файл и сразу же запустим его:
$ curl -sfL https://get.k3s.io | sh -s -
[INFO] Finding release for channel stable
[INFO] Using v1.27.6+k3s1 as release
...
[INFO] Installing k3s to /usr/local/bin/k3s
...
[INFO] systemd: Starting k3s
Проверим, что k3s запущен:
$ sudo systemctl status k3s
● k3s.service - Lightweight Kubernetes
Loaded: loaded (/etc/systemd/system/k3s.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2023-10-08 16:04:22 MSK; 3min 26s ago
Получим список всех узлов:
$ sudo k3s kubectl get nodes
NAME STATUS ROLES AGE VERSION
azamat-lenovo-ideapad-s145-15iil Ready control-plane,master 4m32s v1.27.6+k3s1
k3s разворачивает на текущем устройстве узел, который одновременно является и главным, и рабочим. В случае необходимости вы можете добавить дополнительные рабочие узлы. Нам хватит одного.
Развертывание необходимых компонентов
Установим следующие компоненты:
Prometheus — система мониторинга, в нашем случае используемый в качестве источника данных для Grafana для отслеживания состояния k8s кластера.
Grafana Loki — система для сбора, хранения и анализа логов. Также как и Prometheus, используется как источник данных для Grafana.
Grafana — система визуализации данных. С помощью графаны можно получать различные данные в удобном виде.
Все три системы можно установить с помощью одного Helm чарта. Helm позаботиться о том, чтобы развернуть все нужные компоненты и избавит вас от лишних хлопот по развертыванию всего по отдельности.
Добавим репозитории чартов grafana:
$ helm repo add grafana https://grafana.github.io/helm-charts
"grafana" has been added to your repositories
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "grafana" chart repository
Update Complete. ⎈Happy Helming!⎈
Установим чарт loki-stack. С помощью этого чарта вы можете развернуть всё что вам необходимо при работе с Grafana. Создадим файл values.yaml, где укажем Helm установить помимо Loki и Promtail также Grafana и Prometheus:
prometheus:
enabled: true
isDefault: false
url: http://{{ include "prometheus.fullname" .}}:{{ .Values.prometheus.server.service.servicePort }}{{ .Values.prometheus.server.prefixURL }}
datasource:
jsonData: "{}"
loki:
enabled: true
isDefault: true
url: http://{{(include "loki.serviceName" .)}}:{{ .Values.loki.service.port }}
readinessProbe:
httpGet:
path: /ready
port: http-metrics
initialDelaySeconds: 45
livenessProbe:
httpGet:
path: /ready
port: http-metrics
initialDelaySeconds: 45
datasource:
jsonData: "{}"
uid: ""
promtail:
enabled: true
config:
logLevel: info
serverPort: 3101
clients:
- url: http://{{ .Release.Name }}:3100/loki/api/v1/push
grafana:
enabled: true
sidecar:
datasources:
label: ""
labelValue: ""
enabled: true
maxLines: 1000
image:
tag: 10.0.2
Создадим отдельный namespace для всех ресурсов, касающихся мониторинга и установим чарт, указав файл values.yaml:
$ kubectl create namespace monitoring
$ helm install -n monitoring --values values.yaml loki-stack grafana/loki-stack
Убедимся, что все нужные Deployment были успешно развернуты:
$ kubectl -n monitoring get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
loki-stack-kube-state-metrics 1/1 1 1 21m
loki-stack-grafana 1/1 1 1 21m
loki-stack-prometheus-pushgateway 1/1 1 1 21m
loki-stack-prometheus-alertmanager 1/1 1 1 21m
loki-stack-prometheus-server 1/1 1 1 21m
Подключение источников данных (Data source)
Мы всё развернули, но теперь нам нужно зайти в Grafana. Но как? Помимо подов, Helm также создал ClusterIP сервисы:
kubectl -n monitoring get svc | grep grafana
loki-stack-grafana ClusterIP 10.43.184.63 80/TCP 81m
Если вы работаете в команде, то наилучшим решением будет создание балансировщика нагрузки с внутренним IP адресом с доступом только через VPN (открывать публично Grafana плохая идея). Но для нашей статьи создавать балансировщик нагрузки будет излишним, ведь можно использовать Port Forwarding, с помощью которого можно открыть доступ к сервису или поду. Для этого необходимо указать название ресурса, а также порты: порт для доступа по localhost и порт сервиса. Сервис loki-stack-grafana запущен на 80 порту. Откроем его на порту 8080:
$ kubectl -n monitoring port-forward svc/loki-stack-grafana 8080:80
Forwarding from 127.0.0.1:8080 -> 3000
Forwarding from [::1]:8080 -> 3000
Handling connection for 8080
Перейдем по адресу http://localhost:8080 и попадем на страницу логина
Юзернейм и пароль для входа хранятся в секрете в формате base64:
$ kubectl -n monitoring get secret | grep grafana
loki-stack-grafana Opaque 3 3h
$ kubectl -n monitoring get secret/loki-stack-grafana -o custom-columns="VALUE":.data.admin-user --no-headers | base64 --decode
admin
$ kubectl -n monitoring get secret/loki-stack-grafana -o custom-columns="VALUE":.data.admin-password --no-headers | base64 --decode
nijST2z6eKWhhtPibUJvLWQrAgGjmTkrDNBWigud
Введём полученные значения и успешно залогинимся. Нажмем на три полоски слева вверху и перейдем в раздел Administration (Data sources)
Перейдя в данный раздел, можно увидеть список всех источников данных. Как видно из снимка экрана, Loki и Prometheus уже подключены.
Просмотр метрик
Prometheus
Теперь рассмотрим некоторые метрики. Перейдем в раздел Explore
Тут можно обнаружить много разных форм и кнопок. Разберем основные:
Выбор источника данных. В нашем случае выборка между Loki или Prometheus
Метрика и её метки. Метрика это параметр какого-то ресурса, тогда как метки это фильтры, для которых отображать значение метрики. Помимо выбора метрик и меток через форму, есть возможность написания запроса через код (справа вместо Builder выбрать Code). Для этого используется отдельный язык запросов PromQL Также можно применять различные функции, нажав на Operations, такие как тригонометрические, агрегационные, временные и другие.
Легенда. Если на графике будет статистика о нескольких ресурсах, то вместо всех меток ресурса будет отображаться определенное значение.
Окно с данными. Тут появится график после нажатия Run query (6)
Временной промежуток. Можно задать в какой период времени просмотреть информацию
Запуск.
Чтобы лучше понять как использовать вкладку Explore, давайте попробуем узнать потребления оперативной памяти Deployment-ами в пространстве имён monitoring. Для этого выберем источник данных Prometheus (1), выберем метрику container_memory_usage_bytes для просмотра потребление оперативной памяти контейнерами и назначим метку namespace=monitoring (2). Воспользуемся PromQL, чтобы перевести байты в мегабайты (разделить на 1048576). В легенде укажем значение {{container}} (3), выберем временный диапазон «Last 5 minutes» (5) и запустим запрос (6):
Как видим на графике (5), Prometheus потребляет больше всего оперативной памяти. Давайте внимательно изучим окно с графиком. Вы можете менять вид отображения (линий / бары / точки). Помимо этого, вы можете нажать на значение из легенды, например на loki, и затем на графике выделить нужный временный диапазон:
Таким образом, вы можете в удобном для вас формате следить за состоянием приложении, а также гибко настраивать метрики и метки.
Loki
Теперь давайте узнаем как можно просматривать логи контейнеров. Перейдем снова в Explore, но изменим источник данных на Loki
В случае с Loki, у нас нет инпута для метрик, только метки. Это связано с тем, что Loki, в отличие от Prometheus, служит только лишь для сбора логов. Давайте посмотрим логи от самой loki за последние 30 минут, при этом воспользуемся некоторыми возможностями из Operations, а именно парсингом логов в формате logfmt и дальнейшей фильтровкой по уровню логированию:
В окне Logs volume можно увидеть количество поступивших логов в определенное время (определяется исходя из временного диапозона, на фото один бар — одна минута). Пролистаем ниже и заметим окно с самими логами. Тут мы можем удобно настроить их отображение, сортировать по новизне или скачать логи и затем послать их коллеге.
Дашборды
«С одним Explore-ом не уедешь». Explore удобен тем, что можно быстро изучить какую-то метрику, поковыряться в графике и затем в полном счастье закрыть графану. Но если вы планируете просматривать одни и те же графики чаще, чем один раз в жизни, то вам будут полезны дашборды. Это полезно также для коллег, которые не будут тратить своё время на настройку метрик и меток и сразу приступят к просмотру логов.
Вы можете создавать свои собственые дашборды или же импортировать существующий. Разобраться с тем как создать свой дашборд не так сложно, если вы прочитали эту статью и узнали как работать в Explore. Давайте импортируем готовый дашборд с информацией о потреблении ресурсов Kubernetes-ом.
Перейдем во вкладку Dashboards, нажмем на New и выберем Import.
Вы можете импортировать дашборд различными способами: загрузить JSON файл или ввести ID дашборда. Импортируем дашборд «Kubernetes / Views / Namespaces», уже на протяжении полугода я активно его использую для мониторинга кластера в dev и prod средах. Зайдя на сайт с дашбордом, справа вы можете увидеть окно с двумя кнопками.
Скопируем Dashboard ID и вернемся к Grafana. Вставим ID в поле, затем выберем Data source и нажмем Import:
После нажатия на кнопку вас должно перекинуть на импортированный дашборд. Тут вы можете увидеть множество графиков.
Вы можете увидеть общее потребление CPU и оперативной памяти, количество запущенных ресурсов, количество недоступных реплик и прочее. Сверху доступны четыре переменные, через которые можно выбрать источник данных и пространство имён. Вы можете не только просматривать графики, но также и изменять их. Кстати, вы можете даже перейти в Explore!
Выводы
Таким образом, мы при помощи одной команды (спасибо Helm) развернули весь необходимый стек для полноценного мониторинга K8s и сбора логов, рассмотрели возможности вкладки Explore и импортировали готовый дашборд.