Skip to content

antony@notes:~/kubernetes$ cat "Logging-Operator.md"

Logging Operator

2026-03-24· kubernetes

Logging Operator — Kubernetes 日誌管理解決方案

Preface

本篇文章會先介紹什麼是 Logging Operator,並透過 Rancher Logging 實作將 Pod Log 導入 OpenSearch

簡介

Logging Operator 是一套專為 Kubernetes 環境設計的日誌管理工具。它能夠自動部署與設定完整的日誌收集流程(logging pipeline),讓你不必手動處理繁瑣的日誌基礎設施配置。

運作流程

Logging Operator 的日誌處理分為三個階段:

1. 日誌收集(Log Collector)

Operator 會在 Kubernetes 叢集中的每個節點上部署一個 Fluent Bit DaemonSet,負責從節點的檔案系統中收集 App Containers 和應用程式的日誌。

2. 中繼資料 enrichment(Metadata Enrichment)

Fluent Bit 會查詢 Kubernetes API,為日誌附加 Pod 的相關中繼資料(metadata),例如 Pod 名稱、namespace、標籤等。接著,將日誌連同這些中繼資料一併傳送給日誌轉發器(Log Forwarder)。

3. 日誌轉發(Log Forwarding)

日誌轉發器負責接收、過濾與轉換傳入的日誌,並將處理完的結果傳送到一個或多個目的地輸出(destination outputs)。

目前支援的日誌轉發器有兩種:

轉發器說明
Fluentd廣泛使用的開源日誌轉發工具
syslog-ng(透過 AxoSyslog 發行版)高效能的系統日誌處理引擎

image

安全性

所有日誌的傳輸皆透過經過驗證(authenticated)且加密(encrypted)的通道進行,確保資料在傳輸過程中的安全性。

核心優勢

Logging Operator 最大的特色在於:你可以將日誌的行為描述直接定義在應用程式的 Helm Chart 中,Operator 會自動完成其餘的部署與配置工作。

換句話說,日誌設定可以隨著應用程式一起版本控制與部署,實現基礎設施即程式碼(Infrastructure as Code)的理念。

功能特色

Logging Operator 提供以下核心功能:

  • Namespace 隔離:日誌流(flow)與輸出(output)可以限定在特定的 namespace 中運作,實現多租戶隔離。
  • 原生 Kubernetes Label Selector:直接使用 Kubernetes 原生的標籤選擇器來篩選要收集的日誌來源。
  • 安全通訊(TLS):所有日誌傳輸皆支援 TLS 加密,確保資料安全。
  • 設定檔驗證:自動驗證設定是否正確,降低配置錯誤的風險。
  • 多重 Flow 支援:同一份日誌可以經由多條 flow 進行不同的過濾與轉換處理。
  • 多重 Output 支援:同一份日誌可以同時傳送到多個儲存目的地,例如 S3、GCS、Elasticsearch、Loki 等。
  • 多重 Logging 系統支援:在同一個叢集中可以部署多套 Fluentd 與 Fluent Bit 實例,滿足不同的日誌需求。
  • 雙轉發器引擎:同時支援 syslog-ng 與 Fluentd 作為核心日誌路由元件。

架構概覽

Logging Operator 管理日誌基礎設施中的三個核心角色:日誌收集器(Log Collector)日誌轉發器(Log Forwarder),以及定義日誌該送往何處的路由規則

日誌收集器(Log Collector)

  • 部署在每個 Kubernetes 節點上的端點代理程式(endpoint agent)。
  • 負責收集該節點上所有 App Container 的日誌,並傳送給日誌轉發器。
  • 目前使用 Fluent Bit 作為日誌收集器。

日誌轉發器(Log Forwarder / Log Aggregator)

  • 接收來自收集器的日誌後,進行過濾(filter)轉換(transform)
  • 將處理後的日誌傳送到一個或多個目的地輸出。
  • 支援兩種轉發器引擎:
轉發器適用場景
Fluentd生態系成熟、外掛豐富,適合大多數使用情境
syslog-ng高效能、低資源消耗,適合需要進階日誌處理邏輯的場景

如何選擇適合的轉發器,可參考官方文件 Which log forwarder to use

路由規則(Flow & Output)

你可以透過 Flow 自訂資源來過濾、處理日誌訊息,並將它們路由到適當的 Output(目的地),例如 Elasticsearch 或 Amazon S3。

