Xây dựng Pipeline Giám sát Log và Metric Hiệu quả với Prometheus, Loki và Grafana
Trong môi trường hệ thống hiện đại, việc chỉ dựa vào metrics số liệu thô từ Prometheus là chưa đủ để chẩn đoán triệt để sự cố. Các kỹ sư hệ thống cần một giải pháp kết hợp giữa giám sát hiệu năng (monitoring) và nhật ký hoạt động (logging) trên cùng một nền tảng thống nhất để có cái nhìn toàn diện. Bài viết này sẽ hướng dẫn chi tiết cách thiết lập một pipeline giám sát hoàn chỉnh, nơi dữ liệu log từ ứng dụng được thu thập bởi Promtail, lưu trữ trong Loki, và hiển thị trực quan, đồng bộ với metrics của Prometheus thông qua Grafana. Đây là mô hình 3P (Prometheus, Promtail, Loki) giúp giảm thiểu chi phí lưu trữ so với ELK stack truyền thống đồng thời tận dụng cơ sở hạ tầng bạn đã có sẵn.
Nguyên lý hoạt động của kiến trúc thu thập dữ liệu
Kiến trúc này dựa trên nguyên tắc "pull" đặc trưng của Prometheus. Thay vì ứng dụng đẩy log đi một nơi xa, chúng ta sử dụng một tác nhân nhẹ gọi là Promtail chạy trên cùng một host nơi chứa ứng dụng. Promtail sẽ quét các tệp log theo cấu hình, thực hiện trích xuất văn bản (grep), thêm các nhãn (labels) cần thiết vào từng dòng log, sau đó đẩy dữ liệu đó về Loki. Loki đóng vai trò là nơi lưu trữ, nó không chỉ lưu log mà còn gắn liền log với các label để việc truy vấn trở nên cực kỳ nhanh chóng. Cuối cùng, Grafana đóng vai trò là giao diện duy nhất, kết nối đồng thời với Prometheus để vẽ biểu đồ metric và với Loki để hiển thị log, cho phép bạn click vào một điểm bất thường trên biểu đồ và xem ngay log tương ứng trong khoảng thời gian đó.
Cấu hình Promtail để thu thập và làm giàu log
Việc cấu hình Promtail là bước quan trọng nhất để đảm bảo dữ liệu log sạch và có ý nghĩa. Chúng ta không nên chỉ đơn thuần lấy toàn bộ file log mà cần cấu hình để trích xuất các trường quan trọng như cấp độ log (severity), thời gian, hoặc ID phiên giao dịch. Hãy tạo file cấu hình /etc/promtail/promtail.yml với nội dung chi tiết sau để thu thập log từ ứng dụng web và thêm các label động:
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: app-logs
static_configs:
- targets:
- localhost
labels:
__path__: /var/log/nginx/access.log
job: nginx-access
environment: production
severity: error
- targets:
- localhost
labels:
__path__: /var/log/nginx/error.log
job: nginx-error
environment: production
Tuy nhiên, để pipeline thực sự mạnh mẽ, bạn nên sử dụng pipeline stages để phân tích cú pháp log ngay trước khi gửi lên Loki. Điều này giúp giảm tải cho Loki và tối ưu hóa việc tìm kiếm. Dưới đây là một đoạn cấu hình nâng cao sử dụng stage regex để tách các trường từ log và thêm vào label, giúp việc query sau này linh hoạt hơn nhiều so với việc chỉ lọc theo từ khóa thô.
scrape_configs:
- job_name: application-logs
static_configs:
- targets:
- localhost
labels:
__path__: /var/log/app/*.log
job: backend-api
pipeline_stages:
- json:
expressions:
level: level
message: message
trace_id: trace_id
- labels:
severity: level
trace_id: trace_id
job: backend-api
- drop:
expression: 'severity == "DEBUG"'
Đoạn cấu hình trên thực hiện việc giải mã log dạng JSON, trích xuất trường level và trace_id, sau đó ánh xạ chúng thành các label mới. Đặc biệt, stage drop sẽ tự động loại bỏ các log có cấp độ DEBUG trước khi gửi lên Loki, giúp tiết kiệm đáng kể dung lượng lưu trữ mà vẫn giữ lại các thông tin quan trọng cho vận hành.
Cài đặt và tối ưu hóa Loki cho lưu trữ
Loki được thiết kế với kiến trúc đơn giản, phân tách rõ ràng giữa thành phần đọc, viết và lưu trữ, nhưng trong các môi trường vừa và nhỏ, chúng ta thường triển khai ở chế độ single binary để dễ quản lý. Cấu hình của Loki cần được điều chỉnh để phù hợp với lưu lượng log dự kiến, đặc biệt là giới hạn kích thước của batch và thời gian giữ lại log (retention period). Dưới đây là file cấu hình cơ bản cho /etc/loki/loki.yaml bao gồm các tham số quan trọng để đảm bảo hệ thống hoạt động ổn định.
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
common:
ring:
kvstore:
store: memberlist
replication_factor: 1
path_prefix: /loki
storage:
type: boltdb
compactor:
working_directory: /tmp/loki
shared_remote: true
query_range:
results_cache:
enabled: true
schema_config:
configs:
- from: 2020-10-24
store: boltdb-shipper
object_store: filesystem
schema: v11
index:
prefix: index_
period: 24h
ruler:
alertmanager_url: http://alertmanager:9093
chunk_store_config:
max_block_ingestion_age: 68h
ingester:
lifecycler:
ring:
kvstore:
store: memberlist
replication_factor: 1
chunk_idle_period: 10m
chunk_retain_period: 60s
max_transfer_retries: 0
limits_config:
ingestion_rate_mb: 16
ingestion_burst_size_mb: 32
max_global_streams_per_user: 0
max_streams_per_user: 0
storage:
type: filesystem
filesystem:
directory: /loki/chunks
Cấu hình này sử dụng lưu trữ đơn giản trên filesystem và boltdb cho index, phù hợp để triển khai nhanh trên một node duy nhất hoặc trong môi trường DevOps. Tham số ingestion_rate_mb là giới hạn tốc độ ghi log, bạn cần điều chỉnh giá trị này dựa trên tài nguyên của máy chủ để tránh tình trạng Loki bị quá tải và mất dữ liệu khi có sự cố đột biến. Việc bật results_cache cũng rất quan trọng để tăng tốc độ phản hồi khi người dùng thực hiện các truy vấn lặp lại trên dashboard Grafana.
Liên kết Log và Metric trong Grafana
Sức mạnh thực sự của hệ thống này nằm ở khả năng liên kết dữ liệu trong Grafana. Khi bạn có một biểu đồ metric từ Prometheus hiển thị một đỉnh lỗi (error spike), bạn cần có thể ngay lập tức xem log tương ứng của những phút đó mà không cần thay đổi context hay chuyển sang tab khác. Để làm được điều này, bạn cần cấu hình datasource trong Grafana. Trước tiên, thêm datasource Loki và Prometheus vào phần Configuration > Data sources với địa chỉ tương ứng. Sau đó, khi tạo hoặc chỉnh sửa dashboard, hãy sử dụng tính năng "Mixed" để kết hợp các panel.
Tuy nhiên, cách tiếp cận chuyên nghiệp hơn là sử dụng biến (variables) hoặc tính năng "Explore" với chế độ hiển thị kết hợp. Trong chế độ Explore, bạn có thể viết query cho Prometheus như rate(http_requests_total[5m]) và query cho Loki như {job="backend-api", environment="production"}. Khi bạn thực hiện query, Grafana sẽ hiển thị log ngay bên dưới biểu đồ metric, đồng bộ về mặt thời gian. Để tự động hóa việc lọc log khi metric bất thường, bạn có thể sử dụng label trong Loki để khớp với label trong Prometheus. Ví dụ, nếu Prometheus có label status_code="500", bạn có thể cấu hình query trong Loki để lọc các dòng log chứa status_code="500", tạo thành một chuỗi điều tra sự cố liên tục và tự động hóa.
Triển khai với Docker Compose để môi trường thử nghiệm
Để kiểm chứng toàn bộ luồng dữ liệu này trong môi trường phát triển hoặc staging, việc sử dụng Docker Compose là phương pháp nhanh chóng và tiện lợi nhất. Dưới đây là file docker-compose.yml hoàn chỉnh bao gồm Prometheus, Loki, Promtail, Grafana và một ứng dụng mẫu (nginx) để sinh log, giúp bạn có một môi trường giám sát đầy đủ chỉ với một lệnh docker-compose up -d.
version: '3'
services:
loki:
image: grafana/loki:2.9.0
ports:
- "3100:3100"
volumes:
- ./loki.yml:/etc/loki/loki.yml:ro
command: -config.file=/etc/loki/loki.yml
promtail:
image: grafana/promtail:2.9.0
volumes:
- /var/log:/var/log:ro
- /tmp/positions.yaml:/tmp/positions.yaml
- ./promtail.yml:/etc/promtail/promtail.yml:ro
command: -config.file=/etc/promtail/promtail.yml
prometheus:
image: prom/prometheus:v2.47.0
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
grafana:
image: grafana/grafana:10.0.0
ports:
- "3000:3000"
environment:
- GF_AUTH_ANONYMOUS_ENABLED=true
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
volumes:
- ./grafana:/var/lib/grafana
nginx:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
command: nginx -g 'daemon off;'
File cấu hình này tạo ra một mạng lưới ảo kết nối tất cả các dịch vụ. Promtail sẽ mount thư mục /var/log của host vào container để có thể đọc log của nginx đang chạy cùng container. Grafana được cấu hình cho phép truy cập ẩn danh để tiện cho việc test demo. Khi đã chạy thành công, bạn truy cập Grafana, thêm Loki và Prometheus, sau đó tải mẫu dashboard "Loki Dashboard" và "Prometheus Dashboard" từ kho Grafana có sẵn để bắt đầu trải nghiệm khả năng giám sát toàn diện. Việc tích hợp này giúp giảm thiểu sự phân mảnh dữ liệu, giúp đội ngũ vận hành nhanh chóng xác định nguyên nhân gốc rễ của sự cố từ góc độ cả hiệu năng lẫn hành vi ứng dụng.