Virtualization

Tập trung log nhiều VPS với Grafana Loki và Promtail

Bạn đang quản lý 5, 10 hay 20 VPS? Mỗi lần có sự cố, bạn lại SSH vào từng máy, chạy journalctl hay tail -f để mò log. Cách đó tốn thời gian và dễ sót. Grafana Loki giải quyết đúng bài toán này: gom log từ nhiều VPS về một nơi, lưu trữ theo dạng nén, và truy vấn nhanh bằng ngôn ngữ LogQL ngay trên web. Bài này hướng dẫn bạn dựng hệ thống tập trung log với Loki và Promtail chạy bằng docker-compose, áp dụng cho VPS Ubuntu 24.04 và Debian 12, đủ chi tiết để làm theo là chạy.

Kiến trúc gồm ba phần: một VPS trung tâm chạy Loki (lưu trữ log) và Grafana (giao diện truy vấn), các VPS còn lại chạy Promtail (agent đọc log và gửi về Loki qua mạng). Promtail nhẹ, chỉ tốn vài chục MB RAM, nên cứ thoải mái cài trên mọi máy chủ. Toàn bộ phần khó là cấu hình đúng đường dẫn file log và label cho từng VPS.

Yêu cầu trước khi bắt đầu

  • Một VPS làm trung tâm log, tối thiểu 2 GB RAM và 40 GB NVMe SSD. Bài dùng Ubuntu 24.04 LTS, bạn cần quyền root hoặc user có sudo.
  • Các VPS cần gom log, chạy Linux (Ubuntu, Debian, AlmaLinux đều được) và có quyền cài Docker.
  • Đã cài Docker và Docker Compose v2 trên cả VPS trung tâm lẫn VPS client. Nếu chưa, xem bài cách cài Docker trên VPS Ubuntu.
  • Các VPS client phải kết nối được tới VPS trung tâm qua port 3100 (Loki) hoặc 80/443 nếu bạn đặt sau reverse proxy.

Nếu bạn chưa có VPS, thuê VPS Linux tại thueVPS là lựa chọn hợp lý: hạ tầng NVMe, IPv4 riêng tại Việt Nam và full root, đủ để dựng hệ thống này.

Kiến trúc Loki gồm những gì?

Loki được thiết kế khác hẳn Elasticsearch hay Splunk: nó không đánh index toàn bộ nội dung log, mà chỉ index các label (nhãn). Nội dung log được nén và lưu theo khối (chunk). Nhờ vậy, Loki tốn ít RAM và ổ đĩa hơn nhiều so với Elasticsearch khi cùng lượng log, phù hợp với một VPS tầm trung.

Ba thành phần chính bạn cần biết:

  • Promtail: agent chạy trên từng VPS, đọc log từ file, thêm label rồi gửi lên Loki.
  • Loki: server lưu trữ, nhận log từ Promtail, nén và lưu chunk.
  • Grafana: giao diện web để truy vấn log bằng LogQL, vẽ dashboard.

Vì Loki lưu log dạng nén và chỉ giữ index nhỏ, một VPS 4 GB RAM có thể xử lý hàng trăm GB log mỗi ngày mà vẫn nhẹ. Tuy nhiên, bạn nên cấu hình retention (thời gian giữ log) để tránh đầy ổ, ví dụ giữ 30 ngày là hợp lý cho hầu hết trường hợp.

Bước 1 - Cài đặt Loki và Grafana trên VPS trung tâm

Tạo thư mục làm việc và file docker-compose cho Loki, Grafana và một Promtail cục bộ (để gom log của chính VPS trung tâm):

mkdir -p /opt/loki && cd /opt/loki
nano docker-compose.yml

Nội dung file docker-compose.yml:

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

  promtail:
    image: grafana/promtail:3.4.2
    container_name: promtail
    restart: unless-stopped
    volumes:
      - /var/log:/var/log
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - ./promtail-config.yaml:/etc/promtail/config.yaml
    command: -config.file=/etc/promtail/config.yaml

  grafana:
    image: grafana/grafana:11.4.0
    container_name: grafana
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - ./data/grafana:/var/lib/grafana

File cấu hình Loki loki-config.yaml giữ cấu hình mặc định nhưng tăng thời gian giữ log lên 30 ngày:

nano loki-config.yaml
auth_enabled: false

server:
  http_listen_port: 3100

common:
  instance_addr: 127.0.0.1
  path_prefix: /loki
  storage:
    filesystem:
      chunks_directory: /loki/chunks
      rules_directory: /loki/rules
  replication_factor: 1
  ring:
    kvstore:
      store: inmemory

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

limits_config:
  retention_period: 720h
  allow_structured_metadata: true

compactor:
  working_directory: /loki/compactor
  retention_enabled: true

storage_config:
  filesystem:
    directory: /loki/chunks

Cấu hình Promtail cục bộ promtail-config.yaml để đọc log hệ thống và log container Docker trên chính máy trung tâm:

nano promtail-config.yaml
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: varlogs
    static_configs:
      - targets:
          - localhost
        labels:
          job: varlogs
          host: trung-tam
          __path__: /var/log/*.log

  - job_name: docker
    pipeline_stages:
      - docker: {}
    static_configs:
      - targets:
          - localhost
        labels:
          job: docker
          host: trung-tam
          __path__: /var/lib/docker/containers/*/*-json.log

Chạy toàn bộ hệ thống:

docker compose up -d

Kiểm tra các container đã chạy đúng chưa:

docker compose ps

Bạn sẽ thấy ba container loki, promtail, grafana đều ở trạng thái Up. Chờ khoảng 30 giây cho Promtail gom log đầu tiên, rồi mở trình duyệt truy cập http://<IP_VPS_TRUNG_TAM>:3000 để vào Grafana. Đăng nhập với tài khoản admin/admin, hệ thống sẽ yêu cầu đổi mật khẩu lần đầu.

Bước 2 - Thêm Loki làm datasource trong Grafana

Grafana chưa biết Loki ở đâu, bạn cần khai báo datasource. Trong giao diện Grafana, làm theo các bước sau:

  1. Vào menu ConnectionsData sourcesAdd data source.
  2. Chọn Loki.
  3. Mục URL nhập http://loki:3100 (vì Grafana chạy cùng mạng Docker với Loki).
  4. Kéo xuống mục Additional settings, đặt Maximum lines1000 để xem được nhiều log hơn mỗi lần truy vấn.
  5. Nhấn Save & test, đợi thông báo xanh "Successfully queried the Loki API".

Sau khi lưu, chuyển sang menu Explore (biểu tượng kính lúp ở sidebar), chọn datasource Loki và chạy thử truy vấn LogQL:

{job="varlogs"}

Nếu có kết quả, hệ thống đã hoạt động. Log của chính VPS trung tâm đang được gom về. Giờ chuyển sang phần chính: gom log từ các VPS khác.

Bước 3 - Cài Promtail trên các VPS client

Trên mỗi VPS cần gom log, thay vì cài Docker nặng nề, bạn cài Promtail trực tiếp bằng file nhị phân. Cách này nhẹ hơn nhiều, chỉ tốn khoảng 40 MB RAM. Tải Promtail bản mới nhất:

cd /tmp
curl -O -L "https://github.com/grafana/loki/releases/download/v3.4.2/promtail-linux-amd64.zip"
apt install unzip -y
unzip promtail-linux-amd64.zip
mv promtail-linux-amd64 /usr/local/bin/promtail
chmod +x /usr/local/bin/promtail

Tạo user riêng để chạy Promtail cho an toàn:

useradd --no-create-home --shell /usr/sbin/nologin promtail

Tạo thư mục chứa file vị trí đọc log (positions) và file cấu hình:

mkdir -p /etc/promtail /var/lib/promtail
touch /etc/promtail/config.yaml
touch /var/lib/promtail/positions.yaml
chown -R promtail:promtail /etc/promtail /var/lib/promtail

Mở file cấu hình config.yaml và sửa IP <IP_VPS_TRUNG_TAM> thành địa chỉ thật của VPS trung tâm:

nano /etc/promtail/config.yaml

Nội dung file, chú ý label host đặt tên riêng cho từng VPS để phân biệt khi truy vấn:

server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /var/lib/promtail/positions.yaml

clients:
  - url: http://<IP_VPS_TRUNG_TAM>:3100/loki/api/v1/push

