iT邦幫忙

2025 iThome 鐵人賽

DAY 24
1
DevOps

牧場主的 K8s 放牧日記系列 第 24

Day 24: LGTM Stack 部署實戰 - 牧場的統一可觀測性平台

  • 分享至 

  • xImage
  •  

牧場主今日工作

昨天我們建立了漂亮的 Grafana 儀表板,今天要來認識現代可觀測性的終極解決方案 - LGTM Stack!就像現代牧場主需要全方位監控系統來追蹤每頭牛的健康、活動和行為,我們也需要統一的可觀測性平台。今天先從整體架構介紹開始,並部署第一個組件 Loki,讓我們的 Kubernetes 牧場開始收集完整的活動日誌!

LGTM Stack 完整架構介紹

https://ithelp.ithome.com.tw/upload/images/20250907/2014179429cvh3eeds.png

什麼是 LGTM Stack?

LGTM = Loki + Grafana + Tempo + Mimir

這是 Grafana Labs 推出的統一可觀測性解決方案,涵蓋現代 SRE 所需的三大支柱:
https://ithelp.ithome.com.tw/upload/images/20250907/2014179482LCSYlGGI.png

LGTM vs 傳統方案對比

傳統分散式監控

# 傳統痛點
❌ Prometheus (短期指標) + ELK (日誌) + Jaeger (追蹤)
❌ 三套不同系統,學習成本高
❌ 資料孤島,難以關聯分析
❌ 維護複雜,各自獨立升級

LGTM 統一方案

# LGTM 優勢  
✅ 統一的 Grafana 介面
✅ 一致的查詢體驗
✅ 資料自動關聯
✅ 統一部署和維護

我們的分階段部署計畫

現有環境回顧

  • ✅ Day 22: kube-prometheus-stack (Prometheus + Grafana)
  • ✅ Day 23: Grafana 儀表板設定完成

接下來三天的計畫

  • Day 24: Loki 部署 - 補強日誌收集能力
  • Day 25: Mimir 部署 - 作為 Prometheus 長期儲存
  • Day 26: Tempo 部署 - 加入分散式追蹤

Loki 日誌聚合系統深入介紹

Loki 的核心理念

Loki 設計哲學:「Like Prometheus, but for logs」
https://ithelp.ithome.com.tw/upload/images/20250907/20141794F1ErHGbMaM.png

Loki vs ELK Stack 技術深度對比

ELK Stack 架構回顧

ELK = Elasticsearch + Logstash + Kibana
https://ithelp.ithome.com.tw/upload/images/20250907/20141794EdRvOOi8Aq.png

ELK 的技術特性

  • Elasticsearch:基於 Lucene 的分散式搜尋引擎
  • Logstash:重量級日誌處理器,支援複雜的數據轉換
  • Kibana:功能強大的資料視覺化平台
  • 全文索引:對日誌內容建立倒排索引 (Inverted Index)

詳細技術對比分析

技術面向 Loki ELK Stack
索引策略 只索引 Labels (metadata) 全文索引 (Full-text Index)
搜尋機制 標籤過濾 + grep 模式匹配 基於 Lucene 的複雜查詢
儲存格式 日誌流壓縮儲存 JSON 文檔存儲
磁碟使用 較低 (高壓縮率) 較高 (索引開銷)
記憶體需求 較低 較高
查詢語法 LogQL (類似 PromQL) KQL/DSL (複雜查詢語言)
擴展方式 水平擴展各微服務 分片 (Sharding) 機制
運維複雜度 較簡單 較複雜

索引策略深度說明

Loki 的 Label-Only 索引

# Loki 只索引這些標籤
labels:
  namespace: "kube-system"
  pod: "coredns-12345"  
  container: "coredns"
  level: "info"

# 日誌內容不建索引,使用 grep 風格搜尋
content: "2024-01-01 10:00:00 INFO: DNS query processed"

ELK 的全文索引