除了 namespace 層級的 flow 與 output,你也可以定義叢集層級的 ClusterFlow 與 ClusterOutput,讓所有 namespace 的使用者都能引用同一組集中式輸出,但無法修改其設定。

注意: Flow 與 Output 資源是依據你選用的轉發器類型(Fluentd 或 syslog-ng)而不同的,兩者的 CRD 不能混用。

Custom Resource Definitions(CRD)一覽

共用資源

CRD說明作用範圍
logging定義叢集的日誌基礎設施,包含日誌收集器與轉發器的設定。也可包含 Fluent Bit、Fluentd、syslog-ng 的配置。自 4.5 版起,這些元件也可作為獨立資源分開設定。叢集層級

Fluentd 專用 CRD

CRD說明作用範圍
output定義 Fluentd 的日誌輸出目的地。Namespace
flow定義 Fluentd 的日誌路由規則,使用 filter 與 output 將選定的日誌導向指定目的地。Namespace
clusteroutput定義可供所有 flow 與 clusterflow 使用的 Fluentd 輸出。預設僅在 controlNamespace 中生效,除非設定 allowClusterResourcesFromAllNamespaces: true叢集層級
clusterflow定義可從所有 namespace 收集日誌的 Fluentd 路由規則。預設僅在 controlNamespace 中生效,除非設定 allowClusterResourcesFromAllNamespaces: true叢集層級

syslog-ng 專用 CRD

CRD說明作用範圍
SyslogNGOutput定義 syslog-ng 的日誌輸出目的地。Namespace
SyslogNGFlow定義 syslog-ng 的日誌路由規則,使用 filter 與 output 將選定的日誌導向指定目的地。Namespace
SyslogNGClusterOutput定義可供所有 flow 與 clusterflow 使用的 syslog-ng 輸出。預設僅在 controlNamespace 中生效,除非設定 allowClusterResourcesFromAllNamespaces: true叢集層級
SyslogNGClusterFlow定義可從所有 namespace 收集日誌的 syslog-ng 路由規則。預設僅在 controlNamespace 中生效,除非設定 allowClusterResourcesFromAllNamespaces: true叢集層級

Fluentd 與 syslog-ng 的 CRD 結構相似,但各自針對自身引擎的特性進行了調整。選用哪一組 CRD 取決於你在 logging 資源中選擇的轉發器類型。


Rancher Logging — 將 Pod Log 導入 OpenSearch 實作指南

環境概述

Rancher 的日誌管理由 Logging operator 提供支持。 以下實作將透過 Rancher logging,將指定 Kubernetes Pod 的 stdout log 經由 Fluentd 轉送至外部 OpenSearch。

環境準備

  • Rancher 安裝 DownStream RKE2 Cluster
  • DownStream RKE2 Cluster 已安裝 Rancher Logging
  • 在 DownStream RKE2 Cluster 外部已安裝好 opensearch

步驟一:建立 Namespace

kubectl create ns app

步驟二:部署測試用 Pod

建立一個每秒輸出一行遞增計數 log 的 Pod,用以驗證 log pipeline 是否正常運作。

cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: test-logging-pod
  namespace: app
  labels:
    logging-test: "true"
spec:
  automountServiceAccountToken: false
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    runAsGroup: 1000
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: sak
    image: rancherlabs/swiss-army-knife:latest
    command: ["/bin/sh"]
    args:
    - -c
    - |
      i=0; while true; do echo "$(date) INFO $i"; i=$((i+1)); sleep 1; done
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop:
        - ALL
EOF

確認 Pod 已正常啟動:

kubectl -n app get pods -l logging-test=true

預期輸出:

NAME               READY   STATUS    RESTARTS   AGE
test-logging-pod   1/1     Running   0          5s

確認 log 輸出正常:

kubectl -n app logs test-logging-pod

預期輸出(每秒遞增一行):

Mon Mar 16 07:43:57 UTC 2026 INFO 0
Mon Mar 16 07:43:58 UTC 2026 INFO 1
Mon Mar 16 07:43:59 UTC 2026 INFO 2
...

步驟三:建立 OpenSearch 認證 Secret

將 OpenSearch 的帳號密碼以 kubernetes.io/basic-auth 類型的 Secret 儲存於叢集中,供後續 Output CR 引用。

PW='Test12345@'

kubectl create secret generic opensearch-user-auth \
  --namespace=app \
  --type=kubernetes.io/basic-auth \
  --from-literal=username=admin \
  --from-literal=password=$PW

