м. Київ, вул. Кирилівська 102

11 серпня 2026 р.

Логування через Loki та Grafana

Логування через Loki та Grafana

Централізовані логи дають змогу бачити події всіх застосунків Kubernetes в одному місці, шукати помилки за namespace, pod або контейнером і швидко переходити від метрики до причини збою. Якщо метрики вже зібрані за попередньою інструкцією про моніторинг Kubernetes через Prometheus та Grafana, наступний логічний крок — додати Loki як сховище логів, Grafana Alloy як агент збору та Grafana як інтерфейс пошуку.

У цій інструкції розглянемо практичну схему для невеликого або середнього кластера: Loki працює в режимі Monolithic із постійним диском, Alloy читає stdout і stderr контейнерів, а Grafana підключається до Loki як datasource. Така конфігурація зрозуміла для першого запуску та не заважає надалі перейти до розподіленої архітектури.

Як працюють Loki, Alloy та Grafana

Loki часто порівнюють із Prometheus, але для логів. Він не створює повнотекстовий індекс для кожного рядка. Натомість Loki індексує набір міток, наприклад `cluster`, `namespace`, `pod`, `container` і `app`, а самі записи зберігає окремо. Через це система потребує менше ресурсів, якщо мітки спроєктовані правильно.

Grafana Alloy запускається в кластері, знаходить pod-и через Kubernetes API, читає їхні логи та надсилає записи до Loki. Grafana виконує запити мовою LogQL, будує таблиці й графіки та дозволяє пов'язувати логи з метриками на одному дашборді.

Для невеликої інсталяції достатньо одного Loki в режимі Monolithic. Усі його внутрішні компоненти працюють в одному процесі, тому конфігурацію простіше підтримувати. Для великого навантаження та високої доступності варто планувати Distributed-режим, кілька реплік і сумісне з S3 об'єктне сховище. Режим Simple Scalable більше не варто обирати для нової інсталяції.

Перед початком перевірте, що в кластері є StorageClass, DNS між namespace та встановлені `kubectl` і Helm. Для супроводу кластера, оновлень і спостережуваності також можна залучити послугу DevOps.

Встановлення Loki через Helm

Створіть окремий namespace та додайте репозиторій чартів. У робочому середовищі зафіксуйте перевірену версію чарта у змінній, щоб випадкове оновлення залежностей не змінило інсталяцію.

bash
kubectl create namespace logging

helm repo add grafana-community https://grafana-community.github.io/helm-charts
helm repo update
helm search repo grafana-community/loki --versions | head

export LOKI_CHART_VERSION="ВКАЖІТЬ_ПЕРЕВІРЕНУ_ВЕРСІЮ"
helm show values grafana-community/loki \
  --version "$LOKI_CHART_VERSION" > loki-default-values.yaml

Створіть файл `loki-values.yaml`. Приклад нижче використовує файлове сховище та одну репліку, тому підходить для навчального, тестового або невеликого внутрішнього кластера. Назву StorageClass і розмір диска змініть відповідно до своєї інфраструктури.

yaml
deploymentMode: Monolithic

loki:
  auth_enabled: false
  commonConfig:
    replication_factor: 1
  schemaConfig:
    configs:
      - from: "2024-04-01"
        store: tsdb
        object_store: filesystem
        schema: v13
        index:
          prefix: loki_index_
          period: 24h

monolithic:
  replicas: 1
  persistence:
    enabled: true
    storageClass: standard
    size: 30Gi

read:
  replicas: 0
backend:
  replicas: 0
write:
  replicas: 0

chunksCache:
  enabled: false
resultsCache:
  enabled: false

Встановіть реліз і дочекайтеся готовності pod-ів:

bash
helm upgrade --install loki grafana-community/loki \
  --namespace logging \
  --version "$LOKI_CHART_VERSION" \
  --values loki-values.yaml \
  --wait --timeout 10m

kubectl -n logging get pods,pvc,svc
kubectl -n logging logs statefulset/loki --tail=100

Не використовуйте тимчасовий диск для даних, які потрібно зберегти після перезапуску. Для production-кластера замініть filesystem на об'єктне сховище, увімкніть потрібну кількість реплік і перевірте резервування даних. `auth_enabled: false` допустимий лише тоді, коли Loki не відкритий у публічну мережу та доступ контролюється всередині кластера.

Збір логів Kubernetes через Grafana Alloy

Promtail довго був типовим агентом Loki, але для нової конфігурації доцільно використовувати Grafana Alloy. Він виконує discovery ресурсів Kubernetes, додає корисні мітки, обробляє записи й передає їх через HTTP endpoint Loki.

Нижче наведено базову конфігурацію Alloy. Вона знаходить pod-и, залишає низькокардинальні мітки та надсилає записи через сервіс gateway. Ім'я сервісу обов'язково звірте командою `kubectl -n logging get svc`.

alloy
discovery.kubernetes "pods" {
  role = "pod"
}

discovery.relabel "pod_logs" {
  targets = discovery.kubernetes.pods.targets

  rule {
    source_labels = ["__meta_kubernetes_namespace"]
    target_label  = "namespace"
  }
  rule {
    source_labels = ["__meta_kubernetes_pod_name"]
    target_label  = "pod"
  }
  rule {
    source_labels = ["__meta_kubernetes_pod_container_name"]
    target_label  = "container"
  }
  rule {
    source_labels = ["__meta_kubernetes_pod_label_app_kubernetes_io_name"]
    target_label  = "app"
  }
}

loki.source.kubernetes "pod_logs" {
  targets    = discovery.relabel.pod_logs.output
  forward_to = [loki.process.pod_logs.receiver]
}

loki.process "pod_logs" {
  stage.static_labels {
    values = { cluster = "main" }
  }
  forward_to = [loki.write.default.receiver]
}

loki.write "default" {
  endpoint {
    url = "http://loki-gateway.logging.svc.cluster.local/loki/api/v1/push"
  }
}

Збережіть її у `alloy-config.alloy`, підставте до values-файлу актуального Alloy chart і встановіть агент як DaemonSet. Спочатку перегляньте стандартні values саме зафіксованої версії: назви параметрів чартів можуть змінюватися.

bash
helm search repo grafana-community/alloy --versions | head
export ALLOY_CHART_VERSION="ВКАЖІТЬ_ПЕРЕВІРЕНУ_ВЕРСІЮ"
helm show values grafana-community/alloy \
  --version "$ALLOY_CHART_VERSION" > alloy-default-values.yaml

kubectl -n logging get pods -l app.kubernetes.io/name=alloy
kubectl -n logging logs daemonset/alloy --tail=100

Агенту потрібні RBAC-права на читання метаданих pod-ів, namespace і node. Офіційний chart створює необхідні ресурси, але власні обмежені ролі слід перевірити окремо. Не додавайте як мітки `request_id`, час, UUID користувача або інші майже унікальні значення: висока кардинальність різко збільшує індекс. Такі поля краще залишати в тексті JSON або structured metadata.

Підключення Loki до Grafana та запити LogQL

Якщо Grafana вже встановлена через kube-prometheus-stack, додайте Loki до її values як додаткове джерело даних. Внутрішній URL не потребує Ingress і залишається доступним лише з кластера.

yaml
grafana:
  additionalDataSources:
    - name: Loki
      type: loki
      access: proxy
      url: http://loki-gateway.logging.svc.cluster.local
      isDefault: false
      editable: false

Застосуйте той самий Helm release і той самий основний values-файл, які використовували під час початкової інсталяції Grafana. Не запускайте upgrade лише з коротким фрагментом вище, якщо інші параметри релізу не збережені: Helm може повернути їх до значень за замовчуванням.

У Grafana відкрийте Explore, виберіть datasource Loki та почніть із простого селектора:

logql
{cluster="main", namespace="production"}

Фільтр знаходить помилки без створення окремої мітки для рівня логування:

logql
{namespace="production", app="api"} | json | level="error"

Щоб порахувати кількість помилок за п'ять хвилин і згрупувати результат за pod, використайте metric query:

logql
sum by (pod) (
  count_over_time({namespace="production"} |= "error" [5m])
)

Спочатку звужуйте потік індексованими мітками, а потім застосовуйте текстові або JSON-фільтри. Це зменшує обсяг даних, який Loki має прочитати. Для регулярної діагностики збережіть запити в dashboard і додайте посилання з панелей Prometheus на відповідний часовий діапазон у Loki.

Retention, безпека та типові проблеми

До запуску визначте строк зберігання логів. Він залежить від доступного диска, швидкості надходження даних і вимог до аудиту. Контролюйте заповнення PVC, помилки запису, затримку ingestion та ресурси самого Loki. Зменшення retention не замінює моніторинг диска, а збільшення PVC не замінює політику очищення.

Якщо в Explore немає записів, перевіряйте шлях послідовно: Alloy знайшов pod-и, агент читає файли, endpoint доступний із його namespace, Loki приймає push, datasource відповідає. Корисні команди:

bash
kubectl -n logging get pods
kubectl -n logging logs daemonset/alloy --since=10m
kubectl -n logging logs statefulset/loki --since=10m
kubectl -n logging port-forward svc/loki-gateway 3100:80
curl -fsS http://127.0.0.1:3100/ready

Помилка `429` зазвичай означає перевищення лімітів або надто інтенсивний потік. `401` чи `403` вказують на автентифікацію, проксі або неправильний tenant. Тайм-аути часто пов'язані з DNS, NetworkPolicy чи невірною назвою сервісу. Якщо один запит споживає забагато ресурсів, звузьте часовий діапазон і селектор міток.

Не публікуйте gateway Loki без автентифікації. Доступ до Grafana захистіть ролями, TLS та окремими обліковими записами, а секрети маскуйте ще на етапі обробки в Alloy. Команда моніторингу сайтів і серверів допоможе налаштувати сповіщення, контроль ресурсів і регулярну перевірку всього контуру.

Що варто зробити після запуску

Після інсталяції переконайтеся, що логи надходять з усіх потрібних namespace, перезапуск pod-а не видаляє дані Loki, а збережені LogQL-запити швидко працюють на реальному часовому діапазоні. Додайте алерти на відсутність логів від критичного застосунку, помилки ingestion, заповнення сховища та недоступність datasource.

Почніть із невеликого набору стабільних міток, виміряйте фактичний потік і лише після цього змінюйте retention або масштабуйте компоненти. У результаті Grafana стане єдиною точкою для метрик і логів, а пошук причини інциденту скоротиться від ручного перегляду окремих pod-ів до одного точного запиту LogQL.

📞Логування через Loki та Grafana | ITheal