{
  "@timestamp": "2024-01-01T10:00:00Z",
  "namespace": "kube-system",
  "pod": "coredns-12345",
  "message": "DNS query processed",
  "_index": {
    "DNS": ["dns", "query"],
    "query": ["query", "processed"],
    "processed": ["processed"]
  }
}

成本與效能差異

Loki 的成本優勢

  • 索引成本低:只索引標籤,不對日誌內容建立索引
  • 壓縮率高:日誌以壓縮格式存儲
  • 資源需求低:微服務架構,各組件資源需求相對較小

ELK 的資源需求

  • 索引開銷大:需要為日誌內容建立完整的倒排索引
  • 存儲膨脹:結構化存儲和副本機制導致存儲需求增加
  • 記憶體密集:Elasticsearch 需要大量記憶體來維護索引

查詢體驗對比

Loki LogQL 範例

# 簡潔直觀,類似 PromQL
{namespace="kube-system"} 
  |= "error" 
  | rate[5m]

# 日誌聚合統計
sum by (pod) (
  rate({namespace="kube-system"} |= "error" [5m])
)

ELK KQL/DSL 範例

{
  "query": {
    "bool": {
      "must": [
        {"match": {"namespace": "kube-system"}},
        {"match": {"message": "error"}}
      ],
      "filter": {
        "range": {
          "@timestamp": {
            "gte": "now-5m"
          }
        }
      }
    }
  },
  "aggs": {
    "errors_by_pod": {
      "terms": {"field": "pod"}
    }
  }
}

適用場景分析

選擇 Loki 的場景

✅ 成本敏感的環境
✅ 已有 Prometheus + Grafana
✅ 主要做故障排查和趨勢分析  
✅ 團隊熟悉 PromQL 語法
✅ 需要長期日誌保存
✅ 雲端原生環境

選擇 ELK 的場景

✅ 需要複雜的全文搜尋
✅ 業務分析和報表需求
✅ 需要豐富的視覺化選項
✅ 已有大量 ELK 運維經驗
✅ 合規要求詳細的日誌分析
✅ 不在意成本和複雜度

Loki 的技術優勢總結

架構優勢

  • 微服務設計:可獨立擴展各組件
  • 無狀態查詢:Querier 可水平擴展
  • 對象存儲友善:天然支援 S3、GCS

生態整合

  • 服務發現共享:與 Prometheus 使用相同機制
  • 標籤體系一致:減少學習和維護成本
  • Grafana 原生支援:無縫整合體驗

運維友善

  • 資源需求低:適合資源受限環境
  • 配置簡單:相較 ELK 大幅簡化
  • 故障恢復快:組件重啟成本低

Loki 部署實戰

環境準備

# 檢查現有環境
kubectl get pods -n monitoring | grep grafana
kubectl get svc -n monitoring

# 添加 Grafana Helm Repository
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update

# 檢視 LGTM Stack 版本
helm search repo grafana/lgtm-distributed

LGTM Stack 配置(只啟用 Loki)

建立適合實驗環境的 LGTM Stack 配置(只啟用 Loki):

# 建立 lgtm-values.yaml
cat > lgtm-values.yaml << 'EOF'
# LGTM Stack 配置 - 只啟用 Loki
grafana:
  # 關鍵:不部署新的 Grafana,使用現有的
  enabled: false

# Loki 日誌系統配置
loki:
  enabled: true
  # 針對實驗環境的資源配置
  loki:
    auth_enabled: false
    commonConfig:
      replication_factor: 1
    storage:
      type: filesystem
    resources:
      requests:
        cpu: 100m
        memory: 256Mi
      limits:
        cpu: 500m
        memory: 512Mi
  
  # Gateway 配置
  gateway:
    enabled: true
    replicas: 1
    resources:
      requests:
        cpu: 50m
        memory: 128Mi
      limits:
        cpu: 200m
        memory: 256Mi
    # 修正 RKE2 的 DNS resolver 問題
    nginxConfig:
      resolver: "10.43.0.10"  # RKE2 CoreDNS IP

  # Backend (Write Path)
  backend:
    replicas: 1
    resources:
      requests:
        cpu: 100m
        memory: 256Mi
      limits:
        cpu: 500m
        memory: 512Mi

  # Read 組件
  read:
    replicas: 1
    resources:
      requests:
        cpu: 100m
        memory: 256Mi
      limits:
        cpu: 300m
        memory: 512Mi

  # Write 組件  
  write:
    replicas: 1
    resources:
      requests:
        cpu: 100m
        memory: 256Mi
      limits:
        cpu: 300m
        memory: 512Mi

# Mimir 指標存儲系統(暫時 disable)
mimir:
  enabled: false

# Tempo 分散式追蹤系統(暫時 disable)
tempo:
  enabled: false

# Grafana OnCall(不需要)
grafana-oncall:
  enabled: false
EOF

部署 LGTM Stack

# 建立 namespace
kubectl create namespace lgtm-stack

# 部署 LGTM Stack(只啟用 Loki)
helm install lgtm-stack grafana/lgtm-distributed \
  -n lgtm-stack \
  -f lgtm-values.yaml

# 檢查部署狀態
kubectl get pods -n lgtm-stack -w

預期結果

NAME                                READY   STATUS
lgtm-stack-loki-gateway-xxx         1/1     Running
lgtm-stack-loki-backend-xxx         1/1     Running
lgtm-stack-loki-read-xxx            1/1     Running  
lgtm-stack-loki-write-xxx           1/1     Running

Grafana Alloy 日誌收集器部署

Grafana Alloy 簡介

為什麼選擇 Alloy?

  • Promtail 已 EOL:Grafana Labs 官方推薦的替代方案
  • 統一收集器:支援 metrics、logs、traces、profiles
  • 現代架構:更好的效能和資源利用率
  • 豐富生態:支援更多資料來源和輸出

使用 Helm 部署 Alloy

環境準備

# 添加 Grafana Helm Repository(如果還沒有的話)
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update

建立 Alloy 配置

# 建立 alloy-values.yaml
cat > alloy-values.yaml << 'EOF'
# Alloy 配置 - 專門用於日誌收集
alloy:
  configMap:
    content: |
      // Kubernetes Service Discovery
      discovery.kubernetes "pods" {
        role = "pod"
      }

      // 日誌收集規則
      loki.source.kubernetes "pods" {
        targets    = discovery.kubernetes.pods.targets
        forward_to = [loki.process.pods.receiver]
      }

      // 日誌處理管道
      loki.process "pods" {
        forward_to = [loki.write.default.receiver]

        stage.static_labels {
          values = {
            cluster = "rancher-custom",
          }
        }

        // 解析日誌等級
        stage.regex {
          expression = "(?i)(?P<level>debug|info|warn|error|fatal)"
        }

        stage.labels {
          values = {
            level = "",
          }
        }
      }

      // 發送到 Loki
      loki.write "default" {
        endpoint {
          url = "http://lgtm-stack-loki-gateway.lgtm-stack.svc.cluster.local/loki/api/v1/push"
        }
      }

  # 啟用日誌收集相關的 mount
  mounts:
    varlog: true
    dockercontainers: true

# Controller 配置
controller:
  type: daemonset  # 在每個節點運行

# RBAC 配置
rbac:
  create: true

# Service Account 配置  
serviceAccount:
  create: true
EOF

部署 Alloy

# 部署 Alloy 到 lgtm-stack namespace
helm install alloy grafana/alloy \
  --version 1.2.1 \
  -n lgtm-stack \
  -f alloy-values.yaml

# 檢查部署狀態
kubectl get pods -n lgtm-stack | grep alloy

預期結果

NAME                READY   STATUS
alloy-xxxxx         2/2     Running  # 每個節點一個 Pod

Grafana 整合設定

在現有 Grafana 中添加 Loki 資料來源

# 存取 Grafana
kubectl port-forward -n monitoring svc/kube-prometheus-stack-grafana 3000:80

# 測試 Loki 連線
kubectl port-forward -n lgtm-stack svc/lgtm-stack-loki-gateway 3100:80 &
curl http://localhost:3100/ready

curl http://localhost:3100/

透過 Helm values 配置資料來源

更新現有的 prometheus-values.yaml 文件,在 grafana 區段添加 Loki 資料來源:

# 在現有的 grafana 區段中添加 additionalDataSources
grafana:
  # 保持現有設定...
  adminPassword: "admin123"
  persistence:
    enabled: true
    size: 5Gi
  
  # 新增 Loki 資料來源
  additionalDataSources:
    - name: Loki
      type: loki
      url: http://lgtm-stack-loki-gateway.lgtm-stack.svc.cluster.local
      access: proxy
      isDefault: false
      editable: true
      jsonData:
        maxLines: 1000

升級 Prometheus Stack 配置:

helm upgrade kube-prometheus-stack prometheus-community/kube-prometheus-stack \
  -n monitoring \
  -f prometheus-values.yaml

基本 LogQL 查詢驗證

在 Grafana Explore 中測試以下查詢:

重要:確保在 Explore 中選擇 Loki 資料來源,並將時間範圍設為「Last 5 minutes」。

# 查看所有日誌(使用我們配置的 cluster 標籤)
{cluster="rancher-custom"}

# 查看特定服務的日誌(使用 instance 標籤)
{cluster="rancher-custom"} |= "cattle-system"

# 查看錯誤日誌
{cluster="rancher-custom", level="Error"}

# 查看 Alloy 本身的日誌
{cluster="rancher-custom"} |= "alloy"

# 查看特定 Pod 的日誌
{cluster="rancher-custom"} |= "fleet-agent"

# 使用正規表達式過濾
{cluster="rancher-custom"} |~ "error|failed"

如果查不到結果,請檢查

  1. 時間範圍是否正確(建議用 Last 5 minutes)
  2. 確認已選擇 Loki 資料來源
  3. 檢查 Alloy 是否正常運行:kubectl logs -n lgtm-stack daemonset/alloy --tail=5

日誌收集驗證與測試

檢查 Alloy 收集狀態

# 檢查 Alloy Pods
kubectl get pods -n lgtm-stack | grep alloy

# 檢查 Alloy 日誌
kubectl logs -n lgtm-stack daemonset/alloy

# 檢查 Alloy metrics
kubectl port-forward -n lgtm-stack daemonset/alloy 12345:12345
curl http://localhost:12345/metrics | grep loki

今日總結與明日預告

今天我們深入認識了 LGTM Stack 的完整架構,並成功部署了第一個組件 - Loki 日誌聚合系統!透過現代化的 Grafana Alloy 收集器,我們的 Kubernetes 牧場現在能夠收集完整的活動日誌,並整合到現有的 Grafana 中查看。

重點回顧

  • LGTM 架構:理解統一可觀測性的完整願景
  • Loki 優勢:成本效益高的日誌解決方案
  • Alloy 現代化:取代 EOL 的 Promtail
  • 無縫整合:善用現有 Grafana,避免重複部署

明天我們要部署 Mimir,讓它作為 Prometheus 的長期指標儲存後端,解決 Prometheus 本地儲存的限制,真正實現企業級的指標管理!

💡 牧場主小提示:LGTM Stack 的威力在於統一體驗,但部署策略要靈活!分階段部署讓你每一步都看得到效果,避免一次性部署的複雜性。Alloy 作為 Promtail 的替代方案值得關注,多了解不同工具的特性總是好事!


上一篇
Day 23: Grafana 監控儀表板實戰 - 匯入社群模板與 Ingress 設定
系列文
牧場主的 K8s 放牧日記24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言