Логирование пользовательских действий (Docker Compose)
Назовите свой проект
В качестве примера в этой инструкции используется проект с именем testit
. Вы можете использовать другое название.
Подготовка
Установите параметры
vm.max_map_count=262144
иvm.overcommit_memory=1
на машине, где будет запускаться ELK стек:echo 'vm.max_map_count=262144' >> /etc/sysctl.conf echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf sysctl -p
Для версий 5.3 и выше
Внимание
Начиная с версии 5.3.0 логи пользовательских действий поступают вместе со всеми другими служебными логами в stdout контейнеров по умолчанию.Формат логов - JSON. В связи с этим ELK стек выходит из состава поставки Test IT.
Вы можете использовать ELK стек или другие решения для централизованного сбора логов самостоятельно.
Если нужно выделять/фильтровать логи пользовательских действий среди других, сделать это можно, применив фильтр, который оставляет только те логи, в которых JSON-ключ LogType
в разделе Properties
имеет значение UserAction
:
// пример содержимого лога пользовательских действий
{
//...
"Properties": {
//...
"LogType": "UserAction",
//...
},
//...
}
Как временное решение (т.е. до полного перехода на ваши инструменты логирования), пример использования ELK+filebeat стека для логирования пользовательских действий представлен ниже.
ДИСКЛЕЙМЕР: это не production-ready, а концептуально-демонстрационное решение
Состав файлов для запуска:
- filebeat.sh
- filebeat.yml
- kibana.yml
- logstash.sh
- logstash.yml
- logstash.conf
- docker-compose.elk.yml
Ниже представлено содержимое файлов.
filebeat.sh
#!/bin/bash
cat /tmp/filebeat.yml > /usr/share/filebeat/filebeat.yml
chown -R root /usr/share/filebeat/
chmod -R go-w /usr/share/filebeat
/usr/local/bin/docker-entrypoint -environment container
filebeat.yml
filebeat.inputs:
- type: log
paths:
- /var/lib/docker/containers/*/*-json.log
output.logstash:
hosts: ["logstash:5044"]
kibana.yml
server.name: kibana
server.host: "0"
elasticsearch.hosts: ["http://elasticsearch:9200"]
xpack.monitoring.ui.container.elasticsearch.enabled: true
logstash.sh
#! /bin/bash
generate_put_data()
{
cat <<EOF
{
"policy": {
"phases": {
"hot": {
"min_age": "0ms",
"actions": {
"rollover": {
"max_age": "24h"
}
}
},
"delete": {
"min_age": "${EVENT_LOG_MAX_AGE:-30d}",
"actions": {
"delete": {}
}
}
}
}
}
EOF
}
curl --retry 8 --location \
--request PUT "${ELASTICSEARCH_CONNECTION_STRING}/_ilm/policy/testit_logs_policy?pretty" \
--header 'Content-Type: application/json' \
--data "$(generate_put_data)"
cat /tmp/logstash.yml > /usr/share/logstash/config/logstash.yml
cat /tmp/logstash.conf > /usr/share/logstash/pipeline/logstash.conf
/usr/local/bin/docker-entrypoint
logstash.yml
http.host: "0.0.0.0"
logstash.conf
input {
# Accept logs from filebeat, listening on port 5044
beats {
port => 5044
}
}
filter {
# Docker-level JSON logs parser
json {
source => "message"
tag_on_failure => ["json_parse_error"] # Error-handling for JSON parsing
}
# Date format for Kibana
date {
match => ["time", "ISO8601"]
target => "@timestamp"
}
# Renaming fields for convenience
mutate {
rename => { "[log]" => "message" }
rename => { "[stream]" => "log_stream" }
}
#####################################---Optional Block---#####################################
# #
# #
if [message] =~ /^\{.*\}$/ { # Check the message field for JSON-compatibility
json {
source => "message"
tag_on_failure => ["nested_json_parse_error"] # Error-handling for JSON parsing
}
} else {
drop { } # Non-JSON logs are dropped (necessary for the filter below)
}
if [Properties][LogType] != "UserAction" {
drop { } # Non-"aciton" logs are dropped (optional)
}
# #
# #
#####################################---Optional Block---#####################################
}
output {
elasticsearch {
hosts => "${ELASTICSEARCH_CONNECTION_STRING}"
ilm_enabled => true
ilm_rollover_alias => "testit_logs" # < Index name prefix in ElasticSearch
ilm_pattern => "{now/d{dd.MM.yyyy}}-000001" # < Index name postfix, containing date and number
ilm_policy => "testit_logs_policy" # < Log storage policy, created during logstash init (logstash.sh)
}
}
docker-compose.elk.yml
version: '3.8'
x-logging: &default-logging
driver: "json-file"
options:
max-size: "500m"
max-file: "2"
networks:
testit_monitoring_network:
name: "testit_monitoring_stack"
external: true
x-networks: &default-networks
- "testit_monitoring_network"
x-elk-service: &elk-service-defaults
logging: *default-logging
networks: *default-networks
restart: unless-stopped
services:
elasticsearch:
image: elasticsearch:8.8.1
<<: *elk-service-defaults
environment:
ES_JAVA_OPTS: "-Xms1024m -Xmx1024m"
bootstrap.memory_lock: "true"
cluster.name: "elasticsearch"
discovery.type: "single-node"
network.host: "0.0.0.0"
http.port: "9200"
xpack.security.enabled: "false"
xpack.security.http.ssl.enabled: "false"
ulimits:
memlock:
soft: -1
hard: -1
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9200/_cluster/health"]
interval: 30s
timeout: 10s
retries: 5
volumes:
- elastic-volume:/usr/share/elasticsearch/data
logstash:
image: logstash:8.8.1
<<: *elk-service-defaults
environment:
PATH_CONFIG: "/usr/share/logstash/pipeline/logstash.conf"
ELASTICSEARCH_CONNECTION_STRING: "http://elasticsearch:9200"
ELASTICSEARCH_INDEX: "testit"
ELASTICSEARCH_LOGS_INDEX: "testit_logs"
LS_JAVA_OPTS: "-Xmx512m -Xms512m"
EVENT_LOG_MAX_AGE: 30d
ELASTICSEARCH_SSL_ENABLED: "false"
entrypoint: ["/bin/bash", "-c"]
command: ["/tmp/launch.sh"]
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9600/_node"]
interval: 30s
timeout: 10s
retries: 3
volumes:
- ${PWD}/logstash.conf:/tmp/logstash.conf:ro
- ${PWD}/logstash.yml:/tmp/logstash.yml:ro
- ${PWD}/logstash.sh:/tmp/launch.sh:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
depends_on:
elasticsearch:
condition: service_healthy
kibana:
image: "kibana:8.8.1"
<<: *elk-service-defaults
ports:
- ${KIBANA_EXPOSE_PORT:-5601}:5601
environment:
SERVER_NAME: "localhost"
SERVER_HOST: "0.0.0.0"
ELASTICSEARCH_URL: "http://elasticsearch:9200"
ELASTICSEARCH_HOSTS: "http://elasticsearch:9200"
SERVER_SSL_ENABLED: "false"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5601/api/status"]
interval: 30s
timeout: 10s
retries: 3
volumes:
- ${PWD}/kibana.yml:/usr/share/kibana/config/kibana.yml:ro
depends_on:
elasticsearch:
condition: service_healthy
filebeat:
image: elastic/filebeat:8.8.1
user: root
<<: *elk-service-defaults
entrypoint: ["/bin/bash", "-c"]
command: ["/tmp/launch.sh"]
volumes:
- ${PWD}/filebeat.yml:/tmp/filebeat.yml:ro
- ${PWD}/filebeat.sh:/tmp/launch.sh:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
healthcheck:
test: ["CMD", "filebeat", "test", "output"]
interval: 30s
timeout: 10s
retries: 3
depends_on:
logstash:
condition: service_healthy
volumes:
elastic-volume:
Команды для развертывания ELK стека:
# Создаем в локальной директории все файлы из списка выше
# Добавляем возможность запуска для скриптов
chmod +x logstash.sh filebeat.sh
# Создаем сеть docker
docker network create testit_monitoring_stack
# Запускаем стек
docker compose -f docker-compose.elk.yml -p testit-monitoring up -d
# После завершения команды запуска переходите на http://localhost:5601 (:порт может отличаться если вы задали другое значение переменной KIBANA_EXPOSE_PORT)
# Информацию по пользованию Kibana (веб-интерфейс ELK стека) можете найти по ссылке ниже:
# https://www.elastic.co/guide/en/kibana/8.8/data-views.html
Команды для остановки ELK стека
# Временная остановка проекта с возможностью перезапуска контейнеров
docker compose -f docker-compose.elk.yml -p testit-monitoring down
# Полная остановка с удалением данных, содержащихся в томе elastic-volume
docker compose -f docker-compose.elk.yml -p testit-monitoring down --volumes
# Удаление сети docker
docker network rm testit_monitoring_stack
Для версий 4.0 и выше
Внимание
Начиная с версии 4.0.0 структура файла docker-compose.elk.yml
была изменена, в новых версиях в этом файле содержатся только сервисы ELK стека.
Для включения опции логирования пользовательских действий:
- Выполните следующие команды:Последняя команда объединяет содержимое файлов
cd ~/testit cp docker-compose.yml docker-compose.yml.bak # резервная копия docker compose -f docker-compose.yml -f docker-compose.elk.yml config --no-interpolate > docker-compose.yaml
docker-compose.yml
иdocker-compose.elk.yml
и записывает результат в файлdocker-compose.yml
, замещая предыдущее содержимое. - Выполните шаги из Инструкции по установке в Docker Compose или Руководства по обновлению.
Альтернативный способ запуска стека ELK
Альтернативным способом включения сервисов ELK-стека может быть выполнение команд docker compose с двумя ключами “-f”, при этом передается несколько файлов.
Например, для установки Test IT может быть выполнена следующая команда:
docker compose -f docker-compose.yml -f docker-compose.elk.yml --project-name testit up --detach --timeout 120
Для создания резервной копии и восстановления из нее следующие команды:
scripts/backup.sh "docker-compose.yml -f docker-compose.elk.yml" testit scripts/restore.sh "docker-compose.yml -f docker-compose.elk.yml" testit backup_21_05_2019.tar
Для версий ниже 4.0
Для включения опции логирования пользовательских действий:
Замените
docker-compose.yml
на содержимоеdocker-compose.elk.yml
:cd ~/testit cp docker-compose.yml docker-compose.yml.bak # резервная копия cp docker-compose.elk.yml docker-compose.yml
Выполните шаги из Инструкции по установке в Docker Compose или Руководства по обновлению.