В данной статье мы рассмотрим вопрос централизованного логирования с использованием filebeat (гребаный спойлер) и graylog. В какой-то момент мы заметили, что машин в нашей инфраструктуре стало достаточно много, и чтобы посмотреть логи, приходилось иногда заходить на несколько машин и мучительно искать по множеству контейнеров, в этот момент мы поняли, что дальше жить так нельзя.
Постановка задачи стояла следующим образом:
- Чем собирать логи
- Где хранить
- Нужно не потерять логи при недоступности центрального хранилища логов
Ранее мы уже пробовали централизованно собирать логи vector (https://vector.dev/), но нам хотелось иметь удобный веб-интерфейс для просмотра. А vector веб-интерфейса не имеет. В качестве веб-интерфейса, а заодно и местом централизованного хранения, мы выбрали graylog, фактически сейчас единственное open source решение, которое имеет обширный функционал и удобство использования. На момент написания статьи vector “из коробки” не умеет отправлять в gelf формате в graylog, но в одном из issues на github один энтузиаст смог сконфигурировать vector нужным образом (https://github.com/vectordotdev/vector/issues/4868#issuecomment-782740639). В общем vector в качестве решения для сбора логов отбросили.
Прежде чем отвечать на вопрос “Чем собирать”, нужно немного сказать про инфраструктуру: в инфраструктуре у нас все приложения запускаются в docker контейнерах, машин на момент написания у нас уже 16, а самих контейнеров около 60, контейнеры в свою очередь находятся под управлением nomad. Также важным моментом является то, что несколько машин в нашей инфраструктуре являются прерываемыми, они один раз в сутки перезапускаются. С инфраструктурой разобрались, теперь нужно определяться, чем собирать. Сперва наш взгляд упал на fluentd, fluentbit, т.к. они умели отправлять в gelf формате. В процессе настройки fluentd почему-то не слал больше 30 сообщений, разобраться, почему, нам так и не удалось, при использовании fluentbit в какой-то момент использования docker logging driver gelf и настройки fluentbit c output gelf выяснилось, что при недоступности fluentbit в момент рестарта контейнеров (на прерываемых машинах контейнеры один раз в сутки перезапускаются) они не запустятся и становятся неработоспособными. Мы поняли, что чем проще - тем лучше, и решили, что нужно собирать из файлов. В свою очередь настроили fluentbit для сбора из файлов, но fluentbit почему-то тоже доставлял не все логи, аналогично с fluentd определить, почему так происходит, не удалось. И в итоге мы остановились на filebeat в качестве сборщика логов (https://www.elastic.co/guide/en/beats/filebeat/current/how-filebeat-works.html), а graylog в качестве хранилища логов.
Еще один важный момент, который нужно учесть, это то, что graylog находится в другой инфраструктуре, т.е. прямой сетевой связности между graylog сервером и машинами, на которых запущен filebeat, нет. Т.о. мы связали это все через гейт, на котором у нас находится traefik (смотри диаграмму ниже). Теперь перейдем к настройке. Graylog мы запустили на отдельной машине в обычном docker-compose.yml файле.
Graylog docker-compose.yml
version: "2.3"
services:
es01:
image: elasticsearch:7.10.1
restart: unless-stopped
network_mode: host
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
environment:
- "ES_JAVA_OPTS=-Xms5g -Xmx5g"
- ELASTIC_PASSWORD=test
- discovery.type=single-node
- cluster.max_shards_per_node=20000
- search.max_open_scroll_context=9000
volumes:
- /etc/localtime:/etc/localtime:ro
- /graylog/data/es01:/usr/share/elasticsearch/data
labels:
- "SERVICE_CHECK_HTTP=/_cluster/health"
- "SERVICE_CHECK_INTERVAL=40s"
- "SERVICE_CHECK_TIMEOUT=3s"
- "SERVICE_CHECK_DEREGISTER_AFTER=10m"
mongodb:
image: mongo:4.2
restart: unless-stopped
network_mode: host
volumes:
- /graylog/data/mongo:/data/db
graylog:
image: graylog/graylog:4.3.3
restart: unless-stopped
depends_on:
- mongodb
- es01
network_mode: host
volumes:
- /graylog/data/graylog:/usr/share/graylog/data
environment:
- GRAYLOG_PASSWORD_SECRET=test
- GRAYLOG_ROOT_PASSWORD_SHA2=shashasha
- GRAYLOG_HTTP_EXTERNAL_URI=http://192.168.2.2:9000/
entrypoint: /usr/bin/tini -- wait-for-it 172.22.202.104:9200 -- /docker-entrypoint.sh
labels:
- "SERVICE_TAGS=hostname=graylog,traefik.enable=true,\
traefik.http.routers.graylog.rule=Host(`graylog.dev`),\
traefik.http.routers.graylog.entrypoints=websecure,\
traefik.http.routers.graylog.tls=true"
- SERVICE_NAME=graylog
- SERVICE_CHECK_DEREGISTER_AFTER=10m
- SERVICE_9000_NAME=graylog
- SERVICE_9000_CHECK_TCP=true
- SERVICE_9000_CHECK_INTERVAL=40s
- SERVICE_9000_CHECK_TIMEOUT=5s
- SERVICE_9000_CHECK_DEREGISTER_AFTER=10m
Перейдем к конфигурации filebeat
Конфиг filebeat.yml у нас простейший
filebeat.inputs:
- type: container
paths:
- /var/lib/docker/containers/*/*.log
processors:
- add_docker_metadata:
match_source_index: 4
output.logstash:
hosts:
- graylog_host:graylog_port
Тут все просто, мы просто отправляем все логи всех контейнеров на хост graylog, в свою очередь graylog_host - это у нас хост с traefik, а в конфигурации traefik уже указан сам graylog, т.к. с гейта есть прямая сетевая связность с graylog.
Т.к. у нас nomad, то filebeat мы деплоим тоже в nomad, далее конфигурация filebeat job для деплоя его в nomad. Единственное, что здесь стоит отметить, так это то, что в env параметры GRAYLOG_HOST, GRAYLOG_PORT мы передаем ip адрес и порт на traefik. Также стоит обратить внимание, что тип job у нас system, что запускает filebeat на всех машинах. Также мы монтируем в контейнер filebeat каталог /filebeat/registry, для сохранения registry файла. Это необходимо для того, чтобы при отказе output filebeat отслеживал последние изменения, чтобы после того, как output вернется в рабочее состояние, доставить туда логи. Более подробно про registry файл можно почитать в документации filebeat https://www.elastic.co/guide/en/beats/filebeat/current/how-filebeat-works.html#_how_does_filebeat_keep_the_state_of_files
job "filebeat" {
datacenters = ["a", "b", "c"]
namespace = "default"
update {
max_parallel = 1
auto_revert = true
auto_promote = false
canary = 0
}
type = "system"
group "logging" {
restart {
mode = "delay"
attempts = 2
interval = "1m"
delay = "30s"
}
task "filebeat" {
driver = "docker"
kill_timeout = "30s"
leader = true
user = "root"
env {
SERVICE_IGNORE = "true"
GRAYLOG_HOST = "GRAYLOG_HOST"
GRAYLOG_PORT = "GRAYLOG_PORT"
}
config {
auth {
username = "test"
password = "test"
}
image = "docker.registry/filebeat:7.10.1"
force_pull = true
volumes = [
"/var/lib/docker/containers:/var/lib/docker/containers:ro",
"/var/run/docker.sock:/var/run/docker.sock:ro",
"/filebeat/registry:/filebeat/registry:rw"
]
}
service {
name = "filebeat"
tags = ["filebeat", "logging", "hostname=${attr.unique.hostname}"]
check_restart {
grace = "1m"
ignore_warnings = false
}
}
logs {
max_files = 3
max_file_size = 10
}
resources {
memory = 100
memory_max = 150
}
}
}
}
Теперь перейдем к конфигурации traefik, здесь лишь фрагмент конфига traefik.yml, мы добавляем еще один entrypoint для graylog.
…………
entryPoints:
web:
address: ":80"
forwardedHeaders:
insecure: true
websecure:
address: ":443"
http:
middlewares:
- sslheader@file
- trimwww@file
graylog:
address: ":11111"
…………
Также не забываем сконфигурировать порт для работы с graylog в конфиге job nomad для traefik, ниже указан фрагмент traefik job.
job "traefik" {
datacenters = ["a", "b", "c"]
…………………
type = "system"
group "traefik" {
network {
mode = "host"
port "http" {
static = 80
to = 80
host_network = "private"
}
port "public" {
static = 443
to = 443
host_network = "public"
}
port "ui" {
to = 8080
host_network = "private"
}
port "graylog" {
static = 11111
to = "11111"
host_network = "private"
}
}
task "traefik" {
driver = "docker"
kill_timeout = "30s"
leader = true
………………
config {
image = "traefik:v2.8.7"
force_pull = true
ports = ["http", "public", "ui",
"graylog"
]
…………………
}
Так выглядят entrypoints в веб-интерфейсе traefik.
Конфигурация роутера для graylog осуществляется в tcp router, вот как это выглядит в веб-интерфейсе traefik:
Также нужно сконфигурировать сервис (в терминологии traefik), куда мы будем отправлять логи в graylog, именно в конфигурации сервиса в traefik указывается сам ip и порт graylog сервера.
В веб-интерфейсе graylog вот так конфигурируется input (в терминологии graylog), т.е. входная точка, которая будет принимать логи на стороне graylog. Тут видно, что тип input у нас Beats.
Вот так выглядит сам веб-интерфейс graylog, где мы уже ищем конкретные логи:
Вот так достаточно просто (конечно после нескольких десятков часов исследований) настраивается централизованный сбор логов. Мы пойдем посмотрим, что у нас там в логах, а вы пока stay tuned.
Top comments (0)