步驟四:建立 Logging Output CR

定義 Fluentd 將 log 發送至 OpenSearch 的目標端點與 buffer 策略。

cat <<'EOF' | kubectl apply -f -
apiVersion: logging.banzaicloud.io/v1beta1
kind: Output
metadata:
  name: opensearch-admin
  namespace: app
spec:
  opensearch:
    host: opensearch-node.kubeantony.com
    port: 9200
    scheme: https
    ssl_verify: false
    ssl_version: TLSv1_2
    suppress_type_name: true
    user: admin
    password:
      valueFrom:
        secretKeyRef:
          key: password
          name: opensearch-user-auth
    buffer:
      flush_interval: 10s
      flush_mode: interval
      retry_type: exponential_backoff
      retry_forever: true
      chunk_limit_size: 8MB
      total_limit_size: 512MB
EOF

Buffer 參數說明

參數說明
flush_modeinterval以固定時間間隔觸發 flush,在即時性與效能間取得平衡
flush_interval10s每 10 秒將累積的 log 批次送出
chunk_limit_size8MB單一 chunk 上限;達到後即使未到 flush 時間也會送出,防止記憶體暴漲
total_limit_size512MB所有 buffer 佔用的磁碟空間上限;超過後新 log 將依 overflow_action 處理
retry_typeexponential_backoff發送失敗時以指數退避策略重試(1s → 2s → 4s → …),避免對 OpenSearch 造成衝擊
retry_forevertrue無限重試直到成功,確保 log 不遺失(代價是 buffer 可能在長時間故障時被填滿)

確認 Output 資源已建立(此時 ACTIVEfalse 是正常的,表示尚未被任何 Flow 引用):

kubectl -n app get outputs.logging.banzaicloud.io

預期輸出:

NAME               ACTIVE   PROBLEMS
opensearch-admin   false

步驟五:建立 Logging Flow CR

建立 Flow 將帶有 logging-test: "true" label 的 Pod log 路由至上一步定義的 Output。

cat <<'EOF' | kubectl apply -f -
apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
  name: app-to-opensearch
  namespace: app
spec:
  match:
    - select:
        labels:
          logging-test: "true"
  localOutputRefs:
    - opensearch-admin
EOF

確認 Flow 已啟用:

kubectl -n app get flows.logging.banzaicloud.io

預期輸出:

NAME                ACTIVE   PROBLEMS
app-to-opensearch   true

步驟六:於 OpenSearch 驗證 Log 寫入

確認索引已建立

於 OpenSearch Dashboards 左上角選單進入 Index Management → Indexes,搜尋 fluentd,應可看到對應索引已自動建立。

image

查詢最新 Log

Dev Tools 執行以下查詢,取得最近 3 筆 log:

GET fluentd/_search
{
  "size": 3,
  "sort": [{ "time": { "order": "desc" }}],
  "query": {
    "match_all": {}
  }
}

回傳結果中,每筆文件的 _source 應包含 message(原始 log 訊息)、kubernetes(Pod metadata)、以及 time(時間戳記)等欄位,代表 log pipeline 已完整串通。

image

以下為其中一筆 log

{
  "took": 1000,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 10000,
      "relation": "gte"
    },
    "max_score": null,
    "hits": [
      {
        "_index": "fluentd",
        "_id": "q0239pwBR50SWBx4toac",
        "_score": null,
        "_source": {
          "time": "2026-03-16T20:55:59.312256038+08:00",
          "stream": "stdout",
          "logtag": "F",
          "message": "Mon Mar 16 12:55:59 UTC 2026 INFO 9961",
          "kubernetes": {
            "pod_name": "test-logging-pod",
            "namespace_name": "app",
            "pod_id": "50148584-185c-475c-b203-4120526c755d",
            "labels": {
              "logging-test": "true"
            },
            "annotations": {
              "kubectl.kubernetes.io/last-applied-configuration": """{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{"logging-test":"true"},"name":"test-logging-pod","namespace":"app"},"spec":{"automountServiceAccountToken":false,"containers":[{"args":["-c","i=0; while true; do echo \"$(date) INFO $i\"; i=$((i+1)); sleep 1; done\n"],"command":["/bin/sh"],"image":"rancherlabs/swiss-army-knife:latest","name":"sak","securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true}}],"securityContext":{"runAsGroup":1000,"runAsNonRoot":true,"runAsUser":1000,"seccompProfile":{"type":"RuntimeDefault"}}}}
"""
            },
            "host": "rke2-w2",
            "container_name": "sak",
            "docker_id": "d820db7b9416cde0b968f2e2fa314e74d656a064def3ecc183b7768bef65102a",
            "container_hash": "docker.io/rancherlabs/swiss-army-knife@sha256:af25a3ace6269adb9e494b693644bc2f897ec872076d78f78bc5ded69f2ee222",
            "container_image": "docker.io/rancherlabs/swiss-army-knife:latest"
          },
          "kubernetes_namespace": {
            "name": "app",
            "labels": {
              "field.cattle.io/projectId": "p-pzhk7",
              "kubernetes.io/metadata.name": "app"
            }
          }
        },
        "sort": [
          1773665759312
        ]
      }
    ]
  }
}

log 架構說明

以下逐層說明這個 OpenSearch 查詢回應的結構:

image

第一層:查詢執行資訊

took 表示 OpenSearch 花了 1000 毫秒完成這次查詢。timed_out: false 代表查詢在設定的超時限制內完成。_shards 記錄了參與查詢的分片狀態,這裡只有 1 個分片且執行成功、無失敗。

第二層:結果集合 hits

hits.total.value 為 10000,搭配 relation: "gte" 表示實際命中數量「大於或等於」10,000 筆,這是 OpenSearch 預設的計數上限(track_total_hits 未啟用精確計數時的行為)。max_scorenull 是因為查詢使用了 sort 排序,此時相關性分數不會被計算。

第三層:單筆文件 hits.hits[]

每筆文件包含 _index(寫入的索引名稱,這裡是 fluentd)、_id(OpenSearch 自動產生的文件 ID)、以及 sort(排序欄位的原始值,此處為 time 的毫秒級 epoch)。

第四層:_source — Fluentd 寫入的原始資料

這是最核心的部分,由 Fluentd 的 Kubernetes metadata filter 自動附加:

  • time:log 產生的時間戳記(ISO 8601 格式,含時區)
  • message:容器的原始 stdout 輸出內容
  • stream:輸出流類型,stdoutstderr
  • logtag:CRI log 的完整性標記,F 代表完整行(Full),P 代表部分行(Partial,尚有後續)
  • kubernetes:Pod 層級的元資料,包含 pod 名稱、namespace、pod ID、labels、annotations、所在節點(host)、容器名稱與 image 資訊
  • kubernetes_namespace:Namespace 層級的元資料,包含名稱及其 labels(如 Rancher 的 projectId)

Rancher Logging — 將 Pod Log 導入 OpenSearch 實作指南 2

環境概述

以下實作將透過 Rancher logging,將指定 Kubernetes namespace 底下所有 Pods 的 log 經由 Fluentd 轉送至外部 logstash 再轉送到 opensearch。

環境準備

  • Rancher 安裝 DownStream RKE2 Cluster
  • DownStream RKE2 Cluster 已安裝 Rancher Logging
  • 在 DownStream RKE2 Cluster 外部已安裝好 logstash
  • 在 DownStream RKE2 Cluster 外部已安裝好 opensearch

開始實作

# Secret: CA 憑證
kubectl -n kube-system create secret generic logstash-ca \
  --from-file=ca.crt=/etc/logstash/certs/ca.crt

# Secret: basic auth 帳密
kubectl -n kube-system create secret generic logstash-auth \
  --from-literal=username=logstash \
  --from-literal=password=logstash

cat <<'EOF' | kubectl apply -f -
apiVersion: logging.banzaicloud.io/v1beta1
kind: Output
metadata:
  name: logstash-http
  namespace: kube-system
spec:
apiVersion: logging.banzaicloud.io/v1beta1
kind: Output
metadata:
  name: logstash-http
  namespace: kube-system
spec:
  http:
    endpoint: "https://logstash.kubeantony.com:8080"
    content_type: "application/json"
    json_array: true
    auth:
      username:
        valueFrom:
          secretKeyRef:
            name: logstash-auth
            key: username
      password:
        valueFrom:
          secretKeyRef:
            name: logstash-auth
            key: password
    tls_ca_cert_path:
      mountFrom:
        secretKeyRef:
          name: logstash-ca
          key: ca.crt
    buffer:
      type: file
      flush_interval: 5s
      flush_mode: interval
      timekey: 1m
      timekey_wait: 10s
      total_limit_size: 1GB
EOF

