Регистрация приложений Docker с помощью Filebeat и Logstash
У меня есть набор докционированных приложений, разбросанных по нескольким серверам и пытающийся настроить централизованное ведение журнала на уровне производства с помощью ELK. У меня все в порядке с частью ELK, но я немного запутался в том, как пересылать журналы на мои журналы.
Я пытаюсь использовать Filebeat из-за его функции loadbalance.
Я также хотел бы избежать упаковки Filebeat (или чего-либо еще) во все мои докеры и держать его разделенным, прикрепленным или нет.
Как я могу продолжить?
Я пытаюсь сделать следующее. Мои Dockers регистрируются на stdout, поэтому бездокументированный Filebeat настроен для чтения из stdin, который я делаю:
журналы докеров -f mycontainer |./filebeat -e -c filebeat.yml
Это похоже на работу в начале. Первые журналы отправляются на мой логсташ. Я думаю, кешированный. Но в какой-то момент он застревает и продолжает отправлять одно и то же событие
Является ли это просто ошибкой или я направляюсь в неправильном направлении? Какое решение вы настроили?
Ответы
Ответ 1
Docker позволяет вам использовать logDriver. Этот ответ не заботится о Filebeat или балансировке нагрузки.
В презентации я использовал syslog для пересылки журналов в экземпляр Logstash (ELK), прослушивающий порт 5000.
Следующая команда постоянно отправляет сообщения через syslog в Logstash:
docker run -t -d --log-driver=syslog --log-opt syslog-address=tcp://127.0.0.1:5000 ubuntu /bin/bash -c 'while true; do echo "Hello $(date)"; sleep 1; done'
Ответ 2
Здесь один из способов переслать docker logs
в стек ELK (требуется драйвер docker >= 1.8 для драйвера журнала gelf):
-
Запустите контейнер Logstash с плагин ввода gelf, чтобы читать с gelf и выводить на хост Elasticsearch (ES_HOST: port):
docker run --rm -p 12201:12201/udp logstash \
logstash -e 'input { gelf { } } output { elasticsearch { hosts => ["ES_HOST:PORT"] } }'
-
Теперь запустите контейнер Docker и используйте glog Docker logging. Вот тупой пример:
docker run --log-driver=gelf --log-opt gelf-address=udp://localhost:12201 busybox \
/bin/sh -c 'while true; do echo "Hello $(date)"; sleep 1; done'
-
Загрузите Kibana и все, что приземлилось в docker logs
, теперь видно. исходный код gelf показывает, что для вас создаются некоторые полезные поля (hat-tip: Christophe Labouisse): _container_id
, _container_name
, _image_id
, _image_name
, _command
, _tag
, _created
.
Если вы используете docker-compose (обязательно используйте docker-compose >= 1.5) и добавьте соответствующие настройки в docker-compose.yml
после запуска контейнера старта:
log_driver: "gelf"
log_opt:
gelf-address: "udp://localhost:12201"
Ответ 3
С помощью filebeat вы можете просто выполнить вывод docker logs
, как вы описали. Поведение, которое вы видите, определенно звучит как ошибка, но также может быть частью частичной настройки чтения строки, поражающей вас (повторите частичные строки до тех пор, пока не будет найден символ новой строки).
Проблема, которую я вижу с трубопроводом, - это возможное противодавление в случае отсутствия логсташа. Если filebeat не может отправлять какие-либо события, он будет буферизовать события внутри и в какой-то момент прекратить чтение из stdin. Не знаю, как/если докер защищает от stdout, становится невосприимчивым. Еще одна проблема с трубопроводом может быть перезапуск поведения filebeat + docker, если вы используете docker-compose. docker-compose по умолчанию повторно использует изображения + состояние изображения. Поэтому, когда вы перезагружаетесь, вы будете отправлять все старые журналы снова (учитывая, что основной файл журнала еще не был повернут).
Вместо того, чтобы прокладывать каналы, вы можете попробовать прочитать файлы журнала, написанные докером, в хост-системе. Драйвер журнала docker по умолчанию - это json log driver. Вы можете и должны настроить драйвер журнала json для ведения журнала вращения + сохранить некоторые старые файлы (для буферизации на диске). См. Параметры максимального размера и максимального файла. Драйвер json помещает одну строку данных "json" для каждой строки, подлежащей регистрации. В хост-системе докера файлы журнала записываются в /var/lib/docker/containers/container _id/container_id-json.log. Эти файлы будут перенаправлены filebeat на logstash. Если логстаст или сеть становятся недоступными или перезапущен файл, он продолжает пересылать строки журнала, в которых он находился (данные файлы не были удалены из-за поворота журнала). Никакие события не будут потеряны. В logstash вы можете использовать кодек json_lines или фильтр для анализа строк json и фильтра grok для получения дополнительной информации из ваших журналов.
обсуждение об использовании libbeat (используется файловым файлом для отправки файлов журналов), чтобы добавить новый драйвер журнала для докеров. Возможно, в будущем можно будет собирать журналы через dockerbeat с помощью журналов docker api (я не знаю никаких планов об использовании logs api, хотя).
Использование syslog также является опцией. Возможно, вы можете получить какое-то реле syslog на ваших событиях балансировки нагрузки хост-сервера докеров. Или вы можете записывать файлы журнала syslog и использовать filebeat для их пересылки. Я думаю, что у rsyslog есть как минимум некоторый режим восстановления после сбоя. Вы можете использовать входной плагин logstash syslog и rsyslog для пересылки журналов в logstash с поддержкой отказа при условии, что активный экземпляр журнала не будет недоступен.
Ответ 4
Я создал свое собственное изображение докеров с помощью Docker API для сбора журналов контейнеров, работающих на машине, и отправки их в Logstash благодаря Filebeat. Нет необходимости устанавливать или настраивать что-либо на хосте.
Проверьте это и скажите мне, подходит ли оно вашим потребностям: https://hub.docker.com/r/bargenson/filebeat/.
Код доступен здесь: https://github.com/bargenson/docker-filebeat
Ответ 5
Просто для того, чтобы помочь другим, которые должны это сделать, вы можете просто использовать Filebeat для отправки журналов. Я бы использовал контейнер by @brice-argenson, но мне нужна поддержка SSL, поэтому я пошел с локально установленным экземпляром Filebeat.
Искатель из filebeat (повторите для большего количества контейнеров):
- input_type: log
paths:
- /var/lib/docker/containers/<guid>/*.log
document_type: docker_log
fields:
dockercontainer: container_name
Это немного утомительно, что вам нужно знать идентификаторы GUID, поскольку они могут меняться при обновлениях.
На сервере logstash настройте обычный источник входного файла для logstash и используйте фильтр следующим образом:
filter {
if [type] == "docker_log" {
json {
source => "message"
add_field => [ "received_at", "%{@timestamp}" ]
add_field => [ "received_from", "%{host}" ]
}
mutate {
rename => { "log" => "message" }
}
date {
match => [ "time", "ISO8601" ]
}
}
}
Это приведет к анализу JSON из журналов Docker и установит метку времени, указанную Docker.
Если вы читаете журналы с изображения nginx Docker, вы также можете добавить этот фильтр:
filter {
if [fields][dockercontainer] == "nginx" {
grok {
match => { "message" => "(?m)%{IPORHOST:targethost} %{COMBINEDAPACHELOG}" }
}
mutate {
convert => { "[bytes]" => "integer" }
convert => { "[response]" => "integer" }
}
mutate {
rename => { "bytes" => "http_streamlen" }
rename => { "response" => "http_statuscode" }
}
}
}
Преобразование/переименование является необязательным, но фиксирует надзор в выражении COMBINEDAPACHELOG
, где он не передает эти значения целым числам, что делает их недоступными для агрегации в Kibana.
Ответ 6
Я подтвердил, что erewok написал выше в комментарии:
В соответствии с документами вы должны иметь возможность использовать шаблон, подобный этому в ваших поисках .paths:/var/lib/docker/containers/*/*.log - erewok 18 апреля в 21:03
Контейнеры контейнера докера, представленные как первые '*', корректно разрешаются при запуске filebeat. Я не знаю, что происходит с добавлением контейнеров.