Перейти к содержанию

▍Настройка централизованного логирования в Docker с применением ELK Stack

ELK Stack Logo

Название стека представляет собой аббревиатуру первых букв трех открытых проектов, разрабатываемых и поддерживаемых компанией Elastic: Elasticsearch, Logstash, Kibana

Этот набор компонентов обеспечивает удобное централизованное логирование (ведение журналов) с разных серверов. ELK stack позволяет надежно и безопасно получать данные из любого источника во всех форматах и работать с этими данными: осуществлять поиск по ним, анализировать и визуализировать их в режиме real-time (NRT).

Основными его элементами являются: Elasticsearch (search engine – для хранения и быстрого поиска структурированных данных), Logstash (collector – для приема в различном формате данных, их фильтрации и преобразования, и последующей отправки в различные базы данных) и Kibana (инструмент для визуализации).

Настройка Elasticsearch

version: '3.3'

services:
   elasticsearch:
        image: elasticsearch:8.4.3
        restart: always
        container_name: elasticsearch
        ports:
          - "9200:9200"
        environment:
          - discovery.type=single-node
          - ELASTIC_PASSWORD=passwd123
          - xpack.license.self_generated.type=basic
          - path.data=/usr/share/elasticsearch/data
          - bootstrap.memory_lock=true
          - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
        volumes:
          - /srv/docker/data/elasticsearch:/usr/share/elasticsearch/data
Важно! Запускаем docker-compose в интерактивном режиме, иначе не получится сгенерировать токен.

$ docker-compose up elasticsearch

Генерируем токен:

$ docker exec -ti elasticsearch bash                                                                                                                                                 
elasticsearch@3eb40a1c5607:~$ bin/elasticsearch-create-enrollment-token -s kibana                                                                                                                      
WARNING: Owner of file [/usr/share/elasticsearch/config/users] used to be [root], but now is [elasticsearch]                                                                                                                                  
WARNING: Owner of file [/usr/share/elasticsearch/config/users_roles] used to be [root], but now is [elasticsearch]                                                                                                                            
eyJ2ZXIiOiI4LjQuMyIsImFkciI6WyIxNzIuMTguMC4yOjkyMDAiXSwiZmdyIjoiY2U4NDI4ODcyM2Q3NmU2OGY3NDUxNTkyMDExOWMyY2Y1YzA2YjQ3MWE1NTgxNTZiNTE2OTdmNjA4OTFmMDBmMiIsImtleSI6ImxVYnMxWU1CcWhLT05uZ3AtdGg0Om16VFF3dVpLU1Z5Q1Rqa245Uk0zcGcifQ==          

Настройка Kibana

version: '3.3'

services:
   kibana:
        image: kibana:8.4.3
        restart: always
        container_name: kibana
        ports:
          - "5601:5601"
        depends_on:
          - elasticsearch
        environment:
          - ELASTICSEARCH_URL=https://elasticsearch:9200
          - SERVER_NAME=kibana
          - PATH_DATA=/usr/share/kibana/data
        volumes:
          - /srv/docker/conf/kibana:/usr/share/kibana/data

Запускаем:

docker-compose up -d kibana

Запустим вывод лога кибаны, там будет указан пин код, который потребуется позже ввести в дашборде:

$ docker logs -f kibana                                                                                                                                                                                            
[2022-10-14T09:58:31.932+00:00][INFO ][node] Kibana process configured with roles: [background_tasks, ui]                                                                                                                                     
[2022-10-14T09:58:44.796+00:00][INFO ][http.server.Preboot] http server running at http://0.0.0.0:5601                                                                                                                                        
[2022-10-14T09:58:44.851+00:00][INFO ][plugins-system.preboot] Setting up [1] plugins: [interactiveSetup]                                                                                                                                     
[2022-10-14T09:58:44.854+00:00][INFO ][preboot] "interactiveSetup" plugin is holding setup: Validating Elasticsearch connection configuration…                                                                                                
[2022-10-14T09:58:44.900+00:00][INFO ][root] Holding setup until preboot stage is completed.                                                                                                                                                      

i Kibana has not been configured.                                                                                                                                                       

Go to http://0.0.0.0:5601/?code=029224 to get started.                                                                                                

Your verification code is:  029 224                  

Заходим в сам дашбор кибаны и вводим сгенерированный ранее токен:

Kibana token

Указываем пин код:

Kibana token

Вводим логин elastic и пароль, указанный ранее, в переменной ELASTIC_PASSWORD:

Kibana token

и попадаем в сам дашборд:

Kibana dashboard

Настройка Logstash

version: '3.3'

services:
   logstash:
        image: logstash:8.4.3
        container_name: logstash
        restart: always
        ports:
          - "5044:5044"
        environment:
          - NODE_NAME=logstash
          - xpack.monitoring.enabled=false
        volumes:
          - /srv/docker/conf/logstash/pipeline:/usr/share/logstash/pipeline
        links:
          - elasticsearch
        depends_on:
          - elasticsearch

