ELK Stack с Docker и несколькими серверами для UDP логирования

Вопрос или проблема

Я пытаюсь настроить стек ELK (Kibana, Logstash и Elasticsearch) в Portainer, который должен получать логи от ПК по всему миру.

Я не уверен, как должна выглядеть правильная настройка, чтобы производительность для клиентов была хорошей.

Допустим, Portainer работает в Европе в контейнере Docker, и есть пользователи в Америке, Европе, Австралии и Азии.

Какой будет правильная настройка? Я предполагаю, что мне нужен сервер на каждом континенте в моем стеке, но как мне перенаправить логи на самый “быстрый” конечный пункт?

Будет здорово, если кто-нибудь сможет подсказать мне некоторые ключевые слова и статьи, где я могу найти решение, как может выглядеть эта настройка.

Прямо сейчас у меня есть стек ELK на моем локальном компьютере с Docker, и я отправляю UDP-сообщения (содержимое JSON) в мой стек. Частота этих сообщений может составлять несколько раз в секунду от клиента. В мире одновременно онлайн примерно 600-700 человек (возможно, больше в будущем).

Мой elasticsearch.yml

cluster.name: docker-cluster
network.host: 0.0.0.0

xpack.license.self_generated.type: trial
xpack.security.enabled: true

Вот мой docker-compose.yml

setup:
profiles:
  - setup
build:
  context: setup/
  args:
    ELASTIC_VERSION: ${ELASTIC_VERSION}
init: true
volumes:
  - ./setup/entrypoint.sh:/entrypoint.sh:ro,Z
  - ./setup/lib.sh:/lib.sh:ro,Z
  - ./setup/roles:/roles:ro,Z
environment:
  ELASTIC_PASSWORD: ${ELASTIC_PASSWORD:-}
  LOGSTASH_INTERNAL_PASSWORD: ${LOGSTASH_INTERNAL_PASSWORD:-}
  KIBANA_SYSTEM_PASSWORD: ${KIBANA_SYSTEM_PASSWORD:-}
  METRICBEAT_INTERNAL_PASSWORD: ${METRICBEAT_INTERNAL_PASSWORD:-}
  FILEBEAT_INTERNAL_PASSWORD: ${FILEBEAT_INTERNAL_PASSWORD:-}
  HEARTBEAT_INTERNAL_PASSWORD: ${HEARTBEAT_INTERNAL_PASSWORD:-}
  MONITORING_INTERNAL_PASSWORD: ${MONITORING_INTERNAL_PASSWORD:-}
  BEATS_SYSTEM_PASSWORD: ${BEATS_SYSTEM_PASSWORD:-}
networks:
  - elk
depends_on:
  - elasticsearch

elasticsearch:
build:
  context: elasticsearch/
  args:
    ELASTIC_VERSION: ${ELASTIC_VERSION}
volumes:
  - ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro,Z
  - elasticsearch:/usr/share/elasticsearch/data:Z
ports:
  - 9200:9200
  - 9300:9300
environment:
  node.name: elasticsearch
  ES_JAVA_OPTS: -Xms512m -Xmx512m
  ELASTIC_PASSWORD: ${ELASTIC_PASSWORD:-}
  discovery.type: single-node
networks:
  - elk
restart: unless-stopped

logstash:
build:
  context: logstash/
  args:
    ELASTIC_VERSION: ${ELASTIC_VERSION}
volumes:
  - ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml:ro,Z
  - ./logstash/pipeline:/usr/share/logstash/pipeline:ro,Z
ports:
  - 5044:5044/udp
  - 50000:50000/tcp
  - 9600:9600
environment:
  LS_JAVA_OPTS: -Xms256m -Xmx256m
  LOGSTASH_INTERNAL_PASSWORD: ${LOGSTASH_INTERNAL_PASSWORD:-}
networks:
  - elk
depends_on:
  - elasticsearch
restart: unless-stopped

kibana:
build:
  context: kibana/
  args:
    ELASTIC_VERSION: ${ELASTIC_VERSION}
volumes:
  - ./kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml:ro,Z
ports:
  - 5601:5601
environment:
  KIBANA_SYSTEM_PASSWORD: ${KIBANA_SYSTEM_PASSWORD:-}
networks:
  - elk
depends_on:
  - elasticsearch
restart: unless-stopped

networks:
  elk:
    driver: bridge

volumes:
  elasticsearch:

моя logstash.conf

    input {
    tcp {
        port => 50000
    }
    udp {
        port => 5044
        codec => json
  }
}

filter {
    json {
        source => "message"
        target => "parsed_message" 
        skip_on_invalid_json => true
    }

    mutate {
        rename => {
        "[parsed_message][message]" => "message"
        "[parsed_message][logLevel]" => "logLevel"
        "[parsed_message][application]" => "application"
        "[parsed_message][username]" => "username"
        "[parsed_message][computer]" => "computer"
        "[parsed_message][timestamp]" => "timestamp"
        }
    }
}

output {
    elasticsearch {
        #index => "logstash-%{+YYYY.MM.dd}"
        #hosts => "elasticsearch:9200"
        hosts => ["elasticsearch:9200"]
        data_stream => "true"          
        data_stream_type => "logs"       
        data_stream_dataset => "logstash" 
        data_stream_namespace => "default" 
        user => "logstash_internal"
        password => "${LOGSTASH_INTERNAL_PASSWORD}"
    }
}