scrape_configs:
  - job_name: varlogs
    static_configs:
      - targets:
          - localhost
        labels:
          job: varlogs
          host: web-01
          __path__: /var/log/*.log

  - job_name: journal
    journal:
      max_age: 12h
      labels:
        job: journal
        host: web-01
    relabel_configs:
      - source_labels: ['__journal__systemd_unit']
        target_label: 'unit'
    static_configs:
      - targets:
          - localhost
        labels:
          job: journal
          host: web-01
          __path__: ""

Với mỗi VPS khác, bạn chỉ cần đổi giá trị host (ví dụ db-01, app-02) cho dễ nhận diện. Promtail còn hỗ trợ đọc log từ systemd journal để bắt log của các service chạy bằng systemd, rất hữu ích với các ứng dụng không ghi ra file riêng.

Tạo file systemd service để Promtail tự động chạy khi khởi động:

nano /etc/systemd/system/promtail.service
[Unit]
Description=Promtail log collector
After=network-online.target

[Service]
User=promtail
Group=promtail
ExecStart=/usr/local/bin/promtail -config.file=/etc/promtail/config.yaml
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Khởi động và kích hoạt service:

systemctl daemon-reload
systemctl enable --now promtail
systemctl status promtail

Bạn sẽ thấy trạng thái active (running). Nếu không, xem log lỗi bằng lệnh:

journalctl -u promtail -f

Lặp lại bước này trên tất cả các VPS còn lại, chỉ đổi giá trị host trong config. Nhớ mở port 3100 trên firewall của VPS trung tâm để các client kết nối vào. Nếu dùng ufw, chạy:

ufw allow from <IP_VPS_CLIENT> to any port 3100 proto tcp

Cách này an toàn hơn mở cho mọi IP. Nếu bạn có nhiều VPS client với dải IP khác nhau, có thể mở theo từng IP hoặc đặt sau VPN WireGuard, chủ đề mình đã hướng dẫn trong bài WireGuard VPN trên VPS.

Bước 4 - Truy vấn log tập trung với LogQL

Sau vài phút, log từ các VPS client bắt đầu đổ về Loki. Quay lại Grafana, vào Explore và thử các truy vấn sau:

Xem toàn bộ log của VPS tên web-01:

{host="web-01"}

Xem log của riêng service Nginx trên VPS web-01:

{host="web-01",unit="nginx.service"}

Lọc log chứa từ khóa "error" trên tất cả các VPS:

{job="varlogs"} |= "error"

Đếm số log lỗi mỗi giờ trong 24 giờ qua, dùng cho dashboard cảnh báo:

sum by (host) (count_over_time({job="varlogs"} |= "error" [1h]))

LogQL gần giống PromQL nhưng dành riêng cho log. Bạn có thể kết hợp nhiều toán tử lọc: |= (chứa), != (không chứa), |~ (khớp regex). Nếu muốn gom log của ứng dụng Nginx theo dạng có cấu trúc để truy vấn theo status code, bạn cần thêm pipeline_stages với regex trong config Promtail, nhưng đó là nâng cao, mình sẽ đề cập ở phần sau.

Bước 5 - Cảnh báo và gợi ý mở rộng

Gom log mới chỉ là một nửa. Phần giá trị hơn là cảnh báo khi log chứa dấu hiệu bất thường. Trong Grafana, bạn có thể tạo alert rule từ một truy vấn LogQL: vào AlertingAlert rulesNew alert rule, chọn datasource Loki và đặt điều kiện, ví dụ số dòng log chứa "panic" hoặc "FATAL" trong 5 phút lớn hơn 0 thì gửi cảnh báo qua Telegram, email hoặc webhook.

Hệ thống này kết hợp tốt với giám sát metrics. Nếu bạn đã có Prometheus và Grafana giám sát VPS, thì gắn thêm Loki vào cùng một Grafana là hợp lý: một nơi xem metrics, một nơi xem log. Khi có sự cố, nhìn dashboard metrics để biết máy nào ngốn CPU hay RAM, rồi nhảy sang Explore để xem log chi tiết của đúng VPS đó trong cùng khung thời gian.

Nếu bạn cần gom log cho ứng dụng chạy Docker trên nhiều máy, thay vì cài Promtail thủ công từng máy như trên, có thể dùng Docker image grafana/promtail với cùng cấu hình. Nhưng với dịch vụ systemd hoặc log file thường, cách cài binary như mình hướng dẫn nhẹ và dễ quản lý hơn.

Xử lý lỗi thường gặp

Grafana báo "No data" khi truy vấn

Đầu tiên kiểm tra Promtail trên VPS client đã gửi được log chưa:

journalctl -u promtail -f

Thấy lỗi connection refused nghĩa là VPS client không kết nối được tới cổng 3100 của VPS trung tâm. Kiểm tra firewall và đường truyền:

curl -v http://<IP_VPS_TRUNG_TAM>:3100/ready

Nếu trả về ready, kết nối ổn. Kiểm tra tiếp vị trí file positions và đường dẫn log trong config có khớp không. Nếu Promtail đọc file nhưng không có label đúng, truy vấn {job="varlogs"} cũng không ra kết quả.

Dung lượng ổ đĩa VPS trung tâm tăng nhanh

Kiểm tra mức độ log đang gửi về:

du -sh /opt/loki/data/loki/chunks

Nếu tăng quá nhanh, giảm thời gian retention trong limits_config.retention_period xuống còn 168h (7 ngày) và khởi động lại Loki. Bạn cũng nên cấu hình logrotate trên các VPS client để log không phình vô hạn. Chi tiết xem bài cấu hình logrotate quản lý log hiệu quả.

Promtail không có quyền đọc journal

User promtail cần nằm trong group systemd-journal mới đọc được journal:

usermod -aG systemd-journal promtail
systemctl restart promtail

Nên chọn VPS trung tâm cấu hình bao nhiêu?

VPS trung tâm log không cần CPU quá mạnh, nhưng RAM và ổ đĩa NVMe nên ưu tiên. Loki đánh index label trên RAM, nên với khoảng 10 VPS client, mỗi máy tầm 1-2 GB log mỗi ngày, một VPS Linux 4 GB RAM là thoải mái. Nếu bạn quản lý trên 20 VPS hoặc log lớn, nên lên 8 GB RAM. Trong mọi trường hợp, dùng ổ NVMe vì Loki ghi chunk liên tục, ổ SSD thường sẽ nhanh đầy I/O. Bạn có thể tham khảo bảng giá VPS tại thueVPS để chọn gói phù hợp theo nhu cầu.

Một lưu ý nữa: nếu bạn lo ngại log nhạy cảm (mật khẩu, token) truyền qua mạng, hãy đặt Loki sau reverse proxy Nginx với TLS, hoặc chạy toàn bộ trong mạng WireGuard riêng. Log là dữ liệu quan trọng, đừng để lộ trên đường truyền trần.

Câu hỏi thường gặp

Grafana Loki có miễn phí không?

Có. Loki, Promtail và Grafana đều là phần mềm mã nguồn mở, bạn tự cài trên VPS và không mất phí bản quyền. Chi phí riêng biệt là tiền thuê VPS trung tâm lưu log.

Loki khác gì Elasticsearch?

Elasticsearch đánh index toàn bộ nội dung log nên truy vấn nhanh nhưng tốn rất nhiều RAM và ổ đĩa. Loki chỉ index label, nén nội dung log nên nhẹ hơn nhiều, phù hợp với VPS tầm trung. Đánh đổi là truy vấn full-text chậm hơn Elasticsearch.

Promtail có nặng không?

Không. Promtail chạy dưới dạng binary chỉ tốn khoảng 30-50 MB RAM mỗi máy, nhẹ hơn nhiều so với cài Docker hoặc Filebeat. Bạn có thể cài trên cả VPS 1 GB RAM mà không lo ảnh hưởng ứng dụng.

Tôi có thể gom log của Windows Server không?

Được. Loki có agent tên Promtail bản Windows, hoặc bạn dùng Alloy. Cấu hình tương tự như trên Linux, chỉ khác đường dẫn file log kiểu C:\ProgramData\.... Nếu bạn quản lý VPS Windows, xem thêm bài quản lý VPS Windows bằng PowerShell Remoting.

Giữ log bao lâu thì hợp lý?

Tùy nhu cầu. Mình đặt mặc định 30 ngày cho hệ thống production, 7 ngày cho môi trường test. Bạn chỉnh trong limits_config.retention_period của file config Loki rồi khởi động lại container.

Bài viết liên quan

Lưu ý: Bài viết mang tính tham khảo, tổng hợp kiến thức chung. Mỗi hệ thống, hạ tầng và nhu cầu có đặc thù riêng, nên kiểm thử trong môi trường an toàn và tham vấn kỹ sư trước khi triển khai thực tế.