Добавим пайплайн для nginx логов:

nano /srv/docker/conf/logstash/pipeline/nginx.conf
# Sample Logstash configuration for creating a simple
# Beats -> Logstash -> Elasticsearch pipeline.


input {
  beats {
    port => 5044
  }
}

filter{
  if "nginx-access" in [tags] {
     grok {
           match => {
           'message' => '%{DATA:[nginx][access][referrer]} %{IPORHOST:[nginx][access][remote_ip]} (?:%{IPORHOST:[nginx][access][x_forwarded_for]}|-) \[%{HTTPDATE:timestamp_nginx_access}\] %{NUMBER:[nginx][access][response_code]} (?:%{IPO>
           }
           remove_field => 'message'
     }
     useragent {
           source => "[nginx][access][agent]"
           target => "[nginx][access][user_agent]"
           remove_field => "[nginx][access][agent]"
     }
     geoip {
           source => "[nginx][access][remote_ip]"
           target => "[nginx][access][geoip]"
     }
     mutate {
            add_field => { "[fileset][name]" => "access" }
     }
  }
}

output {
  if "nginx-access" in [tags] {
    stdout { codec => rubydebug }
    elasticsearch {
      hosts => ["https://elasticsearch:9200"]
      index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
      ssl => true
      ssl_certificate_verification => false
      user => 'elastic'
      password => 'passwd123'
    }
  }
}

Зададим формат лога в конфиге nginx.conf:

    log_format  main '"$host" $http_x_forwarded_for $remote_addr [$time_local] $status $upstream_addr $upstream_response_time $msec $request_time '
                '"$request" $body_bytes_sent "$http_referer" '
                '"$http_user_agent"';

    access_log /var/log/nginx/access.log main;

Настройка Filebeat

version: '3.3'

services:
   filebeat:
        image: docker.elastic.co/beats/filebeat:8.4.3
        container_name: filebeat
        entrypoint: "filebeat -e -strict.perms=false"
        volumes:
          - /srv/docker/conf/filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml
          - /var/log/docker/nginx:/var/log/nginx

Конфиг Filebeat:

/srv/docker/conf/filebeat/filebeat.yml
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/nginx/*.log
  tags: ["nginx-access"]

output.logstash:
  enabled: true
  hosts: ["logstash:5044"]

setup.kibana:
  host: "http://kibana:5601"
  username: "elastic"
  password: "passwd123"

Запускаем оставшиеся контейнеры:

docker-compose up -d

Снова открывает дашборд с кибаной, переходим в раздел Discover -> Create data view и указываем данные как на скриншоте:

Kibana create data view

в итоге получаем: Kibana data view

В случае если необходимо прикрутить уведомления, например, по почте по какому-либо тексту в логах, то доустановим ElastAlert 2

Настройка ElastAlert 2

version: '3.3'

services:
   elastalert:
        image: jertel/elastalert2
        restart: always
        container_name: elastalert
        depends_on:
          - elasticsearch
        volumes:
          - /srv/docker/conf/elastalert/elastalert.yaml:/opt/elastalert/config.yaml
          - /srv/docker/conf/elastalert/smtp_auth_file.yml/opt/elastalert/smtp_auth_file.yml          
          - /srv/docker/conf/elastalert/rules:/opt/elastalert/rules

Конфиг ElastAlert 2:

/srv/docker/conf/elastalert/elastalert.yaml
rules_folder: /opt/elastalert/rules

run_every:
  seconds: 10

buffer_time:
  minutes: 15

es_host: elasticsearch
es_port: 9200
use_ssl: true
verify_certs: false
es_username: elastic
es_password: passwd123

writeback_index: elastalert_status

alert_time_limit:
  days: 2

Отправка уведомлений в нашем случае будет происходить через SMTP подключение, в smtp_auth_file.yml укажем логин и пароль от ящика:

/srv/docker/conf/elastalert/smtp_auth_file.yml
user: "noreply@example.ru"
password: "пароль от ящика"
/srv/docker/conf/elastalert/rules/rule.yaml
name: "rule"
type: "any"
index: "filebeat-*"
is_enabled: true
realert:
  minutes: 0
terms_size: 50
timestamp_field: "@timestamp"
timestamp_type: "iso"
use_strftime_index: false
alert_subject: "Error"
alert_text: "Error code:"
alert_text_args:
  - "message"
filter:
  - query:
      query_string:
        query: 'message: "ERROR 400" OR message: "ERROR 401" OR message: "ERROR 403"'
alert:
  - "email"

from_addr: noreply@example.ru
smtp_host: smtp.mail.ru
smtp_port: 465
smtp_ssl: true
smtp_auth_file: /opt/elastalert/smtp_auth_file.yml

email:
  - "admin@example.ru"

где "ERROR 400", "ERROR 401", "ERROR 403" тексты ошибок, которые будут искаться в логах и при их обнаружении отправляться сообщение на почту.

К началу