0

Lab 9.6 - Xây dựng hệ thống Centralized Logging với Fluent Bit, Loki và Grafana

Phần 6 - Best Practices về Logging trong Kubernetes Production

Sau khi hoàn thành các phần trước, chúng ta đã xây dựng được một hệ thống Logging hoàn chỉnh:

  • Fluent Bit thu thập log.
  • Loki lưu trữ log.
  • Grafana tìm kiếm và phân tích log.
  • DevOps có thể kết hợp Metrics, Alerts và Logs để điều tra sự cố.

Tuy nhiên, triển khai được một hệ thống Logging mới chỉ là bước khởi đầu.

Trong môi trường Production, cách ghi log cũng quan trọng không kém cách thu thập log.

Một ứng dụng ghi log không đúng cách sẽ khiến việc điều tra sự cố trở nên rất khó khăn, dù bạn có sử dụng Fluent Bit, Loki hay Grafana.

Trong phần cuối của Lab này, chúng ta sẽ tìm hiểu các Best Practices khi xây dựng hệ thống Logging trên Kubernetes.


Mục tiêu của phần này

Sau khi hoàn thành phần này, bạn sẽ:

  • Hiểu các nguyên tắc ghi log trong Kubernetes.
  • Biết cách thiết kế log dễ tìm kiếm và dễ phân tích.
  • Hiểu các mức Log Level.
  • Tránh những lỗi phổ biến khi ghi log.
  • Chuẩn bị cho môi trường Production.

1. Ghi log ra stdout thay vì ghi vào file

Đây là nguyên tắc quan trọng nhất khi chạy ứng dụng trong Kubernetes.

Nhiều lập trình viên vẫn có thói quen ghi log vào file:

logs/application.log

logs/error.log

Điều này hoạt động tốt trên máy chủ truyền thống.

Tuy nhiên, trong Kubernetes, Container có tính chất ephemeral (tồn tại tạm thời).

Ví dụ:

kubectl delete pod todo-backend

Ngay khi Pod bị xóa:

  • Container biến mất.
  • File log cũng biến mất.

Nếu DevOps chưa kịp sao lưu log, toàn bộ thông tin phục vụ điều tra sự cố sẽ mất theo.

Thay vào đó, hãy để ứng dụng ghi log ra Console:

log.info("Create Todo successfully");

log.error("Database connection timeout");

Spring Boot sẽ ghi log ra:

stdout

Container Runtime sẽ lưu log vào:

/var/log/containers

Fluent Bit sẽ tự động thu thập và gửi log tới Loki.

Đây là cách hoạt động chuẩn của hầu hết các ứng dụng chạy trên Kubernetes.


2. Ghi log có cấu trúc (Structured Logging)

Một lỗi phổ biến là ghi log dưới dạng văn bản tự do.

Ví dụ:

Something went wrong

Nhìn vào log này, chúng ta không biết:

  • Lỗi gì?
  • API nào?
  • Người dùng nào?
  • Request nào?

Một log tốt nên chứa đầy đủ thông tin.

Ví dụ:

2026-08-05 10:15:08 ERROR POST /api/todos userId=15 Database connection timeout

Tốt hơn nữa là sử dụng JSON Logging:

{
  "timestamp": "2026-08-05T10:15:08Z",
  "level": "ERROR",
  "service": "todo-api",
  "method": "POST",
  "path": "/api/todos",
  "status": 500,
  "message": "Database connection timeout"
}

Log có cấu trúc giúp:

  • Dễ tìm kiếm.
  • Dễ thống kê.
  • Dễ phân tích bằng LogQL.

Trong các hệ thống Production hiện nay, JSON Logging gần như là tiêu chuẩn.


3. Sử dụng Log Level hợp lý

Không phải mọi thông tin đều nên được ghi với mức ERROR.

Thông thường, chúng ta sử dụng các mức sau:

Level Ý nghĩa
TRACE Thông tin rất chi tiết, dùng để debug
DEBUG Phục vụ quá trình phát triển
INFO Hoạt động bình thường của hệ thống
WARN Có dấu hiệu bất thường nhưng chưa gây lỗi
ERROR Một thao tác thất bại nhưng ứng dụng vẫn tiếp tục chạy

Ví dụ:

log.info("Application started");

log.warn("Response time is above 2 seconds");

log.error("Cannot connect to PostgreSQL");

Trong môi trường Production:

  • TRACE và DEBUG thường bị tắt.
  • INFO, WARN và ERROR được giữ lại.

Điều này giúp giảm lượng log cần lưu trữ.


4. Không ghi thông tin nhạy cảm vào log

Một trong những lỗi nghiêm trọng nhất là ghi dữ liệu nhạy cảm vào log.

Ví dụ:

Password=123456

JWT=eyJhbGciOi...

CreditCard=4111111111111111

Nếu Loki hoặc Grafana bị truy cập trái phép, các dữ liệu này có thể bị lộ.

Những thông tin không nên ghi vào log bao gồm:

  • Mật khẩu.
  • Access Token.
  • Refresh Token.
  • API Key.
  • Số thẻ tín dụng.
  • Mã OTP.
  • Dữ liệu cá nhân không cần thiết.

Thay vì:

Login failed

password=123456

Hãy ghi:

Login failed

username=admin

hoặc:

Authentication failed

Đảm bảo log chỉ chứa những thông tin cần thiết cho việc điều tra sự cố.


5. Gắn Correlation ID cho mỗi Request

Trong hệ thống Microservices, một Request có thể đi qua nhiều Service.

Ví dụ:

Frontend

↓

API Gateway

↓

Todo Service

↓

User Service

↓

Notification Service

Nếu không có Correlation ID, rất khó xác định các log thuộc cùng một Request.

Giải pháp là sinh một ID duy nhất.

Ví dụ:

requestId=9f4d62c1

Mọi Service đều ghi cùng ID này.

Ví dụ:

INFO requestId=9f4d62c1 Call User Service

INFO requestId=9f4d62c1 Query Database

ERROR requestId=9f4d62c1 Timeout PostgreSQL

Khi tìm kiếm:

9f4d62c1

Grafana sẽ hiển thị toàn bộ hành trình của Request.

Đây là kỹ thuật rất phổ biến trong các hệ thống Microservices.


6. Không ghi quá nhiều log

Log không phải càng nhiều càng tốt.

Ví dụ:

for (...) {

    log.info("Loop");

}

Nếu vòng lặp chạy 100.000 lần, hệ thống sẽ sinh 100.000 dòng log.

Hậu quả:

  • Tăng dung lượng lưu trữ.
  • Giảm hiệu năng.
  • Khó tìm thông tin quan trọng.

Hãy chỉ ghi log khi thực sự cần thiết.


7. Ghi log đủ ngữ cảnh

Một log tốt cần trả lời được các câu hỏi:

  • Có chuyện gì xảy ra?
  • Xảy ra ở đâu?
  • Với Request nào?
  • Với API nào?

Ví dụ chưa tốt:

Database Error

Ví dụ tốt hơn:

POST /api/todos

Database connection timeout

userId=15

Càng nhiều ngữ cảnh phù hợp, việc điều tra sự cố càng nhanh.


8. Thiết lập thời gian lưu trữ Log

Không phải log nào cũng cần lưu mãi mãi.

Ví dụ:

Môi trường Thời gian lưu
Development 3–7 ngày
Staging 7–14 ngày
Production 30–90 ngày (tùy yêu cầu)

Nếu lưu log quá lâu:

  • Tăng chi phí lưu trữ.
  • Giảm hiệu năng truy vấn.

Loki hỗ trợ cấu hình Retention để tự động xóa log cũ theo chính sách của tổ chức.


9. Sử dụng Label hợp lý

Loki tìm kiếm dựa trên Label.

Ví dụ:

namespace="todo-app"

app="todo-backend"

container="backend"

environment="production"