cat <<'EOF' | kubectl apply -f -
apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
  name: kube-logs
  namespace: kube-system
spec:
  match:
    - select: {}
  localOutputRefs:
    - logstash-http
EOF

確認索引已建立

於 OpenSearch Dashboards 左上角選單進入 Index Management → Indexes,搜尋 fluentd,應可看到對應索引已自動建立。

image

查詢最新 Log

Dev Tools 執行以下查詢,對日誌索引執行無條件檢索,並依時間戳(@timestamp)降序排列以提取最新的一筆數據紀錄:

GET opensearch-logstash-docker-2026.03.24/_search
{
  "size": 1,
  "query": {
    "match_all": {}
  },
  "sort": [{"@timestamp": "desc"}]
}

回傳結果中,每筆文件的 _source 應包含 message(原始 log 訊息)、kubernetes(Pod metadata)、以及 time(時間戳記)等欄位,代表 log pipeline 已完整串通。

image

以下為其中一筆 log

{
  "took": 563,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 10000,
      "relation": "gte"
    },
    "max_score": null,
    "hits": [
      {
        "_index": "opensearch-logstash-docker-2026.03.24",
        "_id": "ielEH50BXMB4tDz9Y0CX",
        "_score": null,
        "_source": {
          "logtag": "F",
          "message": "W0324 09:54:23.735867       1 logging.go:55] [core] [Channel #4240 SubChannel #4241]grpc: addrConn.createTransport failed to connect to {Addr: \"127.0.0.1:2379\", ServerName: \"127.0.0.1:2379\", BalancerAttributes: {\"<%!p(pickfirstleaf.managedByPickfirstKeyType={})>\": \"<%!p(bool=true)>\" }}. Err: connection error: desc = \"transport: Error while dialing: dial tcp 127.0.0.1:2379: operation was canceled\"",
          "url": {
            "domain": "logstash.kubeantony.com",
            "path": "/",
            "port": 8080
          },
          "kubernetes": {
            "container_hash": "registry.rancher.com/rancher/hardened-kubernetes@sha256:4fab2ebc142aa1bb04a9641daebd6197404040806758cb3f3e78a6acfde47853",
            "annotations": {
              "kubernetes.io/config.mirror": "88a0909b75e7783678932b6535c63316",
              "kubernetes.io/config.hash": "88a0909b75e7783678932b6535c63316",
              "kubernetes.io/config.source": "file",
              "kubernetes.io/config.seen": "2026-03-04T13:33:01.249775809+08:00"
            },
            "pod_name": "kube-apiserver-rke2-c2",
            "container_image": "registry.rancher.com/rancher/hardened-kubernetes:v1.34.4-rke2r1-build20260210",
            "labels": {
              "tier": "control-plane",
              "component": "kube-apiserver"
            },
            "host": "rke2-c2",
            "container_name": "kube-apiserver",
            "pod_id": "80dc734a-bbbc-48bc-a95f-ba88100ec24b",
            "docker_id": "61c3121ba35fa4fa01f25037d1f27181d0b455cb350d196de37b55f13edb2444",
            "namespace_name": "kube-system"
          },
          "@timestamp": "2026-03-24T09:54:28.785431836Z",
          "user_agent": {
            "original": "Ruby"
          },
          "http": {
            "version": "HTTP/1.1",
            "request": {
              "body": {
                "bytes": "1448"
              },
              "mime_type": "application/json"
            },
            "method": "POST"
          },
          "event": {
            "original": """[{"time":"2026-03-24T17:54:23.73604561+08:00","stream":"stderr","logtag":"F","message":"W0324 09:54:23.735867       1 logging.go:55] [core] [Channel #4240 SubChannel #4241]grpc: addrConn.createTransport failed to connect to {Addr: \"127.0.0.1:2379\", ServerName: \"127.0.0.1:2379\", BalancerAttributes: {\"<%!p(pickfirstleaf.managedByPickfirstKeyType={})>\": \"<%!p(bool=true)>\" }}. Err: connection error: desc = \"transport: Error while dialing: dial tcp 127.0.0.1:2379: operation was canceled\"","kubernetes":{"pod_name":"kube-apiserver-rke2-c2","namespace_name":"kube-system","pod_id":"80dc734a-bbbc-48bc-a95f-ba88100ec24b","labels":{"component":"kube-apiserver","tier":"control-plane"},"annotations":{"kubernetes.io/config.hash":"88a0909b75e7783678932b6535c63316","kubernetes.io/config.mirror":"88a0909b75e7783678932b6535c63316","kubernetes.io/config.seen":"2026-03-04T13:33:01.249775809+08:00","kubernetes.io/config.source":"file"},"host":"rke2-c2","container_name":"kube-apiserver","docker_id":"61c3121ba35fa4fa01f25037d1f27181d0b455cb350d196de37b55f13edb2444","container_hash":"registry.rancher.com/rancher/hardened-kubernetes@sha256:4fab2ebc142aa1bb04a9641daebd6197404040806758cb3f3e78a6acfde47853","container_image":"registry.rancher.com/rancher/hardened-kubernetes:v1.34.4-rke2r1-build20260210"},"kubernetes_namespace":{"name":"kube-system","labels":{"field.cattle.io/projectId":"p-xnskv","kubernetes.io/metadata.name":"kube-system"}}}
]"""
          },
          "stream": "stderr",
          "time": "2026-03-24T17:54:23.73604561+08:00",
          "@version": "1",
          "host": {
            "ip": "192.168.11.156"
          },
          "kubernetes_namespace": {
            "name": "kube-system",
            "labels": {
              "field.cattle.io/projectId": "p-xnskv",
              "kubernetes.io/metadata.name": "kube-system"
            }
          }
        },
        "sort": [
          1774346068785
        ]
      }
    ]
  }
}

沒問題!我將根據您提供的架構,結合這份日誌的實際內容進行邏輯拆解與解釋。這份日誌記錄了 2026-03-24 某個 Kubernetes 核心組件發生連線異常的瞬間。


Log 架構邏輯說明

以下逐層說明這個 OpenSearch 查詢回應的結構:

第一層:查詢執行資訊 (Query Execution Info)

  • took: 表示 OpenSearch 花了 563 毫秒 完成這次查詢。
  • timed_out: false: 代表查詢在設定的超時限制內順利完成。
  • _shards: 記錄了參與查詢的分片狀態,這裡只有 1 個分片 且執行成功、無失敗,顯示索引結構較為簡單或資料量尚在單一分片承載範圍內。

第二層:結果集合 hits (Result Metadata)

  • hits.total.value: 10000 搭配 relation: "gte": 表示實際命中數量「大於或等於」10,000 筆。這是 OpenSearch 為了查詢效能所做的預設優化(未開啟 track_total_hits),告訴運維人員:符合條件的日誌非常多,這只是冰山一角。
  • max_score: null: 因為我們在命令中使用了 sort(依照時間排序),OpenSearch 會跳過相關性分數(Relevance Score)的計算,這在日誌分析中是標準做法。

第三層:單筆文件 hits.hits[] (Document Identity)

  • _index: 寫入的索引名稱為 opensearch-logstash-docker-2026.03.24
  • _id: 該筆日誌的唯一標記符 ielEH50BXMB4tDz9Y0CX
  • sort: 排序欄位的原始值 1774346068785(這是一個毫秒級的 Epoch 時間戳記,對應到 @timestamp)。

第四層:_source — 採集器寫入的原始資料 (Enriched Data)

這是運維診斷的核心,由日誌採集器(如 Logstash/Fluentd)自動附加的元資料:

  • 時間戳記與時區邏輯
    • message: 09:54:23(容器原始輸出的 UTC 時間)。
    • time: 17:54:23...+08:00(採集器轉換後的本地時間,兩者相差 8 小時)。
    • @timestamp: 09:54:28Z(OpenSearch 儲存用的標準 UTC 格式,比 log 產出晚 5 秒,代表處理延遲)。
  • message: 核心錯誤內容,顯示 kube-apiserver 無法連線至本地的 etcd (127.0.0.1:2379)。
  • stream: stderr: 標記這是一條錯誤流日誌,並非正常的標準輸出。
  • logtag: F: 代表這是一行完整的(Full)Log,沒有因為長度限制而被截斷。
  • kubernetes (Pod 元資料):
    • 定位:發生在命名空間 kube-system 中的 Pod kube-apiserver-rke2-c2
    • 環境:運行於節點 rke2-c2,映像檔版本為 v1.34.4
    • 身份識別:包含 pod_iddocker_id,方便進一步去主機端(Node)下 docker/crictl inspect 指令查核。
  • kubernetes_namespace: 顯示該 Namespace 屬於 Rancher 專案 p-xnskv,這有助於在多租戶環境下快速判斷受影響的專案範圍。