Останній раз працював з Loki коли вона була ще в Beta, і виглядала вона тоді набагато простіше, ніж зараз.
У новому проекті системи логування немає взагалі, а так як у нас усі люблять Grafana-стек – то вирішили і для логів підняти Loki.
Правда мені думалося, що все буде набагато простіше. Виявилося – ні. Багато змінилося, і довелося знайомитися з нею по суті з нуля.
Що залишилося, як і раніше, – це така собі документація. Якщо опис архітектури та компонентів ще більш-менш нормально описаний, то коли справа доходить до налаштування – то натикаєшся на купу проблем, особливо те, що стосується сторейджа та зберігання в AWS S3 (хоча поки писав цей пост викотили реліз 2.7, і документацію теж оновили – можливо, тепер вона краща). Довелося збирати по шматочках, але в результаті все-таки завелося.
Розглянемо загальну архітектуру та компоненти, потім встановимо в AWS Kubernetes із Helm-чарта.
Зміст
Архітектура Grafana Loki
Loki створена за мікросервісною архітектурою, при цьому всі мікросервіси зібрані в один бінарник.
Для запуску компонентів використовується опція --target
, в якій можна визначити яку частину Loki запустити.
Вхідні дані діляться на стріми – це потік даних, логів, що мають загальний tenant_id
(“відправник”), і загальний набір тегів/labels. Докладніше про стріми поговоримо в Storage.
Компоненти Loki
Робота системи ділиться на два основні потоки: Read path – читання (обробка запитів на вибірку даних) та Write path – запис цих даних в сторейдж.
Загальна схема всіх компонентів:
Тут:
- distributor (write path): займається обробкою вхідних даних від клієнтів – одержує від них дані, валідує їх, ділить дані на блоки, і відправляє в ingester. Бажано мати LoadBalancer перед дистриб’юторами, щоб вхідні стріми розподілялися по інстансах дистриб’юторів. Є stateless компонентом – не зберігає в собі жодних даних. Також відповідає за рейт-ліміти та препроцесинг тегів.
- ingester (write, read path): відповідає за запис даних у довгострокове сховище та за передачу даних для обробки запитів на їх читання клієнтами. Для запобігання втратам даних у разі рестарту інжестера, їх зазвичай запускають у вигляді декількох інстансів (див.
replication_factor
) - querier (read path): обробляє LogQL запити, завантажуючи для відповіді дані з інжестерів та/або довгострокового сховища – спочатку запитує інжестер, якщо в пам’яті інжестера даних немає – то querier йде в сховище даних
- query frontend (read path): опціональний сервіс, що надає доступ до querier API для прискорення операцій читання. При його використанні він зберігає запити, що надходять, а querier звертається до нього, щоб взяти з черги запит на обробку
Крім того, Loki має додаткові компоненти:
- ruler: управління алертами (див. Grafana Loki: алерты з Ruler та labels з логів)
- compactor: зменшення розміру індексів та управління часом зберіганням логів у сховищі даних (retention)
Data flow
Коротко про сам процес обробки даних – запити читання (read), і запис (write).
- Loki отримує дані з promtail (або інших агентів, наприклад fluentd)
- створює блоки даних (chunks), індекс, завантажує їх у довгострокове сховище
- користувач використовує LogQL для вибірки логів у Grafana
- ruler перевіряє данні, і при необхідності відправляє алерт у Prometheus Alertmanager
Read Path
При отриманні запиту на вибірку даних:
- querier отримує HTTP запит
- передає запит до ingesters для пошуку даних в пам’яті
- якщо ingesters знаходитт дані у себе – то повертає їх querier
- якщо в ingesters даних нема – querier йде в сховище даних, і отримує їх звідти
- querier повертає відповідь через теж HTTP-з’єднання
Write Path
При отриманні нових даних:
- distributor отримує HTTP/1 запрос на додавання даних в конкретний стрім
- distributor передає кожний стрім в ingester
- ingester створює новий chunk (“блок даних”, див. Loki Storage) або доповнює існуючий
- distributor відповідає ОК на HTTP/1 запит
Режими запуску
Запускати Loki можна в трьох режимах, кожен з яких визначає, як будуть запущені компоненти – у вигляді одного або декількох подів Kubernetes.
Monolithic mode
Дефолтний тип при використанні локальної filesystem
для зберігання даних.
Підходить для швидкого запуску та невеликих об’ємів даних, до 100GB на день
Балансування запитів виконується по round robin.
Паралелізація запитів обмежена кількістю інстансів та налаштуванням кожної інстансу.
Основне обмеження – не можна використовувати object store, такі як AWS S3.
Simple scalable deployment mode
Дефолтний тип під час використання object store.
Якщо у вас логів більше кількох сотень гігабайт, але менше кількох терабайт на день, або ви хочете ізолювати читання та запис, то можна задеплоїти Loki в режимі simple scalable deployment:
У такому режимі Loki запускається з двома таргетами – read & write.
Потребує наявності лоад-балансера, який буде роутити запити до інстансів з компонентами Loki.
Microservices mode
І для найскладніших випадків, коли у вас логи йдуть терабайтами на день, має сенс деплоїти кожен сервіс окремо:
- ingester
- distributor
- query-frontend
- query-scheduler
- querier
- index-gateway
- ruler
- compactor
Дозволяє моніторити та скейлити кожен компонент незалежно.
Grafana Loki Storage
Див. документацию Grafana Loki Storage.
Loki для зберігання логів використовує два типи даних – chunks та індекси. Не придумав корректного перекладу для chunk, тому нехай буде “блок даних”.
Loki отримує дані від кількох стримів, де кожен стрім – це tenant_id
та набір тегів. При отриманні нових записів від стриму вони упаковуються в блоки і відправляються в довгострокове сховище, в ролі якого можуть бути AWS S3, локальна файлова система, або бази даних типу AWS DynamoDB чи Apache Cassandra.
В індексах зберігається інформація про набір тегів кожного стриму і є посилання на пов’язані з цим стримом блоки даних.
Раніше Loki використовувала два окремі сховища – одне під індекси (наприклад, таблиці DynamoDB), і друге – безпосередньо під самі дані (AWS S3).
Десь з версії 2.0 у Loki з’явилася можливість зберігати індекси у вигляді BotlDB файлів та використовувати Single Store – єдине сховище і для блоків даних, і для індексів. Див. Single Store Loki (boltdb-shipper index type).
Ми будемо використовувати boltdb-shipper
– він буде формувати індекси локально, а потім пушити їх у shared object store. Там же будуть зберігатися і самі chunks.
В Loki 2.7 з’явився ще один новий спосіб зберігання індексів – у вигляді TSDB-файлів, див. Grafana Loki 2.7 release: TSDB index, Promtail enhancements, and more.
Loki streams, labels та збереження даних
Важливий момент, який необхідно враховувати під час роботи з тегами в Loki це те, як формуються індекси та блоки даних: кожен окремий набір тегів формує окремий стрім, а для кожного окремого стріму формуються свої індекси та блоки даних.
Тобто, якщо ви динамічно створюєте теги/лейбли, наприклад client_ip
– то у вас буде формуватися окремий набір файлів на кожен клієнтський IP, що призведе до того, що на кожен такий файл будуть виконуватися окремі запити GET/POST/DELETE, що може привести по-перше до зростання вартості сховища (як у випадку з AWS S3, де оплачується кожен виклик), так і до проблем з швидкістю обробки запитів.
Див. Labels і чудовий пост Grafana Loki and what can go wrong with label cardinality.
Loki Helm charts
Окрім документації у Loki ще й із чартами трохи складнощів, оскільки переносили між репозиторіями, об’єднували, і тепер деякі стали deprecated (хоча посилання на них у документації зустрічаються).
Нижче – не про установку, а просто деякі особливості чартів Loki, з якими довелося повозитися.
Отже – є Хельм-репозиторій Графани – https://grafana.github.io/helm-charts, додаємо його:
[simterm]
$ helm repo add grafana https://grafana.github.io/helm-charts
[/simterm]
Якщо перейти до нього у браузері, то там буде навіть посилання на документацію:
Chart documentation is available in grafana directory.
Переходимо за посиланням, і потрапляємо до git-репозиторію, в якому є пачка чартів:
loki-canary
– актуальнийloki-distributed
– актуальнийloki-simple-scalable
– deprecated, перенесений у https://github.com/grafana/loki/tree/main/production/helm/lokiloki-stack
– актуальнийloki
– deprecated, перенесений у https://github.com/grafana/loki/tree/main/production/helm/loki
Вони ж є при пошуку Хелмом:
[simterm]
$ helm search repo grafana loki NAME CHART VERSION APP VERSION DESCRIPTION bitnami/grafana-loki 2.5.0 2.7.0 Grafana Loki is a horizontally scalable, highly... grafana/loki 3.3.4 2.6.1 Helm chart for Grafana Loki in simple, scalable... grafana/loki-canary 0.10.0 2.6.1 Helm chart for Grafana Loki Canary grafana/loki-distributed 0.65.0 2.6.1 Helm chart for Grafana Loki in microservices mode grafana/loki-simple-scalable 1.8.11 2.6.1 Helm chart for Grafana Loki in simple, scalable...
[/simterm]
Може, залишили для сумісності, окей, але геморою з установкою це додає.
Можна завантажити та розпакувати локально, щоб подивитися, що там є:
[simterm]
$ helm pull grafana/loki --untar
[/simterm]
Дефолтні values – тут>>>.
Helm chart та Deployment Mode
Ще один момент, який трохи поламав мозок: окей, ми бачили, що Loki можна запустити з різними Deployment modes – але як це визначити у чарті? Якогось values типу -target
там немає.
Нижче – трохи копання в чарті, можна пропустити, якщо вам підходить дефолтна установка.
Отже, якщо встановити з дефолтними values, то отримуємо наступні компоненти:
[simterm]
$ helm install loki grafana/loki ... Installed components: * grafana-agent-operator * gateway * read * write
[/simterm]
Та поди:
[simterm]
$ kk get pod NAME READY STATUS RESTARTS AGE loki-canary-7vrj2 0/1 ContainerCreating 0 12s loki-gateway-5868b68c68-lwtfj 0/1 ContainerCreating 0 12s loki-grafana-agent-operator-684b478b77-zmw5t 1/1 Running 0 12s loki-logs-kwxcx 0/2 ContainerCreating 0 3s loki-read-0 0/1 ContainerCreating 0 12s loki-read-1 0/1 Pending 0 12s loki-read-2 0/1 Pending 0 12s loki-write-0 0/1 ContainerCreating 0 12s loki-write-1 0/1 Pending 0 12s loki-write-2 0/1 Pending 0 12s
[/simterm]
Тобто, по дефолту воно встановлюється в simple-scalable, при цьому в документації самих чартів про це нічого не сказано, як ні слова про те, як задати деплоймент-режим взагалі.
А якщо я хочу Single Binary?
Зносимо:
[simterm]
$ helm uninstall loki release "loki" uninstalled
[/simterm]
Спробуємо повірити документації, і створюємо свої values:
loki: commonConfig: replication_factor: 1 storage: type: 'filesystem'
Встановлюємо:
[simterm]
$ helm upgrade --install --values values-local.yaml loki grafana/loki ... Installed components: * grafana-agent-operator * loki
[/simterm]
What?
Тобто, тупо перевизначивши сторейдж – ми змінюємо режим деплойменту?!?
Ах#*$ть – дайте два!
Як воно працює?
Відкриваємо файл templates/_helpers.tpl
, в якому є два шаблони – loki.deployment.isScalable
і loki.deployment.isSingleBinary
, в яких одна і та ж умова, тільки з різними значеннями:
... {{- eq (include "loki.isUsingObjectStorage" . ) "false" }} ...
Якщо true – то це isScalable
, а якщо false – то isSingleBinary
.
Окей, а що за isUsingObjectStorage
?
Знаходимо його в тому же хелпері:
... {{/* Determine if deployment is using object storage */}} {{- define "loki.isUsingObjectStorage" -}} {{- or (eq .Values.loki.storage.type "gcs") (eq .Values.loki.storage.type "s3") (eq .Values.loki.storage.type "azure") -}} {{- end -}} ...
Тобто, якщо ми використовуємо .Values.loki.storage.type
із значенням gcs
, s3
або azure
– то loki.isUsingObjectStorage
прийме значення true
, і Loki буде встановлено в режимі Simple Scale.
Зовсім не очевидно і не описано в документації до чарту.
Запуск Grafana Loki
А тепер, нарешті, перейдемо до запуску і налаштування Loki.
Для зберігання даних будемо використовувати AWS S3, для роботи з індексами – bottledb-shipper
, для налаштування терміну зберігання логів – compactor
.
Аутентифікацію Loki реалізуємо через підключення ServiceAccount із AWS IAM Role, але покажу приклад і зі звичайними ACCESS/SECRET keys.
Створення AWS S3 корзини
Почнемо зі створення корзини. Можна через AWS CLI та create-bucket
, або через Terraform:
resource "aws_s3_bucket" "loki_object_store" { bucket = "${var.client}-${var.environment}-loki-object-store" tags = { Name = "Grafana Loki Object Store" environment = var.environment service = var.service } }
Зараз для простоти створимо через AWS Console:
Запам’ятовуємо регіон, тут це us-west-2:
AWS IAM Role && Policy
Для корзини буде потрібна політика, яка дозволяє до неї доступ, і роль, яку потім підключимо до Kubernetes Pod.
Повертаючись до проблем документації Loki – на сторінці Grafana Loki Storage є приклад політики для AWS S3, яка… не проходить валідацію в AWS IAM :faceplam:
Взагалі часто виникали асоціації з Miscrosoft Azure – там документації теж вірити не можна від слова зовсім, і все треба перевіряти і збирати по шматочках.
Використовуючи ServiceAccount
Докладно ServiceAccount та IAM описував у Kubernetes: ServiceAccount з AWS IAM Role для Kubernetes Pod, тут швиденько.
Переходимо в AWS Console > IAM > Policies, створюємо Policy:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:PutObject", "s3:GetObject", "s3:DeleteObject" ], "Resource": [ "arn:aws:s3:::test-loki-0", "arn:aws:s3:::test-loki-0/*" ] } ] }
Переходимо в EKS, знаходимо OpenID Connect provider URL:
Переходимо в IAM > Identity providers, за ID 537***A10 знаходимо OIDC ARN:
Переходимо в Roles, створюємо роль: вибираємо тип Web identity, зі списку вибираємо наш Identity provider, в Audience вказуємо sts.amazon.com:
Підключаємо створену раніше політику:
Отримуємо Trusted Policy, зберігаємо нову роль:
Зберігаємо ARN ролі – використуємо його далі в параметрах Loki:
Використовуючи AWS Access и Secret Keys
Інший варіант – замість IAM ролі та ServiceAccount використовувати опції access_key_id
та secret_access_key
, див. s3-expanded-config.yaml:
... storage_config: aws: bucketnames: bucket_name1, bucket_name2 endpoint: s3.endpoint.com region: s3_region access_key_id: s3_access_key_id secret_access_key: s3_secret_access_key insecure: false ...
Це трохи простіше, ніж ServiceAccount, питання тільки в тому, як зберігати та передавати секрети з ключем.
Для приклада створимо через AWS Console звичайного користувача, якому підключимо політику.
Переходимо в IAM > Roles, створюємо Policy:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:PutObject", "s3:GetObject", "s3:DeleteObject" ], "Resource": [ "arn:aws:s3:::test-loki-0", "arn:aws:s3:::test-loki-0/*" ] } ] }
Створюємо користувача з Programmatic access:
Підключаємо йому цю політику:
Зберігаємо ключі:
Переходимо до конфігу Loki – тут теж вистачило болю та страждань із документацією та чартом.
Запуск Grafana Loki в Kubernetes
Ну і тепер, коли мені стало ясно і з чартами, і з тим, як же через Helm-чарт Loki задати Deployment Mode, і взагалі який чарт використовувати – спробуємо її запустити.
Готуємо мінімальний конфіг, в якому для початку відключимо весь її внутрішній моніторинг щоб зменшити кількість подів – буде простіше розбиратися з тим, як воно працює, і для початку використовуємо сховище filesystem
, щоб зберігати дані та індекси локально в подах:
loki: auth_enabled: false commonConfig: path_prefix: "/var/loki" replication_factor: 1 storage: type: "filesystem" schema_config: configs: - from: 2022-12-12 store: boltdb object_store: filesystem schema: v12 index: prefix: index_ period: 168h storage_config: boltdb: directory: /var/loki/index filesystem: directory: /var/loki/chunks test: enabled: false monitoring: dashboards: enabled: false rules: enabled: false alerts: enabled: false serviceMonitor: enabled: false selfMonitoring: enabled: false lokiCanary: enabled: false grafanaAgent: installOperator: false
Деплоїмо в неймспейс test-loki-0
:
[simterm]
$ helm upgrade --install --namespace test-loki-0 --create-namespace --values loki-minimal-values.yaml loki grafana/loki ... Installed components: * loki
[/simterm]
Перевіряємо под:
[simterm]
$ kk -n test-loki-0 get pod NAME READY STATUS RESTARTS AGE loki-0 1/1 Running 0 118s
[/simterm]
Окей – є один под, нічого зайвого.
Чарт створює StatefulSet, в якому описується створення цього поду і через який підключаються різні volumes:
[simterm]
$ kk -n test-loki-0 get sts NAME READY AGE loki 1/1 3m
[/simterm]
І ConfigMap, в якій зберігається конфіг, доповнений нашим loki-minimal-values.yaml
:
[simterm]
$ kk -n test-loki-0 get cm loki -o yaml apiVersion: v1 data: config.yaml: | auth_enabled: false common: path_prefix: /var/loki replication_factor: 1 storage: filesystem: chunks_directory: /var/loki/chunks rules_directory: /var/loki/rules ...
[/simterm]
Grafana Loki S3 config
Дуже багато віддав би, щоб десь знайти повний конфіг для Grafana Loki з AWS S3 як у прикладі нижче, та ще й з авторизацією через ServiceAccount і AWS IAM – витратив багато часу, щоб змусити все це працювати.
Власне, сам конфіг, потім трохи про опції та підводні камені, з якими зіткнувся:
loki: auth_enabled: false commonConfig: path_prefix: /var/loki replication_factor: 1 storage: bucketNames: chunks: test-loki-0 type: s3 schema_config: configs: - from: "2022-01-11" index: period: 24h prefix: loki_index_ store: boltdb-shipper object_store: s3 schema: v12 storage_config: aws: s3: s3://us-west-2/test-loki-0 insecure: false s3forcepathstyle: true boltdb_shipper: active_index_directory: /var/loki/index shared_store: s3 rulerConfig: storage: type: local local: directory: /var/loki/rules serviceAccount: create: true annotations: eks.amazonaws.com/role-arn: "arn:aws:iam::638***021:role/test-loki-0-role" write: replicas: 2 read: replicas: 1 test: enabled: false monitoring: dashboards: enabled: false rules: enabled: false alerts: enabled: false serviceMonitor: enabled: false selfMonitoring: enabled: false lokiCanary: enabled: false grafanaAgent: installOperator: false
Итак, тут:
auth_enabled: false
– відключаємо авторизацію в самій Loki (в результаті отримаємоtenant_id
fake в корзині – це ок, нормально, хоча могли б придумати щось красивіше ніж “фейк”)storage.bucketNames.chunks
– потрібно вказати ім’я корзини для блоків, інакше намагатиметься використовувати локальне сховище; у документації не вказано;schema_config.configs.store
:boltdb-shipper
– вказуємо на використанняboltdb-shipper
для роботи з індексами, оскільки він вміє в Single Store, тобто і блоки даних і їх індекси будуть в одній корзиніobject_store: s3
– вказуємо тип сховища, яке налаштовується вstorage_config.aws.s3
(але тут вказуємо саме якschema_config.configs.store.s3
, а неschema_config.configs.store.aws.s3
)
storage_config
– найбільший біль:aws.s3
: вказуємо саме у виглядіs3://<S3_BUCKET_REGION>/<S3_BUCKET_NAME>
, інакше при підключенні ServiceAccount Loki починає намагатися ходити для авторизації на https://sts.dummy.amazonaws.com – я так і не знайшов чому, але при використанні ServiceAccount потрібен саме такий форматboltdb_shipper
– вказуємо йому локальний шлях, де він створює індекси –active_index_directory
, таshared_store
– куди потім їх відправляти; візьме конфіг із тієї жstorage_config.aws.s3
rulerConfig.storage.type: local
– для ruler поки вкажемо локальний каталог, з алертами розберемося в інший раз; якщо не вказати – буде постійно писати в лог помилку, що не може отримати доступ до своєї корзини, яка десь прописана у дефолтах, не пам’ятаю вже де самеwrite.replicas: 2
– мінімальна кількість подів write, щоб Promatil міг писати дані
Оновлюємо Helm-реліз:
[simterm]
$ helm upgrade --install --namespace test-loki-0 --values loki-values.yaml loki grafana/loki ... Installed components: * gateway * read * write
[/simterm]
Тепер у нас є окремо поди read та write. У gateway просто Nginx, який розрулює запити:
[simterm]
$ kk -n test-loki-0 get pod NAME READY STATUS RESTARTS AGE loki-gateway-55b4798bdb-g9hkl 1/1 Running 0 48s loki-read-0 0/1 Pending 0 48s loki-write-0 0/1 Running 0 48s loki-write-1 0/1 Running 0 47s
[/simterm]
Чекаємо хвилину, поки поди перейдуть в Running, перевіряємо логи пода loki-write-0, і після повідомлення:
msg=”joining memberlist cluster succeeded” reached_nodes=2 elapsed_time=1m39.087106032s
перевіряємо корзину:
[simterm]
$ aws --profile development s3 ls test-loki-0 2022-12-25 11:53:13 251 loki_cluster_seed.json
[/simterm]
І ще за кілька хвилин повинні повитися каталоги fake та index:
[simterm]
$ aws --profile development s3 ls test-loki-0 PRE fake/ PRE index/ 2022-12-25 11:53:13 251 loki_cluster_seed.json
[/simterm]
У fake – chunks, в index – індекси.
Окей – начебто завелося.
Дивно, насправді, що цього разу все з першої спроби завелося… Поки сетапив Loki на проекті, де працюю – реально вже подумував взяти ELK та не гаяти час.
Тепер після додавання promatil
, який писатиме дані – Loki Write через ingester
писатиме блоки даних, а bottledb-shipper
почне створювати індекси, і пушити їх у корзину.
Запуск Promtail
Знаходимо Service для Loki Gateway:
[simterm]
$ kk -n test-loki-0 get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE loki-gateway ClusterIP 10.109.225.168 <none> 80/TCP 22m ...
[/simterm]
Деплоїмо, через --set
вказуємо loki.serviceName
:
[simterm]
$ helm upgrade --install --namespace test-loki-0 --set loki.serviceName=loki-gateway promtail grafana/promtail
[/simterm]
Перевіряємо поди:
[simterm]
$ kk -n test-loki-0 get pod NAME READY STATUS RESTARTS AGE loki-gateway-55b4798bdb-7dzlf 1/1 Running 0 5m32s loki-read-0 1/1 Running 0 5m32s loki-write-0 1/1 Running 0 5m32s loki-write-1 1/1 Running 0 5m32s promtail-6pw59 0/1 Running 0 17s promtail-8h78j 0/1 Running 0 17s promtail-jb6bz 0/1 Pending 0 17s ...
[/simterm]
Пішли запускатися поди з promtail
.
Перевіряємо логи Gateway – через нього повинні йти пуші від promtail
:
[simterm]
$ kk -n test-loki-0 logs -f loki-gateway-55b4798bdb-7dzlf ... 10.0.87.55 - - [25/Dec/2022:09:58:19 +0000] 204 "POST /loki/api/v1/push HTTP/1.1" 0 "-" "promtail/2.7.0" "-" 10.0.109.239 - - [25/Dec/2022:09:58:19 +0000] 204 "POST /loki/api/v1/push HTTP/1.1" 0 "-" "promtail/2.7.0" "-"
[/simterm]
Тепер встановимо Grafana і підключимо до неї Loki.
Запуск Grafana
Встановлюємо з того самого репозиторію:
[simterm]
$ helm upgrade --install --namespace test-loki-0 grafana grafana/grafana
[/simterm]
Отримуємо пароль юзера admin:
[simterm]
$ kubectl get secret --namespace test-loki-0 grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo ahUAdmUdpemotqICa6jGzvi9wiU01an5qZJx3WSb
[/simterm]
Прокидуємо порт:
[simterm]
$ kk -n test-loki-0 port-forward svc/grafana 8080:80
[/simterm]
Відкриваємо у браузері http://localhost:8080, логінимось, переходимо до Configuration – Data Sources:
Клікаємо Add data source, выбираємо Loki:
Додаємо Loki, в URL вказуємо http://loki-gateway:80:
Зберігаємо, перевіряємо:
Переходимо в Explore, зверху вибираємо Loki, і дивимось логи:
Готово.