Các Label nên:

  • Ổn định theo thời gian.
  • Có số lượng giá trị giới hạn.
  • Phản ánh thông tin quan trọng để lọc log.

Không nên sử dụng các giá trị thay đổi liên tục (high cardinality) như:

requestId

sessionId

userId

làm Label, vì sẽ làm tăng số lượng Log Stream và ảnh hưởng đến hiệu năng của Loki.

Những thông tin này nên nằm trong nội dung log, không phải trong Label.


10. Quy trình xử lý sự cố trong Production

Đến đây, chúng ta đã có đầy đủ các công cụ cần thiết.

Một quy trình xử lý sự cố điển hình sẽ như sau:

                 Người dùng báo lỗi
                        │
                        ▼
              Alertmanager gửi cảnh báo
                        │
                        ▼
             Kiểm tra Grafana Dashboard
                        │
                        ▼
          Phát hiện Metrics bất thường
                        │
                        ▼
              Mở Grafana Explore
                        │
                        ▼
             Truy vấn Log bằng LogQL
                        │
                        ▼
             Xác định Root Cause
                        │
                        ▼
              Khắc phục sự cố
                        │
                        ▼
               Alert chuyển Resolved

Đây cũng chính là quy trình mà nhiều đội ngũ DevOps sử dụng trong thực tế.


Tổng kết Lab 9

Sau Lab 9, chúng ta đã hoàn thiện mảnh ghép cuối cùng của Observability.

             Kubernetes Cluster
                     │
                     ▼
              Spring Boot App
                     │
        ┌────────────┼────────────┐
        │            │            │
        ▼            ▼            ▼
    Metrics        Logs        Alerts
        │            │            │
        ▼            ▼            ▼
 Prometheus       Loki     Alertmanager
        └────────────┼────────────┘
                     ▼
                  Grafana
                     │
                     ▼
          DevOps & SRE Team

Hệ thống giờ đây có thể:

  • Theo dõi hiệu năng của ứng dụng.
  • Chủ động gửi cảnh báo khi có bất thường.
  • Thu thập và tìm kiếm log tập trung.
  • Điều tra nguyên nhân gốc của sự cố.
  • Hỗ trợ quá trình vận hành trong môi trường Production.

Những gì bạn đã học

Sau Lab 9, bạn đã biết:

  • ✅ Kiến trúc Logging trong Kubernetes.
  • ✅ Fluent Bit và cách thu thập log.
  • ✅ Loki và cơ chế lưu trữ log.
  • ✅ Kết nối Grafana với Loki.
  • ✅ Truy vấn log bằng LogQL.
  • ✅ Điều tra sự cố bằng Metrics, Alerts và Logs.
  • ✅ Các Best Practices khi ghi log trong Kubernetes.
  • ✅ Quy trình xử lý sự cố trong môi trường Production.

Bài học rút ra

Qua chín bài Lab, chúng ta đã xây dựng từng bước một hệ thống Kubernetes từ môi trường phát triển đơn giản đến một nền tảng có khả năng vận hành trong Production.

Từ việc triển khai ứng dụng, tối ưu tài nguyên, tự động mở rộng, giám sát, cảnh báo cho đến thu thập log tập trung, mỗi thành phần đều đóng vai trò quan trọng trong việc đảm bảo hệ thống hoạt động ổn định.

Metrics giúp chúng ta biết hệ thống đang hoạt động như thế nào.

Alerts giúp chúng ta biết khi nào cần hành động.

Logs giúp chúng ta hiểu nguyên nhân thực sự của sự cố.

Khi kết hợp ba thành phần này, chúng ta có một hệ thống Observability hoàn chỉnh, giúp DevOps và Developer rút ngắn thời gian phát hiện, điều tra và khắc phục sự cố, đồng thời nâng cao độ tin cậy của các ứng dụng chạy trên Kubernetes. Đây cũng là nền tảng được sử dụng rộng rãi trong các hệ thống Cloud Native và Kubernetes Production hiện nay.


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.