Hướng dẫn cài đặt và cấu hình Thanos để mở rộng Prometheus: Lưu trữ metrics dài hạn và Global View cho nhiều cluster

Monitoring tutorial - IT technology blog
Monitoring tutorial - IT technology blog

Thanos giải quyết vấn đề gì mà Prometheus không làm được?

Mình từng chạy Prometheus cho 3 cụm Kubernetes riêng lẻ. Mỗi cụm có Grafana riêng, alert riêng. Khi khách hàng hỏi “metrics tháng trước của service X trên production là bao nhiêu?” — mình phải mở 3 tab, tìm từng cụm, copy-paste số liệu vào Excel. Mất 20 phút cho một câu hỏi đơn giản.

Prometheus mặc định chỉ giữ 15 ngày data và không có cách nào xem toàn bộ cluster trong một chỗ. Thanos sinh ra để xử lý đúng 2 cái đau đầu đó.

Quick Start: Thanos chạy được trong 10 phút

Cách nhanh nhất để thử là dùng Docker Compose với MinIO làm object storage giả lập S3. Không cần AWS, không cần account gì cả.

Bước 1: Tạo file cấu hình bucket

mkdir -p ~/thanos-demo && cd ~/thanos-demo

cat > bucket.yaml <<EOF
type: S3
config:
  bucket: thanos
  endpoint: minio:9000
  access_key: minioadmin
  secret_key: minioadmin
  insecure: true
EOF

Bước 2: Docker Compose toàn bộ stack

# docker-compose.yml
version: '3.8'
services:
  minio:
    image: minio/minio:latest
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: minioadmin
    ports:
      - "9000:9000"
      - "9001:9001"
    volumes:
      - minio_data:/data

  prometheus:
    image: prom/prometheus:latest
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.max-block-duration=2h'
      - '--storage.tsdb.min-block-duration=2h'
      - '--web.enable-lifecycle'
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    ports:
      - "9090:9090"

  thanos-sidecar:
    image: thanosio/thanos:latest
    command:
      - sidecar
      - --tsdb.path=/prometheus
      - --prometheus.url=http://prometheus:9090
      - --objstore.config-file=/bucket.yaml
      - --http-address=0.0.0.0:10902
      - --grpc-address=0.0.0.0:10901
    volumes:
      - prometheus_data:/prometheus
      - ./bucket.yaml:/bucket.yaml
    depends_on:
      - prometheus
      - minio

  thanos-store:
    image: thanosio/thanos:latest
    command:
      - store
      - --objstore.config-file=/bucket.yaml
      - --http-address=0.0.0.0:10902
      - --grpc-address=0.0.0.0:10901
    volumes:
      - ./bucket.yaml:/bucket.yaml
    depends_on:
      - minio

  thanos-query:
    image: thanosio/thanos:latest
    command:
      - query
      - --http-address=0.0.0.0:9091
      - --endpoint=thanos-sidecar:10901
      - --endpoint=thanos-store:10901
    ports:
      - "9091:9091"
    depends_on:
      - thanos-sidecar
      - thanos-store

volumes:
  minio_data:
  prometheus_data:

Bước 3: Tạo prometheus.yml tối thiểu

# prometheus.yml
global:
  scrape_interval: 15s
  external_labels:
    cluster: 'demo'
    replica: '0'

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

Bước 4: Khởi động và tạo bucket MinIO

# Khởi động toàn bộ stack
docker compose up -d

# Tạo bucket 'thanos' trên MinIO (dùng mc client)
docker run --rm --network host \
  minio/mc alias set local http://localhost:9000 minioadmin minioadmin

docker run --rm --network host \
  minio/mc mb local/thanos

Xong. Mở http://localhost:9091 — đây là Thanos Query UI. PromQL gõ ở đây sẽ kéo data từ cả Prometheus đang chạy lẫn lịch sử đã lưu trên MinIO, trong suốt với người dùng.

Kiến trúc Thanos: Từng component làm gì?

Thanos không thay thế Prometheus — nó bổ sung bên trên. Mình hay giải thích cho đồng nghiệp theo cách này: Prometheus là kho nhỏ tại chỗ, Thanos là hệ thống kho trung tâm kết nối tất cả lại.

Sidecar — cầu nối Prometheus và Object Storage

Chạy cùng pod với Prometheus. Có 2 nhiệm vụ: expose gRPC endpoint để Thanos Query kéo data real-time, và upload block data 2 giờ một lần lên S3/MinIO.

Lưu ý quan trọng: Phải set --storage.tsdb.max-block-duration=2h trên Prometheus để Sidecar chỉ upload block đã đóng hoàn chỉnh — không đụng vào block đang ghi dở.

Store Gateway — cửa vào kho lưu trữ lịch sử

Query cần data cũ hơn 15 ngày? Nó hỏi Store Gateway. Component này kéo block từ S3, nạp index vào bộ nhớ, rồi trả kết quả về. Data thực tế không lưu local — chỉ cache index để tìm kiếm nhanh.

Query — điểm truy vấn duy nhất

Grafana và người dùng đều trỏ vào đây. Thanos Query biết tự quyết định: hỏi Sidecar cho data mới, hỏi Store Gateway cho data cũ. Nếu có nhiều replica Prometheus cùng scrape một target, nó tự deduplicate — không cần can thiệp thủ công.

Compactor — dọn dẹp và tiết kiệm chi phí

