Tổng quan về kiến trúc
Trong môi trường container hóa, việc quản lý nhật ký tập trung trở nên quan trọng. Hệ thống ELK (Elasticsearch, Logstash, Kibana) được triển khai dưới dạng container cung cấp giải pháp thu thập, lưu trữ và phân tích nhật ký hiệu quả. Bài viết này trình bày cách triển khai đầy đủ từ khâu thu thập nhật ký container, tự động tạo chỉ mục, đến giám sát cảnh báo và quản lý vòng đời dữ liệu.
Triển khai các thành phần ELK dưới dạng container
Khởi tạo Elasticsearch
Container Elasticsearch được cấu hình với các thông số quan trọng:
docker container run -d \
--privileged \
-p 127.0.0.1:9200:9200 \
-p 9300:9300 \
--log-opt max-size=10m \
--log-opt max-file=3 \
--name es-node \
--restart unless-stopped \
-e "discovery.type=single-node" \
-v /storage/es-data:/usr/share/elasticsearch/data \
docker.elastic.co/elasticsearch/elasticsearch:6.6.2
chown -R 1000:1000 /storage/es-data
Các tham số chính:
- Port 9200 cho API HTTP, port 9300 cho giao tiếp cluster
- Giới hạn kích thước file log: tối đa 10MB/file, giữ lại 3 file
- Chế độ khởi động lại tự động
- Chế độ single-node cho triển khai đơn giản
- Mount volume lưu trữ dữ liệu ra host
Cấu hình và chạy Logstash
Tạo file cấu hình pipeline cho Logstash:
mkdir -p /storage/logstash-config
cat > /storage/logstash-config/pipeline.conf << "CONFIG_END"
input {
beats {
host => "0.0.0.0"
port => "5044"
}
}
filter {
grok {
match => {
"message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:content}"
}
}
mutate {
remove_field => ["@version", "host"]
}
}
output {
elasticsearch {
hosts => [ "es-node:9200" ]
index => "logs-%{container_id}-%{+YYYY.MM.dd}"
}
}
CONFIG_END
Khởi chạy container Logstash:
docker container run -d \
-p 5044:5044 \
--name log-processor \
--link es-node \
--restart unless-stopped \
-v /storage/logstash-config/pipeline.conf:/usr/share/logstash/pipeline/logstash.conf \
docker.elastic.co/logstash/logstash:6.6.2
Triển khai Kibana với plugin
cat > /storage/kibana-config.yml << "YAML_END"
server.name: kibana
server.host: "0.0.0.0"
elasticsearch.hosts: http://es-node:9200
monitoring.ui.container.elasticsearch.enabled: true
YAML_END
docker container run -d \
-p 5601:5601 \
--name kibana-ui \
--link es-node \
--restart unless-stopped \
-v /storage/kibana-config.yml:/usr/share/kibana/config/kibana.yml \
docker.elastic.co/kibana/kibana:6.6.2
Thu thập nhật ký container với Filebeat
Cấu hình Filebeat nâng cao
# /storage/filebeat-config.yml
filebeat.inputs:
- type: log
paths:
- '/var/lib/docker/containers/*/*.log'
# Xử lý JSON output từ Docker
json.keys_under_root: true
json.add_error_key: true
json.message_key: log
# Xử lý multi-line log
multiline.pattern: ^\d{4}
multiline.negate: true
multiline.match: after
# Lọc log
exclude_lines: ['DEBUG']
include_lines: ['ERROR', 'WARN', 'INFO']
processors:
- add_docker_metadata:
host: "unix:///var/run/docker.sock"
- rename:
fields:
- from: "docker.container.name"
to: "container_name"
- from: "docker.container.id"
to: "container_id"
- from: "json.log"
to: "raw_message"
- drop_fields:
fields: ["ecs", "agent", "input"]
output.logstash:
hosts: ["host.docker.internal:5044"]
Khởi động Filebeat collector
docker container run -d \
--name log-collector \
--privileged \
--restart unless-stopped \
-v /storage/filebeat-config.yml:/usr/share/filebeat/filebeat.yml:ro \
-v /var/lib/docker/containers:/var/lib/docker/containers:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
docker.elastic.co/beats/filebeat:6.6.2
Thiết lập cảnh báo với ElastAlert
Triển khai ElastAlert Server
# Clone và chuẩn bị cấu hình
git clone https://github.com/bitsensor/elastalert.git
cd elastalert
# Điều chỉnh cấu hình kết nối Elasticsearch
sed -i 's/localhost:9200/es-node:9200/g' config/elastalert.yaml
# Khởi chạy container
docker container run -d \
-p 3030:3030 \
--name alert-engine \
--link es-node \
-v $(pwd)/config/elastalert.yaml:/opt/elastalert/config.yaml \
-v $(pwd)/alert-rules:/opt/elastalert/rules \
bitsensor/elastalert:latest
Cấu hình quy tắc cảnh báo mẫu
# alert-rules/error-threshold.yaml
name: "High Error Rate Alert"
type: frequency
index: logs-*
num_events: 10
timeframe:
minutes:这四个数字
filter:
- query:
query_string:
query: "level:ERROR"
alert:
- "slack"
slack_webhook_url: "https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
slack_username: "ELK Monitor"
slack_channel: "#alerts"
alert_subject: "High Error Rate Detected in {container_name}"
alert_text: |
Container: {container_name}
Error Count: {num_hits}
Time Range: {timeframe}
Tự động dọn dẹp chỉ mục cũ
Script xóa chỉ mục theo thời gian
#!/bin/bash
# /scripts/cleanup-old-indices.sh
ES_HOST="127.0.0.1"
ES_PORT="9200"
RETENTION_DAYS=7
LOG_FILE="/var/log/index-cleanup.log"
# Lấy danh sách tất cả indices
INDICES=$(curl -s "${ES_HOST}:${ES_PORT}/_cat/indices?h=index" | grep -E 'logs-.+-[0-9]{4}\.[0-9]{2}\.[0-9]{2}$')
CURRENT_TS=$(date +%s)
RETENTION_SECONDS=$((RETENTION_DAYS * 24 * 3600))
for INDEX in $INDICES; do
# Trích xuất ngày từ tên index
INDEX_DATE=$(echo $INDEX | grep -o '[0-9]\{4\}\.[0-9]\{2\}\.[0-9]\{2\}$')
if [ -n "$INDEX_DATE" ]; then
# Chuyển đổi định dạng ngày
INDEX_TS=$(date -d "${INDEX_DATE//./-}" +%s 2>/dev/null)
if [ $? -eq 0 ]; then
AGE=$((CURRENT_TS - INDEX_TS))
if [ $AGE -gt $RETENTION_SECONDS ]; then
echo "$(date): Deleting index $INDEX (age: $((AGE/86400)) days)" >> $LOG_FILE
curl -XDELETE "${ES_HOST}:${ES_PORT}/${INDEX}" >> $LOG_FILE 2>&1
fi
fi
fi
done
Thiết lập cron job tự động
# Thêm vào crontab
0 2 * * * /scripts/cleanup-old-indices.sh
Kiểm tra và giám sát
Sau khi triển khai hoàn tất:
- Truy cập Kibana tại http://localhost:5601
- Tạo index pattern:
logs-* - Kiểm tra log trong Discover tab
- Xác minh kết nối ElastAlert trong plugin
- Kiểm tra cảnh báo qua kênh đã cấu hình