Giám sát Syslog mạng tập trung với Rsyslog và Grafana Loki

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

Bắt đầu nhanh: Triển khai hoàn tất trong 5 phút

Sáu tháng trước, đội ngũ hạ tầng của chúng tôi đã gỡ bỏ hoàn toàn một cụm Elasticsearch gồm 3 node – hệ thống vốn ngốn tới 48 GB RAM chỉ để duy trì bộ nhớ đệm cho search index. Thay thế vào đó, chúng tôi triển khai Grafana Loki và Rsyslog. Kiến trúc mới xử lý mượt mà khoảng 8.500 sự kiện syslog mỗi giây từ hơn 120 thiết bị mạng—bao gồm switch Cisco Catalyst 9300, cụm FortiGate 200F và router biên MikroTik CCR—trong khi chỉ tiêu tốn chưa đầy 4 GB RAM.

Bạn hoàn toàn có thể dựng một pipeline thu thập log tương tự trên Ubuntu 22.04 hoặc 24.04 LTS chỉ trong vài phút bằng Docker Compose.

Bước 1: Triển khai Loki và Grafana

Đầu tiên, hãy tạo một thư mục dự án có tên network-logging và lưu tệp docker-compose.yml sau:

version: "3.8"

services:
  loki:
    image: grafana/loki:2.9.4
    container_name: loki
    ports:
      - "3100:3100"
    command: -config.file=/etc/loki/local-config.yaml
    volumes:
      - ./loki-data:/loki
    restart: unless-stopped

  promtail:
    image: grafana/promtail:2.9.4
    container_name: promtail
    volumes:
      - /var/log/network:/var/log/network:ro
      - ./promtail-config.yaml:/etc/promtail/config.yaml:ro
    command: -config.file=/etc/promtail/config.yaml
    restart: unless-stopped

  grafana:
    image: grafana/grafana:10.4.1
    container_name: grafana
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=adminpass
    restart: unless-stopped

Bước 2: Gắn Rsyslog vào cổng UDP/TCP 514

Tiếp theo, cấu hình Rsyslog ở cấp hệ điều hành (host) để tiếp nhận lưu lượng mạng gửi đến. Hãy dán đoạn cấu hình sau vào tệp mới tại /etc/rsyslog.d/10-network-input.conf:

module(load="imudp")
input(type="imudp" port="514")

module(load="imtcp")
input(type="imtcp" port="514")

# Phân tách log nhận được theo IP thiết bị: /var/log/network/<DEVICE_IP>/syslog.log
template(name="NetLogPath" type="string" string="/var/log/network/%fromhost-ip%/syslog.log")
*.* ?NetLogPath
& stop

Thiết lập quyền truy cập thư mục và khởi động lại dịch vụ:

sudo mkdir -p /var/log/network
sudo chmod -R 755 /var/log/network
sudo systemctl restart rsyslog

Bước 3: Trỏ Promtail đến các tệp Syslog