Chạy độc lập theo định kỳ. Nhiệm vụ: gom các block nhỏ thành block lớn, và downsampling data cũ. Block từ 1 năm trước không cần granularity 15 giây — downsampling xuống 1 giờ là đủ để xem trend.

Triển khai thực tế trên Kubernetes với nhiều cluster

Đây là phần mình dùng nhiều nhất trong thực tế. Mỗi cluster chạy Prometheus + Sidecar riêng, tất cả đẩy lên cùng một S3 bucket. Thanos Query đặt ở cluster trung tâm, kết nối tất cả Sidecar qua gRPC.

External labels — bắt buộc phải có

# Cluster Production
global:
  external_labels:
    cluster: 'production-sg'
    region: 'ap-southeast-1'

---
# Cluster Staging
global:
  external_labels:
    cluster: 'staging-sg'
    region: 'ap-southeast-1'

Thiếu external_labels là lỗi phổ biến nhất khi mới dùng Thanos. Data từ 2 cluster đổ vào cùng S3 bucket mà không có label phân biệt — Query không biết dedup thế nào, kết quả truy vấn bị nhân đôi, alert lên nhầm. Đừng bỏ qua bước này.

Kết nối nhiều cluster vào một Thanos Query

# Thanos Query kết nối Sidecar từ nhiều cluster
thanos query \
  --http-address=0.0.0.0:9091 \
  --endpoint=prod-sidecar.monitoring.svc:10901 \
  --endpoint=staging-sidecar.monitoring.svc:10901 \
  --endpoint=thanos-store.monitoring.svc:10901 \
  --query.replica-label=replica

Trước khi có setup này, mình phải SSH vào từng server để kiểm tra. Giờ một Grafana dashboard với datasource trỏ vào Thanos Query, filter theo label cluster là thấy hết — production lẫn staging, trong cùng một biểu đồ.

Cấu hình lưu trữ dài hạn trên AWS S3 thực tế

# bucket-s3.yaml cho production
type: S3
config:
  bucket: company-thanos-metrics
  endpoint: s3.ap-southeast-1.amazonaws.com
  region: ap-southeast-1
  # Dùng IAM Role thay vì hardcode key nếu chạy trên EC2/EKS
  access_key: ${AWS_ACCESS_KEY_ID}
  secret_key: ${AWS_SECRET_ACCESS_KEY}

Thêm Compactor để giảm chi phí storage

thanos compact \
  --data-dir=/tmp/thanos-compact \
  --objstore.config-file=/bucket-s3.yaml \
  --retention.resolution-raw=30d \
  --retention.resolution-5m=90d \
  --retention.resolution-1h=1y \
  --wait

Config trên giữ data thô 30 ngày, downsampled 5 phút trong 90 ngày, downsampled 1 giờ trong 1 năm. Mình đo thực tế trên một hệ thống ~500k active series: chi phí S3 giảm khoảng 65% sau khi bật Compactor với downsampling — so với giữ nguyên 15-second resolution cho cả năm.

Tips thực tế từ kinh nghiệm vận hành

1. Monitor chính Thanos bằng Prometheus

Thanos expose /metrics ở port 10902. Thêm vào scrape config để biết khi nào Compactor bị stuck hay Store Gateway không sync được block mới — tốt hơn là ngồi đợi khách hàng báo.

scrape_configs:
  - job_name: 'thanos-components'
    static_configs:
      - targets:
          - 'thanos-query:10902'
          - 'thanos-store:10902'
          - 'thanos-sidecar:10902'

2. Rút ngắn retention Prometheus sau khi có Thanos

# Prometheus chỉ cần giữ 2-7 ngày, phần còn lại Thanos lo
prometheus \
  --storage.tsdb.retention.time=7d \
  --storage.tsdb.max-block-duration=2h \
  --storage.tsdb.min-block-duration=2h

3. Kiểm tra block đã upload lên S3 chưa

# Dùng thanos tools để inspect bucket
thanos tools bucket inspect \
  --objstore.config-file=bucket.yaml \
  --output=table

4. Xử lý lỗi “duplicate samples”

Grafana hiển thị data bị nhân đôi? Thêm flag deduplication vào Thanos Query:

thanos query \
  --query.replica-label=replica \
  --query.auto-downsampling \
  [các endpoint khác]

5. Alert khi Sidecar mất kết nối S3

# alert rule cho Thanos
groups:
  - name: thanos
    rules:
      - alert: ThanosSidecarBucketOperationsFailed
        expr: rate(thanos_objstore_bucket_operation_failures_total[5m]) > 0
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Thanos Sidecar không upload được lên Object Storage"

Thanos vs Cortex vs VictoriaMetrics — chọn cái nào?

Câu này mình gặp hoài. Câu trả lời phụ thuộc vào quy mô và mức độ sẵn sàng thay đổi kiến trúc.

Thanos phù hợp nhất nếu đang có Prometheus sẵn — chỉ cần thêm Sidecar, không cần đụng vào cấu hình scraping hiện tại. VictoriaMetrics xử lý throughput cao hơn 5-10x Prometheus trên cùng phần cứng và tốn ít RAM hơn, nhưng đòi hỏi migrate hoàn toàn. Cortex mạnh ở quy mô lớn (hàng trăm triệu samples/giây) nhưng cần thêm Cassandra hoặc DynamoDB cho metadata store — overhead vận hành không nhỏ.

Dưới 10 cluster, dưới 1 triệu active series? Thanos là lựa chọn thực dụng nhất. Không cần over-engineer.

Share: