Збирати логи у Grafana Loki з Kubernetes дуже просто – запускаємо Promtail у DaemonSet, йому вказуємо читати всі дані з /var/logs
– і готово (насправді взагалі нічого не вказуємо – з Helm-чарту все працює з коробки).
А от як бути з CloudWatch Logs? На новому проекті маємо купу AWS Lambda, API Gateways і т.д, і всі вони пишуть логи у CloudWatch.
Що стосується Lambda, то можна було б використати Lambda Telemetry API, і писати логи з функції відразу в Loki, див. Building an AWS Lambda Telemetry API extension for direct logging to Grafana Loki, і можливо пізніше ми цей підхід також використаємо, але зараз у нас вже є купа логів від інших сервісів у CloudWatch, і треба таки їх читати.
Ще є варіант встановити CloudWatch як data source у Grafana, і просто користуватись логами з інтерфейсу Grafana та мабуть навіть мати алерти Grafana з цих логів, але рано чи пізно все одно з’явиться Kubernetes або просто ЕС2 інстанси, і треба буде збирати з них логи, тож будемо відразу робити все з Loki, тим більш в неї чудовий LogQL і набагато більше гнучкості у створенні лейбл та алертів.
В такому випадку можемо використати Lambda Promtail від самої Grafana, а працювати воно буде наступним чином:
- якась Lambda-функція (наприклад) пише лог у CloudWatch Log Group
- у Log Group будемо мати Subscription filter, який буде слати логи на іншу Lambda-функцію – власне у Lambda Promtail
- а Lambda Promtail буде пересилати їх до інстансу Loki
Отже, сьогодні створимо тестову Lambda-функцію, яка буде писати логи, і запустимо Lambda Promtail, яка буде слати логи в Grafana Loki, яка вже є.
На що треба звернути увагу, так це на кількість даних, які будуть писатись, бо як завжди з AWS – попасти на гроші досить легко, тому добре мати налаштований AWS Budgets, щоб отримати алерт в разі неочікуваних витрат.
Також треба мати на увазі, що до Loki потрібно буде відкривати доступ на порт 3100, тож Lambda Promtail краще мати в тій самій VPC, де запущена сама Grafana та/або мати якийсь NGINX з HTTP-аутентифікацією.
Зміст
Тестова Lambda для створення логів
Створюємо функцію, нехай буде на Python:
У коді функції додамо кілька print()
, щоб створити запис в лог:
import json import os def lambda_handler(event, context): return { 'statusCode': 200, 'body': json.dumps('Hello from Lambda!') } print('## ENVIRONMENT VARIABLES') print(os.environ['AWS_LAMBDA_LOG_GROUP_NAME']) print(os.environ['AWS_LAMBDA_LOG_STREAM_NAME']) print('## EVENT') print(event)
Тиснемо Test, щоб створити тестовий евент, дані в полі Event JSON нам не важливі, просто вказуємо ім’я евенту, та зберігаємо його:
Тиснемо Test ще раз – функція виконалась, Function Logs пішли:
Переходимо у Monitor > Logs, а звідти у CloudWatch Logs:
І перевіряємо, що Log events є:
Все – тепер можемо переходити до Lambda Promtail.
Запуск Lambda Promtail
Взагалі є готовий Terraform проект і навіть Cloudformation темплейт, тож можна скористатись ними. Єдине, що у Terrafrom треба пофіксити створення resource "aws_iam_role_policy_attachment" "lambda_sqs_execution"
у файлі sqs.tf
, бо там йде виклик ролі role = aws_iam_role.iam_for_lambda.name
, а у main.tf
вона називається resource "aws_iam_role" "this"
.
В усьому іншому Terraform працює – задаємо значення для змінних у variabels.tf
– write_address
, log_group_names
та lambda_promtail_image
, і можна створювати ресурси.
Проте я все ж вважаю за краще на перший раз створити все руками, щоб краще розуміти що і як буде працювати.
Docker образ та Elastic Container Service
Спочатку підготуємо Docker-образ, бо запустити AWS Lambda з публічного ECR Grafana чомусь неможливо, хоча ніде в документації такого обмеження не знайшов.
Переходимо до ECR, створюємо репозиторій:
Завантажуємо публічний образ від Grafana:
[simterm]
$ docker pull public.ecr.aws/grafana/lambda-promtail:main
[/simterm]
Перетегаємо його на свій репозиторій:
[simterm]
$ docker tag public.ecr.aws/grafana/lambda-promtail:main 264***286.dkr.ecr.eu-central-1.amazonaws.com/lambda-promtail-writer:latest
[/simterm]
Логінимось до ECR – вказуємо --profile
, якщо не дефолтний, та AWS Region:
[simterm]
$ aws --profile setevoy ecr get-login-password --region eu-central-1 | docker login --username AWS --password-stdin 264***286.dkr.ecr.eu-central-1.amazonaws.com ... Login Succeeded
[/simterm]
Пушимо туди наш образ:
[simterm]
$ docker push 264***286.dkr.ecr.eu-central-1.amazonaws.com/lambda-promtail-writer:latest
[/simterm]
Переходимо до Lambda.
Створення Lambda Promtail function
Створюємо нову функцію, вибираємо Container image, та вказуємо URI імейджу, який запушили вище:
Переходимо до Configuration > Environment variables, і задаємо мінімально необхідні змінні:
EXTRA_LABELS
: теги/лейбли, які будуть додані у Loki, тут вказуємо у форматі labelname,labelvalueWRITE_ADDRESS
: адреса Loki зhttps://
та URI/loki/api/v1/push
Конфігурація CloudWatch Log Group Subscription filters
Повертаємось до CloudWatch Log Group, в якій були наші тестові логи, і у Subscription filters додаємо нову підписку для Lambda-функції (див. Using CloudWatch Logs subscription filters або How can I configure a CloudWatch subscription filter to invoke my Lambda function?):
Вибираємо функцію, в яку будемо стрімити логи, та при потребі у Configure log format and filters можемо вказати фільтр, через який буде вибиратись що саме пересилати у Lambda, щоб не слати зовсім всі строки.
Зараз нам це не потрібно, тож у Log format ставимо Other, а Subscription filter pattern лишаємо пустим.
У Subscription filter name вказуємо ім’я самого фільтру:
Зберігаємо – Start streaming, повертаємось до Lambda write-logs
, і кілька раз тиснемо Test, щоб створити ще записів у CloudWatch Log Group, які мають стригерити функцію lambda-promtail-testing
і передати їй дані, які вона відправить у Loki.
Перевіряємо у функції lambda-promtail-testing
– у Monitoring мають бути виклики:
У випадку Errors – на вкладці Logs є посилання на CloudWatch Log цієї функції, де буде описана помилка.
Якщо ж все Success – то в Loki вже маємо побачити нову лейблу, і по ній можемо вибрати логи з функції write-logs
:
Готово.
На сторінці документації Grafana ще пишуть, що “Or, have lambda-promtail write to Promtail and use pipeline stages.“, але я так і не знайшов можливості в Promtail писати дані по gRPC або HTTP, хоча така ідея була ще у 2020 році, але вона досі в Draft – Promtail Push API.