Promtail sẽ theo dõi (tail) các tệp log thô trên đĩa, gắn thêm nhãn metadata và đẩy các batch nén dữ liệu vào Loki. Lưu cấu hình này thành promtail-config.yaml trong thư mục dự án của bạn:

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: network_syslog
    static_configs:
      - targets:
          - localhost
        labels:
          job: network_devices
          __path__: /var/log/network/*/*.log
    pipeline_stages:
      - regex:
          expression: '^/var/log/network/(?P<device_ip>[^/]+)/.*\.log$'
          source: filename
      - labels:
          device_ip: ""

Khởi chạy các container:

docker compose up -d

Mở Grafana tại http://<your-server-ip>:3000. Đăng nhập với tài khoản admin / adminpass, thêm Loki (http://loki:3100) làm nguồn dữ liệu (data source), sau đó truy vấn luồng log với câu lệnh {job="network_devices"}.

Đi sâu vào chi tiết: Kiến trúc và Cơ chế Pipeline

Các công cụ truyền thống như Elasticsearch hay OpenSearch thường phân tích cú pháp chuỗi văn bản nhận được thành các inverted index. Cách tiếp cận này hiệu quả cho các câu truy vấn tìm kiếm tùy biến. Tuy nhiên, nó nhanh chóng bộc lộ điểm yếu khi các firewall phát sinh tới 40.000 sự kiện drop gói tin mỗi giây trong các đợt rà quét diện rộng trên Internet. Mức sử dụng RAM tăng vọt, ổ cứng nghẽn I/O liên tục, và việc duy trì cụm máy chủ biến thành một công việc toàn thời gian đầy áp lực.

Tại sao nên dùng Rsyslog làm cổng tiếp nhận tuyến đầu?

Rsyslog được viết bằng C và hoạt động sát tầng kernel ở không gian người dùng (user space). Nhờ đó, nó có khả năng tiếp nhận các gói UDP tần suất cao hiệu quả hơn rất nhiều so với các collector viết bằng Java hay Go như Logstash hay Vector. Ngay cả khi một switch truy cập bị hiện tượng link flapping dữ dội, Rsyslog vẫn lưu giữ các dòng log an toàn trong bộ đệm vòng (ring buffer) trên RAM mà không làm quá tải các nhân CPU.

Triết lý của Loki: Đánh chỉ mục nhãn, không đánh chỉ mục nội dung

Loki đảo ngược hoàn toàn mô hình đánh chỉ mục truyền thống. Nó giữ nguyên phần thân log, nén gzip thành từng chunk rồi ghi trực tiếp xuống đĩa hoặc lưu trữ tương thích S3. Loki chỉ đánh chỉ mục các nhãn metadata của luồng: job, device_ip và environment.

Lựa chọn thiết kế này đã giúp chúng tôi giảm dung lượng lưu trữ từ 1,2 TB xuống chỉ còn khoảng 140 GB mỗi tháng. Tốc độ truy vấn vẫn rất nhanh do Grafana phân tán việc lọc theo kiểu grep song song qua các ranh giới chunk dữ liệu.

Hướng dẫn cấu hình thiết bị

Cấu hình các thiết bị mạng của bạn để chuyển tiếp sự kiện về máy chủ Ubuntu qua cổng 514:

# Cisco IOS / IOS-XE
logging host 192.168.10.50 transport udp port 514
logging trap informational
logging facility local6
logging source-interface GigabitEthernet0/0

# Fortinet FortiGate (CLI)
config log syslogd setting
    set status enable
    set server "192.168.10.50"
    set mode udp
    set port 514
    set facility local7
    set format default
end

# MikroTik RouterOS v7
/system logging action add name=central-syslog target=remote remote=192.168.10.50 remote-port=514 src-address=192.168.10.1
/system logging add action=central-syslog topics=critical,error,warning,info

Sử dụng nâng cao: Phân tích cú pháp và Cảnh báo với LogQL

Các luồng log văn bản thô sẽ phát huy sức mạnh vượt trội khi bạn phân tích cú pháp và lọc chúng theo yêu cầu ngay trong Grafana.

Trích xuất trường dữ liệu khi đọc (Extract on Read)

Các dòng syslog của Cisco tuân theo định dạng rất rõ ràng: %FACILITY-SEVERITY-MNEMONIC: Description. Thay vì phải định nghĩa schema mapping từ trước, bạn có thể phân tích các trường ngay tại thời điểm truy vấn bằng pattern matching trong LogQL:

{device_ip="192.168.10.1"} 
  |= "%LINK-3-UPDOWN:"
  | pattern "<_> %LINK-3-UPDOWN: Interface <interface>, changed state to <status>"

Câu truy vấn này trích xuất trực tiếp các trường interface và status trong tích tắc. Bạn có thể đưa thẳng chúng vào một panel dạng bảng (table panel) trên Grafana để nhận diện các cổng mạng đang bị chập chờn (flapping) trong toàn bộ khu vực campus.

Tạo chuỗi số liệu (Metric Stream) từ log thô

Bạn cũng có thể tổng hợp log thô thành các chuỗi thời gian (time series) tương tự như Prometheus:

sum by (device_ip) (
  rate({job="network_devices"} |= "action=deny" [1m])
)

Biểu thức này tính toán số lượng gói tin bị firewall drop mỗi giây trên từng thiết bị. Bất kỳ sự tăng đột biến nào cũng sẽ giúp phát hiện các cuộc quét mã độc nội bộ hay tấn công brute-force ở vùng biên chỉ trong vài giây.

Cấu hình quy tắc cảnh báo thời gian thực

Phát hiện sự cố định tuyến tức thì bằng cách thêm quy tắc cảnh báo vào cấu hình Loki của bạn:

groups:
  - name: network-alerts
    rules:
      - alert: BGPNeighborDown
        expr: |
          count_over_time({job="network_devices"} |= "%BGP-5-ADJCHANGE:" |= "Down" [2m]) > 0
        for: 0m
        labels:
          severity: critical
        annotations:
          summary: "Phiên BGP peer bị ngắt kết nối trên {{ $labels.device_ip }}"

Kinh nghiệm thực tế: Gia cố và Tối ưu hóa cho Production

Vận hành pipeline này trong môi trường thực tế đã làm lộ ra ba điểm nghẽn hiệu năng mà bạn nên xử lý sớm.

1. Tránh sử dụng nhãn có độ biến thiên cao (High-Cardinality Labels)

Tuyệt đối không trích xuất các giá trị động như địa chỉ IP client từ xa, địa chỉ MAC hay cổng TCP thành các nhãn trong Promtail. Loki tạo ra một stream chỉ mục riêng biệt cho mỗi tổ hợp nhãn duy nhất. Mười nghìn địa chỉ IP client riêng biệt sẽ nhanh chóng tạo ra mười nghìn stream, khiến chỉ mục của Loki phình to bất thường và kéo tụt tốc độ tìm kiếm. Hãy chỉ dùng các nhãn có độ biến thiên thấp như site, role và device_ip.

2. Tối ưu bộ đệm Socket UDP cho Rsyslog

Khi có lưu lượng đột biến, Linux kernel sẽ âm thầm drop các gói tin UDP gửi đến nếu bộ đệm nhận (receive buffer) của hệ điều hành bị bão hòa. Kiểm tra số lượng gói tin bị drop bằng lệnh sau:

netstat -su | grep "receive errors"

Nếu con số này liên tục tăng, hãy nâng bộ đệm nhận của kernel lên 25 MB trong /etc/sysctl.d/99-syslog.conf:

net.core.rmem_default = 26214400
net.core.rmem_max = 26214400

Áp dụng giá trị sysctl mới mà không cần khởi động lại máy chủ:

sudo sysctl -p /etc/sysctl.d/99-syslog.conf

3. Thiết lập chính sách lưu trữ (Retention) trong Compactor

Các thiết bị mạng tạo ra khối lượng log vận hành khổng lồ. Hãy đặt khoảng thời gian lưu trữ rõ ràng trong loki-config.yaml để dọn dẹp các chunk cũ và giải phóng dung lượng ổ đĩa:

compactor:
  working_directory: /loki/compactor
  compactor_ring:
    kvstore:
      store: inmemory
  retention_enabled: true

schema_config:
  configs:
    - from: 2024-01-01
      store: tsdb
      object_store: filesystem
      schema: v13
      index:
        prefix: index_
        period: 24h

limits_config:
  retention_period: 30d

Cấu hình này giữ cho dung lượng ổ cứng NVMe luôn trong tầm kiểm soát, đồng thời vẫn bảo đảm 30 ngày lưu trữ dữ liệu kiểm toán sạch sẽ, dễ tra cứu để phục vụ tuân thủ quy định.

Share: