Monitoring

Thu thập log tập trung cho cụm VPS nhỏ bằng Grafana Loki và Vector

Hướng dẫn xây dựng hệ thống thu thập log tập trung cho cụm VPS nhỏ bằng Grafana Loki và Vector: thay thế ELK nặng nề bằng stack siêu nhẹ, tốn ít RAM.

Thu thập log tập trung cho cụm VPS nhỏ bằng Grafana Loki và Vector
MỤC LỤC

Khi hạ tầng mở rộng từ một máy chủ đơn lẻ lên một cụm gồm vài VPS phục vụ các tầng ứng dụng khác nhau (Web server, API backend, Database, Queue worker), việc SSH vào từng máy để kiểm tra file log bằng tail -f hoặc journalctl trở nên chậm chạp và dễ bỏ sót thông tin khi xảy ra sự cố liên chuỗi.

Tuy nhiên, các giải pháp thu thập log tập trung truyền thống như ELK Stack (Elasticsearch, Logstash, Kibana) đòi hỏi cấu hình phần cứng rất lớn, tiêu tốn từ 4GB đến 8GB RAM chỉ để duy trì bộ máy chỉ mục. Với các cụm máy chủ quy mô nhỏ, sự kết hợp giữa Vector (bộ gom log siêu nhẹ viết bằng Rust) và Grafana Loki (hệ thống lưu trữ log tối ưu theo nhãn) mang lại khả năng quản lý log tập trung mượt mà trên các gói VPS chỉ từ 1GB đến 2GB RAM. Đây cũng là một minh chứng tiêu biểu cho bài toán cân đối giữa chi phí bản quyền SaaS và chi phí hạ tầng trong tiêu chí tự host công cụ nội bộ trên VPS.

Kiến trúc thu thập log cho cụm VPS với Vector và Grafana Loki

1. Tại sao ELK quá nặng và Grafana Loki là lựa chọn phù hợp cho VPS nhỏ?

Để lựa chọn đúng công cụ, người vận hành cần hiểu rõ sự khác biệt căn bản về mặt kỹ thuật giữa cơ chế lập chỉ mục của Elasticsearch và Grafana Loki.

Sự cồng kềnh của Elasticsearch (ELK Stack)

Elasticsearch hoạt động dựa trên cấu trúc Inverted Index (chỉ mục đảo). Khi một dòng log được gửi vào:

  1. Bộ phân tích (Analyzer) sẽ bóc tách toàn bộ câu chữ thành từng từ khóa riêng lẻ (Tokens).
  2. Hệ thống lập chỉ mục cho từng từ khóa đó để phục vụ tìm kiếm văn bản toàn phần (Full-text Search).

Cơ chế này mang lại khả năng tìm kiếm từ ngữ cực nhanh, nhưng cái giá phải trả về tài nguyên là rất lớn:

  • Ngốn bộ nhớ RAM: Elasticsearch chạy trên nền Java Virtual Machine (JVM). Để xử lý luồng log liên tục mà không bị dừng đột ngột do bộ thu gom rác (GC pause), JVM yêu cầu heap memory tối thiểu từ 2GB đến 4GB, đẩy tổng RAM thực tế của máy chủ lên 6GB – 8GB.
  • Phình to dung lượng ổ đĩa: Dung lượng của tệp chỉ mục Inverted Index thường tương đương 50% đến 120% kích thước của chính file log gốc. Nếu bạn có 10GB log, hệ thống cần thêm 5GB đến 12GB dung lượng đĩa chỉ để chứa chỉ mục.

Triết lý thiết kế tinh gọn của Grafana Loki

Grafana Loki được phát triển với khẩu hiệu "Like Prometheus, but for logs". Loki giải quyết bài toán log theo hướng hoàn toàn khác:

  1. Không lập chỉ mục nội dung log: Thay vì phân tích từng từ trong dòng log, Loki chỉ lập chỉ mục cho các cặp nhãn siêu dữ liệu (Metadata Labels). Ví dụ: host="vps-web-01", app="nginx", env="production".
  2. Nén dữ liệu dạng khối (Chunks): Toàn bộ nội dung văn bản thuần của các dòng log cùng nhãn được gom lại thành các khối tệp tin nén bằng thuật toán Snappy hoặc Gzip, sau đó lưu trực tiếp vào ổ đĩa cứng hoặc Object Storage (Cloudflare R2 / AWS S3).
  3. Quét dữ liệu khi truy vấn (Grep on read): Khi bạn tìm kiếm một từ khóa lỗi, Loki sử dụng nhãn để khoanh vùng đúng khối dữ liệu của máy chủ đó, rồi thực thi thao tác quét luồng tương tự như lệnh grep trên Linux ở tốc độ cao.

Nhờ triết lý này, kích thước chỉ mục của Loki chỉ chiếm chưa đến 1% dung lượng log, giúp máy chủ Loki hoạt động ổn định và mượt mà trên một VPS chỉ có 1GB đến 2GB RAM.

Bảng so sánh tài nguyên trên cụm 3 – 5 VPS

Tiêu chí kỹ thuậtELK Stack (Elasticsearch + Filebeat)Grafana Loki + Vector
RAM máy chủ trung tâm4GB – 8GB+ (Yêu cầu JVM Heap)500MB – 1.5GB RAM
RAM trên từng VPS vệ tinh80MB – 150MB (Filebeat / Logstash)15MB – 35MB (Vector viết bằng Rust)
Kích thước chỉ mục lưu trữ50% – 100% dung lượng logDưới 1% dung lượng log
Chi phí hạ tầng VPSTốn kém (cần VPS lớn 8GB RAM)Tiết kiệm (chạy chung trên VPS 2GB RAM)
Khả năng trực quan hóaKibanaGrafana (tích hợp chung với Metrics)

2. Kiến trúc luồng log: VPS Vệ tinh (Vector) → VPS Trung tâm (Loki)

Mô hình triển khai cho cụm từ 3 đến 5 máy chủ VPS được phân định thành hai vai trò rõ ràng:

  1. Máy chủ Log trung tâm (Central Logging VPS):
  • Chạy dịch vụ Grafana Loki để tiếp nhận, nén và lưu trữ các khối log.
  • Chạy dịch vụ Grafana để quản trị viên truy vấn, theo dõi bảng điều khiển và thiết lập cảnh báo.
  • Cổng API tiếp nhận log của Loki là 3100. Để đảm bảo an toàn tuyệt đối, cổng này chỉ được phép lắng nghe trên mạng riêng ảo nội bộ, bạn có thể tham khảo thiết lập Cloudflare Tunnel hay WireGuard cho truy cập nội bộ để không mở cổng ra Internet công cộng.
  1. Các máy chủ vệ tinh (Satellite / Edge VPS):
  • Mỗi máy chủ chỉ cần cài đặt một tiến trình nền duy nhất là Vector Agent.
  • Vector đọc trực tiếp các luồng log:
  • Log từ các Docker Container thông qua Docker Socket /var/run/docker.sock.
  • Log từ các dịch vụ hệ thống thông qua systemd-journald.
  • Các file log văn bản thuần nếu có (như /var/log/nginx/access.log).
  • Vector tự động chuẩn hóa dữ liệu, gắn thêm nhãn nhận diện máy chủ (ví dụ host="vps-api-02") và gửi qua giao thức HTTP POST về cổng 3100 của Loki.

3. Cài đặt cụm trung tâm: Grafana Loki và Grafana

Trên máy chủ VPS được chọn làm trung tâm quản lý log, bạn tạo thư mục triển khai và file cấu hình Docker Compose.

Tạo thư mục làm việc:

bash
mkdir -p /opt/loki-stack/config /opt/loki-stack/data/loki
cd /opt/loki-stack

Tạo file cấu hình Loki: config/loki-config.yaml

Loki cần một file cấu hình định nghĩa cơ chế lưu trữ cục bộ (Filesystem) và chính sách dọn dẹp log:

yaml
auth_enabled: false

server:
  http_listen_port: 3100
  grpc_listen_port: 9096

common:
  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:
  reject_old_samples: true
  reject_old_samples_max_age: 168h # 7 ngày
  retention_period: 14d            # Giữ log tối đa 14 ngày

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

Điểm quan trọng trong cấu hình trên:

  • schema_config sử dụng tsdb: Định dạng TSDB mới của Loki giúp tăng tốc độ tra cứu nhãn và tiêu thụ cực ít bộ nhớ so với cấu hình BoltDB cũ.
  • compactor.retention_enabled: true: Kích hoạt tiến trình dọn dẹp log tự động. Các khối log cũ hơn 14 ngày (14d) sẽ tự động được xóa khỏi ổ đĩa để giải phóng dung lượng.

Tạo file docker-compose.yml

yaml
services:
  loki:
    image: grafana/loki:3.0.0
    container_name: loki
    restart: unless-stopped
    ports:
      - "127.0.0.1:3100:3100" # Chỉ lắng nghe trên localhost hoặc mạng riêng nội bộ
    volumes:
      - ./config/loki-config.yaml:/etc/loki/local-config.yaml:ro
      - ./data/loki:/loki
    command: -config.file=/etc/loki/local-config.yaml
    deploy:
      resources:
        limits:
          memory: 1024M

  grafana:
    image: grafana/grafana:11.0.0
    container_name: grafana
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=MatKhauQuanTriRatManh123
      - GF_USERS_ALLOW_SIGN_UP=false
    volumes:
      - ./data/grafana:/var/lib/grafana
    deploy:
      resources:
        limits:
          memory: 512M

Khởi động cụm dịch vụ:

bash
docker compose up -d

Sau khi khởi động, truy cập Grafana qua cổng 3000 (đặt sau Nginx Reverse Proxy có SSL). Vào mục Connections -> Data sources -> Add data source, chọn Loki và điền URL: http://loki:3100. Nhấn Save & test để xác nhận kết nối thành công.

4. Cài đặt Vector agent trên các máy chủ VPS vệ tinh

Trên từng VPS vệ tinh cần đẩy log về trung tâm, Vector là lựa chọn tối ưu vì được viết bằng ngôn ngữ Rust, không có tiến trình Garbage Collection làm lag CPU và chiếm chưa tới 35MB RAM.

Cài đặt Vector trực tiếp trên Ubuntu/Debian

Chạy lệnh cài đặt chính thức từ kho gói của Vector:

bash
curl -1sLf 'https://repositories.timber.io/public/vector/cfg/setup/bash.deb.sh' | sudo -E bash
sudo apt-get install -y vector

Cấu hình pipeline thu thập: /etc/vector/vector.yaml

Vector sử dụng mô hình Pipeline gồm 3 khối: Sources (nguồn log) → Transforms (tiền xử lý dữ liệu) → Sinks (đích đẩy đến).

Chỉnh sửa file cấu hình /etc/vector/vector.yaml:

yaml
# 1. NGUỒN THU THẬP DỮ LIỆU
sources:
  # Thu thập log của toàn bộ Docker container trên VPS này
  docker_source:
    type: docker_logs

  # Thu thập log hệ thống Linux từ systemd
  journal_source:
    type: journald
    exclude_units:
      - "vector.service"

# 2. XỬ LÝ VÀ CHUẨN HÓA DỮ LIỆU (TRANSFORMS)
transforms:
  process_docker:
    type: remap
    inputs:
      - docker_source
    source: |
      .host = "vps-web-01"                  # Đặt tên định danh cho VPS này
      .job = "docker"
      .container = .container_name

  process_journal:
    type: remap
    inputs:
      - journal_source
    source: |
      .host = "vps-web-01"
      .job = "systemd"
      .service = .SYSTEMD_UNIT || "kernel"

# 3. ĐÍCH GỬI LOG VỀ LOKI TRUNG TÂM (SINKS)
sinks:
  loki_sink:
    type: loki
    inputs:
      - process_docker
      - process_journal
    endpoint: "http://10.8.0.1:3100"       # IP nội bộ của VPS trung tâm chạy Loki
    compression: gzip                      # Nén dữ liệu trước khi truyền qua mạng
    encoding:
      codec: text
    labels:
      host: "{{ host }}"
      job: "{{ job }}"
      container: "{{ container }}"
      service: "{{ service }}"

Khởi động và kích hoạt dịch vụ Vector:

bash
sudo systemctl restart vector
sudo systemctl enable vector

Kiểm tra trạng thái hoạt động:

bash
sudo systemctl status vector
# Xem log của chính Vector để xác nhận kết nối tới Loki thành công:
journalctl -u vector -f

Nếu cấu hình đúng, bạn sẽ thấy thông báo Vector đã kết nối thành công tới endpoint của Loki và bắt đầu gửi các đợt dữ liệu (batches) được nén bằng gzip.

5. Thực hành tra cứu sự cố với ngôn ngữ LogQL trên Grafana

Sau khi các máy chủ vệ tinh đã đẩy log về Loki, bạn mở giao diện Grafana, truy cập mục Explore và chọn Data Source là Loki. Tại đây, bạn sử dụng ngôn ngữ LogQL để truy vấn.

Lọc dữ liệu theo nhãn luồng (Stream Selector)

Cú pháp cơ bản bắt đầu bằng việc chỉ định nhãn trong dấu ngoặc nhọn {}:

text
# Xem toàn bộ log của máy chủ web 01
{host="vps-web-01"}

# Xem log của một container cụ thể trên máy chủ API
{host="vps-api-02", container="payment-service"}

Nhờ cơ chế lập chỉ mục nhãn, câu lệnh trên sẽ trả về kết quả gần như tức thì vì Loki chỉ trỏ đúng vào khối dữ liệu của container đó, bỏ qua hàng triệu dòng log của các dịch vụ khác.

Lọc dòng theo chuỗi ký tự (Line Filter)

Bạn có thể kết hợp tìm kiếm chuỗi nội dung văn bản tương tự như lệnh grep:

  • |= : Dòng có chứa chuỗi ký tự
  • != : Dòng không chứa chuỗi ký tự
  • |~ : Khớp biểu thức chính quy (Regex)
  • !~ : Không khớp biểu thức chính quy

Ví dụ thực tế:

text
# Tìm tất cả các dòng log có chứa mã lỗi 500 trên VPS web
{host="vps-web-01", job="docker"} |= " 500 "

# Tìm lỗi kết nối cơ sở dữ liệu nhưng loại trừ các thông báo healthcheck định kỳ
{job="docker"} |= "database" != "healthcheck"

Phân tích log định dạng JSON (JSON Parser)

Nếu ứng dụng của bạn ghi log ở định dạng cấu trúc JSON (như chuẩn log của Node.js Winston, Go Zap hay Python Loguru):

json
{"level": "error","ts": 1712912400,"msg": "Payment failed","user_id": 4521,"status": 502}

Bạn có thể dùng parser | json của LogQL để trích xuất trực tiếp các trường dữ liệu và lọc theo giá trị số:

text
{container="payment-service"} | json | status >= 500 | level = "error"

Loki sẽ tự động bóc tách trường status và level trong từng dòng JSON để đối chiếu điều kiện, giúp việc khoanh vùng lỗi giao dịch diễn ra chỉ trong vài giây.

Đếm tần suất lỗi phục vụ biểu đồ và cảnh báo (Metric Queries)

LogQL cho phép biến đổi các dòng log văn bản thành các chỉ số số học (metrics) theo thời gian bằng hàm rate() hoặc count_over_time():

text
# Tính số lượng lỗi 500 phát sinh mỗi giây trong khoảng thời gian 5 phút gần nhất
sum by (host) (rate({job="docker"} |= " 500 " [5m]))

Câu truy vấn này có thể được gắn thẳng vào một Panel biểu đồ trên Grafana Dashboard hoặc dùng làm điều kiện kích hoạt thông báo tự động (Grafana Alerting) gửi tin nhắn cảnh báo về Telegram/Slack khi tần suất lỗi vượt ngưỡng 5 lỗi/phút.

Với kiến trúc kết hợp giữa Grafana Loki và Vector, bạn sở hữu một hệ thống thu thập và phân tích log tập trung chuyên nghiệp, linh hoạt và toàn diện cho cụm VPS nội bộ mà không cần phải chi trả hàng trăm USD tiền bản quyền SaaS hay đầu tư cụm máy chủ RAM lớn cho Elasticsearch. Kết hợp hệ thống này với giải pháp vận hành Uptime Kuma trên VPS để giám sát tính sẵn sàng của endpoint, bạn sẽ có một bức tranh hoàn chỉnh về tình trạng sức khỏe và nhật ký hoạt động của toàn bộ hạ tầng.

Nội dung hướng dẫn này có hữu ích với hệ thống của bạn không?

Chia sẻ bài viết hữu ích

Gửi bài viết này cho đồng nghiệp

Đọc tiếp

Bài nên đọc tiếp

Xem tất cả bài về Monitoring