мой kibana.yml

    xpack.fleet.agents.fleet_server.hosts: [ http://fleet-server:8220 ]

xpack.fleet.outputs:
  - id: fleet-default-output
    name: default
    type: elasticsearch
    hosts: [ http://elasticsearch:9200 ]
    is_default: true
    is_default_monitoring: true

xpack.fleet.packages:
  - name: fleet_server
    version: latest
  - name: system
    version: latest
  - name: elastic_agent
    version: latest
  - name: docker
    version: latest
  - name: apm
    version: latest

xpack.fleet.agentPolicies:
  - name: Fleet Server Policy
    id: fleet-server-policy
    description: Static agent policy for Fleet Server
    monitoring_enabled:
      - logs
      - metrics
    package_policies:
      - name: fleet_server-1
        package:
          name: fleet_server
      - name: system-1
        package:
          name: system
      - name: elastic_agent-1
        package:
          name: elastic_agent
      - name: docker-1
        package:
          name: docker
  - name: Agent Policy APM Server
    id: agent-policy-apm-server
    description: Static agent policy for the APM Server integration
    monitoring_enabled:
      - logs
      - metrics
    package_policies:
      - name: system-1
        package:
          name: system
      - name: elastic_agent-1
        package:
          name: elastic_agent
      - name: apm-1
        package:
          name: apm
        # Смотрите манифест пакета APM для списка возможных входов.
        # https://github.com/elastic/apm-server/blob/v8.5.0/apmpackage/apm/manifest.yml#L41-L168
        inputs:
          - type: apm
            vars:
              - name: host
                value: 0.0.0.0:8200
              - name: url
                value: http://apm-server:8200

Ответ или решение

Эффективная настройка ELK Stack с использованием Docker для многоуровневой UDP-логгирования

Введение

В современных распределённых системах необходимо обеспечить высокую надёжность и производительность обработки логов, особенно при наличии большого количества клиентов из разных регионов. Использование ELK Stack (Elasticsearch, Logstash и Kibana) в контейнерах Docker — это популярное решение для централизованного хранения и анализа логов. В данном руководстве будет описан оптимальный способ настройки ELK Stack для приёма UDP-сообщений от клиентов по всему миру, с учётом географического распределения пользователей.

Архитектура системы

1. Геобазирующие серверы

Для обеспечения высокой доступности и производительности рекомендуется разместить серверы ELK Stack в нескольких регионах, например, в Северной Америке, Европе, Австралии и Азии. Каждый из этих серверов будет получать логи локально от клиентов, что снижает задержку передачи данных.

Рекомендуемая архитектура:

  • Серверы ELK в разных регионах: Разверните отдельные экземпляры ELK Stack на каждом сервере (например, AWS, GCP, Azure) в регионе, где находятся ваши клиенты.
  • Забор логов через UDP: Настройте каждый Logstash для прослушивания UDP на соответствующих портах, обеспечивая поддержку JSON-кода.

2. Балансировка нагрузки

Для того чтобы направлять сообщения от клиентов к ближайшему серверу ELK, можно использовать механизмы маршрутизации:

  • DNS Round Robin: Используйте DNS, чтобы настроить несколько A-записей, указывающих на IP-адреса всех серверов ELK, чтобы клиенты могли получать адреса в зависимости от их геолокации.
  • Геораспределённые прокси: Внедрите прокси-сервера, которые будут перенаправлять UDP-сообщения на ближайший сервер ELK на основе географического расположения.

Пример конфигурации серверов

# docker-compose.yml для каждого сервера ELK

version: '3'

services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.5.0
    environment:
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
      - ELASTIC_PASSWORD=yourpassword
    networks:
      - elk
    ports:
      - "9200:9200"
      - "9300:9300"

  logstash:
    image: docker.elastic.co/logstash/logstash:8.5.0
    environment:
      - "LOGSTASH_JAVA_OPTS=-Xms256m -Xmx256m"
      - "LOGSTASH_PASSWORD=yourpassword"
    networks:
      - elk
    ports:
      - "5044:5044/udp"

  kibana:
    image: docker.elastic.co/kibana/kibana:8.5.0
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
      - KIBANA_PASSWORD=yourpassword
    networks:
      - elk
    ports:
      - "5601:5601"

networks:
  elk:
    driver: bridge

Конфигурация Logstash

Настройте файл logstash.conf для приёма UDP-сообщений и их отправки в Elasticsearch:

input {
    udp {
        port => 5044
        codec => json
    }
}

filter {
    # Добавьте необходимые фильтры для трансформации логов
}

output {
    elasticsearch {
        hosts => ["http://elasticsearch:9200"]
        index => "logs-%{+YYYY.MM.dd}"
        user => "your_username"
        password => "your_password"
    }
}

3. Взаимодейственная настройка Kibana

Kibana будет использоваться для визуализации полученных логов. Убедитесь, что kibana.yml настроен для работы с Elasticsearch:

elasticsearch.hosts: ["http://elasticsearch:9200"]
xpack.security.enabled: true

Заключение

Распределение серверов ELK Stack по нескольким регионам не только улучшит производительность системы, но и повлияет на стабильность приема данных от клиентов. Кроме того, правильное использование DNS и балансировщиков нагрузки поможет направить логирующие сообщения к ближайшим серверам, минимизируя задержки в связи.

Для дальнейшего изучения рекомендуется ознакомиться со следующими ресурсами:

С правильной настройкой ELK Stack, основанной на приведенных рекомендациях, вы сможете эффективно обрабатывать и визуализировать данные логов от пользователей всего мира.

Оцените материал
Добавить комментарий

Капча загружается...