講真,OpenObserve 挺好用的!
OpenObserve(簡稱 O2)是一個用 Rust 開發的開源雲原生可觀測平臺,專爲日誌、指標、追蹤而構建,設計用於 PB 級工作。
與需要理解和調整大量配置置的 Elasticsearch 相比,它簡單且易於操作。在 2 分鐘內即可啓動並運行 OpenObserve。對於使用 API 獲取數據並執行搜索的用戶來說,OpenObserve 可以無縫替代 Elasticsearch。OpenObserve 帶有自己的用戶界面,無需單獨安裝。與 Elasticsearch 相比,使用 OpenObserve 可以將日誌存儲成本降低約 140 倍。
相關概念
在詳細瞭解 O2
之前,我們需要了解一些相關概念,這些概念是 O2
的基礎。
Organizations(組織)
組織是 OpenObserve 中對各種流、用戶、功能進行分組的邏輯實體。組織可以代表一個企業、企業的一個部門或一個應用程序。所有流、用戶、功能等都限定在一個組織範圍內。
Streams(流)
OpenObserve 中的流是共享相同源的事件序列(日誌 / 指標 / 跟蹤),例如來自特定應用程序的日誌或來自企業的日誌。比如日誌就是一種流,用於記錄來自應用程序的事件。
Functions(函數)
OpenObserve 中的函數可在攝取和查詢期間使用,以幫助增強高級功能,如豐富、編輯、日誌縮減、合規性等。函數是使用 VRL
腳本定義的。
Parquet
O2
中的數據以 parquet
格式存儲,這是一種列式存儲格式,查詢和存儲效率很高。
Timestamp(時間戳)
_timestamp
在 OpenObserve 中被視爲時間戳列,如果 _timestamp
或 @timestamp
不存在於正在攝取的數據中,我們會將 _timestamp
添加到每個記錄,其 NOW
值爲微秒精度。
對於鍵爲 _timestamp/@timestamp
的輸入數據,對於值我們支持以下數據類型 / 格式:
-
微秒
-
字符串值
-
RFC 3339 和 ISO 8601 日期和時間字符串,例如
1996-12-19T16:39:57-08:00
-
RFC 2822 日期和時間字符串,例如
Tue, 1 Jul 2003 10:52:37 +0200
如果用戶想要支持 _timestamp/@timestamp
以外的鍵,用戶可以使用 ZO_COLUMN_TIMESTAMP
配置來指定時間戳鍵。
User Roles(用戶角色)
OpenObserve 中的用戶可以具有 admin
或 member
角色。與具有 member
角色的用戶相比,具有 admin
角色的用戶擁有更大的權限,例如,具有 admin
角色的用戶可以將其他用戶添加到組織中。
架構
OpenObserve 可以在單節點下運行,也可以在集羣中以 HA 模式運行。
單節點模式
單節點模式也分幾種架構,主要是數據存儲的方式不同,主要有如下幾種:
SQLite 和本地磁盤模式
如果你只需要進行簡單使用和測試,或者對高可用性沒有要求,可以使用此模式。當然你仍然可以在一臺機器上每天處理超過 2 TB 的數據。在我們的測試中,使用默認配置,Mac M2 的處理速度爲約 31 MB / 秒,即每分鐘處理 1.8 GB,每天處理 2.6 TB。該模式也是運行 OpenObserve 的默認模式。
SQLite 和對象存儲模式
該模式和 OpenObserve 的默認模式基本上一致,只是數據存在了對象存儲中,這樣可以更好的支持高可用性,因爲數據不會丟失。
高可用模式
HA 模式不支持本地磁盤存儲,該模式下,OpenObserve 主要包括 Router
、Querier
、Ingester
、Compactor
和 AlertManager
節點(組件),這些節點都可以水平擴展以適應更高的流量。另外使用 Etcd 或 NATS 用作集羣協調器並存儲節點信息,還用於集羣事件。MySQL/PostgreSQL 用於存儲組織、用戶、函數、報警規則、流模式和文件列表(parquet
文件的索引)等元數據。對象存儲(例如 s3、minio、gcs 等)存儲 parquet
文件的數據。
Ingester
Ingester
用於接收攝取請求並將數據轉換爲 parquet
格式然後存儲在對象存儲中,它們在將數據傳輸到對象存儲之前將數據臨時存儲在 WAL
中。
OpenObserve 中攝取的數據默認根據年月日和小時進行分區,我們還可以指定用於對數據進行分區的分區鍵。
數據攝取流程如下所示:
-
從 HTTP / gRPC API 請求接收數據。
-
逐行解析數據。
-
檢查是否有任何用於轉換數據的函數(攝取函數),按函數順序調用每個攝取函數
-
檢查時間戳字段,將時間戳轉換爲微秒;如果記錄中不存在時間戳字段,則設置當前時間戳。
-
檢查流 schema 以確定 schema 是否需要演變。在這裏,如果我們發現需要更新 schema 以添加新字段或更改現有字段的數據類型,則獲取
lock
來更新 schema。 -
評估實時報警(如果爲流定義了任何報警)。
-
按小時桶中的時間戳寫入
WAL
文件,然後將請求中的記錄轉換爲Arrow RecordBatch
並寫入Memtable
。
-
爲每個
organization/stream_type
創建Memtable
,如果僅爲日誌攝取數據,則只有一個Memtable
。 -
WAL 文件和
Metable
是成對創建的,一個 WAL 文件有一個Memtable
。WAL 文件位於data/wal/logs
。
-
當
Memtable
大小達到ZO_MAX_FILE_SIZE_IN_MEMORY = 256MB
或 WAL 文件達到ZO_MAX_FILE_SIZE_ON_DISK = 128MB
時,我們將Memtable
移動到Immutable
並創建一個新的Memtable
和 WAL 文件用於寫入數據。 -
每
ZO_MEM_PERSIST_INTERVAL=5
秒會將Immutable
轉儲到本地磁盤。一個Immutable
將生成多個parquet
文件,因爲它可能包含多個流和多個分區,parquet
文件位於data/wal/files
。 -
每
ZO_FILE_PUSH_INTERVAL=10
秒,我們檢查本地parquet
文件,如果任何分區總大小超過ZO_MAX_FILE_SIZE_ON_DISK=128MB
或任何文件已在ZO_MAX_FILE_RETENTION_TIME=600
秒前,分區中的所有此類小文件將被合併爲一個大文件(每個大文件將最大爲ZO_COMPACT_MAX_FILE_SIZE=256MB
) ,它將被移動到對象存儲。
Ingester 包含三部分數據:
-
Memtable
中的數據 -
Immutable
中的數據 -
WAL 中的
parquet
文件尚未上傳到對象存儲。
這些數據都需要能夠被查詢到。
Router
Router
(路由器)將請求分發給 ingester
或 querier
,它還通過瀏覽器提供 UI 界面,Router 實際上就是一個非常簡單的代理,用於在攝取器和查詢器之間發送適當的請求。
Querier
Querier
(查詢器)用於查詢數據,查詢器節點是完全無狀態的。數據查詢流程如下:
-
使用 http API 接收搜索請求。接收到查詢請求的節點成爲該查詢的
LEADER
查詢器。其他查詢器都是WORKER
查詢器,用於查詢。 -
LEADER
解析並驗證 SQL。 -
LEADER
找到數據時間範圍並從文件列表索引中獲取文件列表。 -
LEADER
從集羣元數據中獲取查詢器節點。 -
LEADER
對每個查詢器要查詢的文件列表進行分區。例如如果需要查詢 100 個文件,並且有 5 個查詢器節點,則每個查詢器可以查詢 20 個文件,LEADER
處理 20 個文件,WORKERS
各處理 20 個文件。 -
LEADER
調用每個WORKER
查詢器上運行的 gRPC 服務,將搜索查詢分派到查詢器節點。查詢器間通信使用 gRPC 進行。 -
LEADER
收集、合併並將結果發送回用戶。
提示:
-
默認情況下,查詢器將在內存中緩存
parquet
文件。我們可以使用環境變量ZO_MEMORY_CACHE_MAX_SIZE
配置查詢器用於緩存的內存大小。默認緩存是使用特定查詢器可用內存的 50% 來完成的。 -
在分佈式環境中,每個查詢器節點只會緩存一部分數據。
-
我們還可以選擇在內存中緩存最新的
parquet
文件。當Ingester
生成新的Parquet
文件並將其上傳到對象存儲時,Ingester
將通知查詢器緩存該文件。
Compactor
Compactor
(壓縮器)會將小文件合併成大文件,使搜索更加高效。Compactor
還處理數據保留策略、full stream 刪除和文件列表索引更新。
AlertManager
AlertManager
運行標準報警查詢、報告作業併發送通知。
安裝
由於 O2
用到的各個存儲可選方案較多,這裏我們選擇使用 PostgreSQL
作爲元數據存儲,Minio
作爲對象存儲,Nats
作爲集羣協調器(建議使用 Nats
,爲了向後兼容,目前仍然支持 Etcd
)。
接下來同樣我們使用 Helm
來安裝 O2
:
helm repo add openobserve https://charts.openobserve.ai
helm repo update
官方的這個 Helm Chart 默認會部署 PostgreSQL,但是需要提前安裝對應的 cloudnative-pg operator
:
kubectl apply --server-side -f \
https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.23/releases/cnpg-1.23.1.yaml
然後我們就可以在 Helm Chart 中使用 PostgreSQL 了,此外爲了啓用 Minio
和 Nats
,我們需要在 values.yaml
中進行配置,修改後的 values.yaml
如下所示
# o2-values.yaml
# auth:
# ZO_ROOT_USER_EMAIL: "root@example.com" # default user email
# ZO_ROOT_USER_PASSWORD: "Complexpass#123" # default user password
ingester:
headless:
enabled: true
persistence:
enabled: true
storageClass: "nfs-client"
querier:
persistence: # If enabled it will be used for disk cache. Highly recommend to enable this for production
enabled: true
storageClass: "nfs-client"
service:
type: NodePort
nats:
enabled: true
container:
image:
repository: library/nats
registry: dhub.kubesre.xyz
config:
cluster:
enabled: true
replicas: 3
jetstream:
enabled: true
fileStore:
enabled: true
pvc:
enabled: true
size: 20Gi
storageClassName: "nfs-client"
natsBox:
container:
image:
registry: dhub.kubesre.xyz
reloader:
image:
registry: dhub.kubesre.xyz
minio:
enabled: true # if true then minio will be deployed as part of openobserve
mode: standalone # or distributed
persistence:
storageClass: "nfs-client"
consoleService:
type: NodePort
nodePort: 32001
# Postgres is used for storing openobserve metadata.
# Make sure to install cloudnative-pg operator before enabling this
postgres:
enabled: true
pgadmin:
enabled: false
spec:
instances: 2 # creates a primary and a replica. replica will become primary if the primary fails
storage:
size: 10Gi
pvcTemplate:
storageClassName: "nfs-client"
然後我們就可以安裝 O2
了:
$ helm upgrade --install o2 openobserve/openobserve -f o2-values.yaml --namespace openobserve --create-namespace
Release "o2" does not exist. Installing it now.
NAME: o2
LAST DEPLOYED: Sat Aug 24 17:29:23 2024
NAMESPACE: openobserve
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
export NODE_PORT=$(kubectl get --namespace openobserve -o jsonpath="{.spec.ports[0].nodePort}" services o2-openobserve)
export NODE_IP=$(kubectl get nodes --namespace openobserve -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
安裝完成後,我們可以通過 kubectl get pods -n openobserve
查看所有的 Pod 是否正常運行。
$ kubectl get pods -n openobserve
NAME READY STATUS RESTARTS AGE
o2-minio-5ff8c55559-g6255 1/1 Running 0 43m
o2-nats-0 2/2 Running 0 32m
o2-nats-1 2/2 Running 0 33m
o2-nats-2 2/2 Running 0 33m
o2-nats-box-588fb755c4-6qxl2 1/1 Running 0 43m
o2-openobserve-alertmanager-95796f856-c6xlg 1/1 Running 0 43m
o2-openobserve-compactor-7f9b8cdb6b-kr8sp 1/1 Running 0 31m
o2-openobserve-ingester-0 1/1 Running 0 32m
o2-openobserve-postgres-1 1/1 Running 0 43m
o2-openobserve-postgres-2 1/1 Running 0 42m
o2-openobserve-querier-0 1/1 Running 0 43m
o2-openobserve-router-58dc4b8fd7-vl42p 1/1 Running 0 31m
$ kubectl get svc -n openobserve
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
o2-minio ClusterIP 10.96.2.46 <none> 9000/TCP 43m
o2-minio-console NodePort 10.96.0.196 <none> 9001:32001/TCP 43m
o2-nats ClusterIP 10.96.2.18 <none> 4222/TCP 43m
o2-nats-headless ClusterIP None <none> 4222/TCP,6222/TCP,8222/TCP 43m
o2-openobserve-alertmanager ClusterIP 10.96.1.79 <none> 5080/TCP,5081/TCP,5082/TCP 43m
o2-openobserve-compactor ClusterIP 10.96.0.207 <none> 5080/TCP,5081/TCP 43m
o2-openobserve-ingester ClusterIP 10.96.2.154 <none> 5080/TCP,5081/TCP 43m
o2-openobserve-ingester-headless ClusterIP None <none> 5080/TCP,5081/TCP 43m
o2-openobserve-postgres-r ClusterIP 10.96.0.123 <none> 5432/TCP 43m
o2-openobserve-postgres-ro ClusterIP 10.96.3.208 <none> 5432/TCP 43m
o2-openobserve-postgres-rw ClusterIP 10.96.0.165 <none> 5432/TCP 43m
o2-openobserve-querier ClusterIP 10.96.3.13 <none> 5080/TCP,5081/TCP 43m
o2-openobserve-router NodePort 10.96.3.228 <none> 5080:31984/TCP,5081:32212/TCP 43m
使用
安裝完成後,我們可以通過 http://<NODE_IP>:31984
訪問 O2
的 Web 界面,然後就可以開始使用了。
使用默認的用戶名 root@example.com
和密碼 Complexpass#123
登錄,然後就可以看到 O2
的主界面了。
因爲現在我們還沒有向 O2
中發送任何數據,所以暫時沒有任何數據。我們可以切換到採集頁面,裏面就有各種遙測數據的採集方式。
示例數據導入
這裏我們可以先使用 JSON API 來加載一些示例日誌數據來了解一下 OpenObserve 的基本使用方法。先使用下面命令下載示例日誌數據:
$ curl -L https://zinc-public-data.s3.us-west-2.amazonaws.com/zinc-enl/sample-k8s-logs/k8slog_json.json.zip -o k8slog_json.json.zip
$ unzip k8slog_json.json.zip
然後使用下面命令將示例日誌數據導入到 OpenObserve 中:
$ curl http://<NodeIP>:31984/api/default/default/_json -i -u "root@example.com:Complexpass#123" -d "@k8slog_json.json"
HTTP/1.1 100 Continue
HTTP/1.1 200 OK
content-length: 71
content-type: application/json
x-api-node: o2-openobserve-ingester-0
access-control-allow-credentials: true
date: Sat, 24 Aug 2024 10:31:05 GMT
vary: accept-encoding
{"code":200,"status":[{"name":"default","successful":3846,"failed":0}]}%
收據導入成功後,刷新頁面即可看到有數據了:
在數據流頁面可以看到我們導入的數據元信息:
然後切換到日誌頁面,從左側的下拉列表中選擇索引爲 default
,就可以看到日誌數據了:
現在我們就可以去根據直接的需求去查詢日誌了,比如要使用倒排索引搜索包含單詞 error
的所有字段:
-
在查詢編輯器中使用
match_all('error')
-
match_all
僅搜索配置爲全文搜索的字段。默認字段集包括log
、message
、content
、data
、events
、json
。如果你希望全文搜索時掃描更多字段,可以在數據流頁面進行配置。在特定字段中進行全文搜索應該使用str_match
函數。
要在沒有倒排索引的情況下搜索包含單詞 error
的所有字段:
-
match_all_raw('error')
,區分大小寫。 -
match_all_raw_ignore_case(error)
,這是不區分大小寫的。 -
match_all_raw
函數僅搜索配置爲全文搜索的字段。默認字段集是log
、message
、content
、data
、events
、json
。如果希望全文搜索時掃描更多字段,可以在數據流設置下進行配置。應該使用str_match
在指定字段中進行全文搜索。
如果僅搜索 log
字段中的 error
,可以使用 str_match(log, 'error')
,這比 match_all_raw
更有效,因爲它在單個字段中搜索。
同樣如果我們要搜索包含 code
爲 200 的所有日誌條目,則可以直接使用 code=200
查詢即可,其中 code
是一個數字字段。如果要搜索 code
字段不包含任何值的所有日誌條目,可以使用 code is null
,但是需要注意使用 code=' '
不會產生正確的結果;同樣的搜索 code
字段具有某個值的所有日誌條目,則可以使用 code is not null
,但是不能使用 code!=' '
。另外也可以使用 code > 399
或者 code >= 400
來搜索 code
大於 399 或者大於等於 400 的所有日誌條目。
此外我們還可以勾選 SQL 模式
來使用 SQL 查詢語句來查詢日誌數據:
同樣現在我們可以去 Minio 中查看數據是否已經被正確的存儲,使用用戶名 rootuser
和密碼 rootpass123
即可登錄成功。
可以看到對象存儲中已經有了我們的 parquet
文件數據。
採集 Kubernetes 觀測數據
O2
還支持通過 OpenTelemetry 採集器導入數據。這裏我們可以使用 OpenTelemetry
來採集 Kubernetes 集羣的觀測數據,首先我們需要安裝 OpenTelemetry
的 Operator
,由於 OpenTelemetry
的 Operator
依賴 cert-manager
,所以我們需要先安裝 cert-manager
:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.1/cert-manager.yaml
等待 cert-manager
安裝完成後,我們就可以安裝 OpenTelemetry
的 Operator
了:
$ kubectl get pods -n cert-manager
NAME READY STATUS RESTARTS AGE
cert-manager-cainjector-65c7bff89d-rxjts 1/1 Running 0 64s
cert-manager-cbcf9668d-tlz2k 1/1 Running 0 64s
cert-manager-webhook-594cb9799b-c5sd8 1/1 Running 0 64s
$ kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/latest/download/opentelemetry-operator.yaml
$ kubectl get pods -n opentelemetry-operator-system
NAME READY STATUS RESTARTS AGE
opentelemetry-operator-controller-manager-fd5689558-lchr7 2/2 Running 0 61s
然後我們就可以來安裝 OpenTelemetry 的 Collector
了,爲了方便使用 O2 官方的 Helm Chart 已經提供了一個定製的 Chart 包,我們可以直接使用它,該採集器可以:
-
從 K8s 集羣中捕獲日誌、指標和 Events 事件並將其發送到 O2
-
在集羣中配置
auto-instrumentation
自動埋點,以捕獲Java
、.Net
、nodejs
、python
和Go
語言編寫的應用程序的鏈路追蹤
使用我們這裏安裝的 O2 集羣的認證信息覆蓋默認的認證信息:
# o2c-values.yaml
exporters:
otlphttp/openobserve:
endpoint: http://o2-openobserve-router.openobserve.svc.cluster.local:5080/api/default
headers:
Authorization: Basic cm9vdEBleGFtcGxlLmNvbTpScmtORWxpenhCWWV4Qzhr # 替換成自己的
stream-name: k8s_logs # 替換成自己的數據流名稱
otlphttp/openobserve_k8s_events:
endpoint: http://o2-openobserve-router.openobserve.svc.cluster.local:5080/api/default
headers:
Authorization: Basic cm9vdEBleGFtcGxlLmNvbTpScmtORWxpenhCWWV4Qzhr # 替換成自己的
stream-name: k8s_events
agent:
enabled: true
tolerations: # 如果需要在 master 節點上運行,需要添加這個容忍
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
其中 endpoint
地址爲 O2
的 router
的 FQDN 地址,Authorization
中 Basic
後面 的值爲用戶名:TOKEN
的 base64
編碼(可以在 O2
採集頁面獲取),stream-name
爲數據流名稱。然後直接使用下面命令安裝 OpenTelemetry
的 Collector
即可:
$ helm upgrade --install o2c openobserve/openobserve-collector -f o2c-values.yaml --namespace openobserve-collector --create-namespace
Release "o2c" does not exist. Installing it now.
NAME: o2c
LAST DEPLOYED: Sun Aug 25 10:30:59 2024
NAMESPACE: openobserve-collector
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
If everything proceeded without errors then your cluster is now sending logs and metrics to OpenObserve.
You can add following to your pods/namespaces to auto instrument your applications to send traces:
1. Java: instrumentation.opentelemetry.io/inject-java: "openobserve-collector/openobserve-java"
2. NodeJS: instrumentation.opentelemetry.io/inject-nodejs: "openobserve-collector/openobserve-nodejs"
3. Python: instrumentation.opentelemetry.io/inject-python: "openobserve-collector/openobserve-python"
4. DotNet: instrumentation.opentelemetry.io/inject-dotnet: "openobserve-collector/openobserve-dotnet"
5. Go: instrumentation.opentelemetry.io/inject-go: "openobserve-collector/openobserve-go" , instrumentation.opentelemetry.io/otel-go-auto-target-exe: "/path/to/container/executable"
6. OpenTelemetry SDK environment variables only: instrumentation.opentelemetry.io/inject-sdk: "true"
我們可以查看 OpenTelemetry
的 Collector
是否正常運行:
$ kubectl get pods -n openobserve-collector
NAME READY STATUS RESTARTS AGE
o2c-openobserve-collector-agent-collector-46r82 1/1 Running 0 10m
o2c-openobserve-collector-agent-collector-cbtnn 1/1 Running 0 10m
o2c-openobserve-collector-agent-collector-kkczz 1/1 Running 0 10m
o2c-openobserve-collector-gateway-collector-0 1/1 Running 0 10m
o2c-openobserve-collector-gateway-targetallocator-59c4468dxmfts 1/1 Running 0 10m
其實這裏我們部署的採集器就是一個 agent
和一個 gateway
,在前面的額 OpenTelemetry 章節已經學習過了,只是這裏我們是將數據導出到了 O2
中。
現在我們就可以去 O2
中查看我們的數據了,切換到數據流頁面,可以看到我們的數據流已經被成功的導入了:
可以看到現在我們的數據流中已經有了 k8s_logs
和 k8s_events
兩個日誌數據流,分別對應我們的日誌和事件數據。除此之外還有很多 metrics
類型的數據流,可以看到指標中的每一個標籤都是一個獨立的 stream
數據流。
我們可以切換到日誌頁面,選擇數據流 k8s_logs
,就可以看到我們採集的 K8s 集羣的日誌數據了:
同樣我們選擇數據流 k8s_events
,就可以看到我們採集的 K8s 集羣的事件數據了:
對於指標數據流,我們可以切換到指標頁面,選擇數據流 k8s_metrics
,就可以看到我們採集的 K8s 集羣指標數據了:
左側我們可以選擇一個指標,然後就可以看到這個指標的標籤列表,然後我們就可以在右側填寫 PromQL 語句來查詢數據了,比如我們這裏查詢每個命名空間的內存使用情況,則可以使用下面的 PromQL 語句:
sum(k8s_pod_memory_usage) by (k8s_namespace_name)
查詢結果如下圖所示:
如果我們需要經常查詢這個指標,這可以將其添加到儀表盤中,點擊頁面中的添加到儀表盤按鈕即可,然後在儀表盤頁面就可以看到我們的儀表盤了:
和 Grafana 類似,我們也可以編輯面板,在面板右上角點擊Edit Panel
,就可以進入面板編輯頁面了,點擊最右側的配置按鈕,就可以編輯面板了,比如我們這裏可以選擇圖例的單位、圖例的顯示名稱等,編輯後可以點擊應用按鈕預覽,如果滿意可以點擊保存按鈕保存:
同樣我們也可以和 Grafana 一樣配置一個變量,然後在面板上展示這個變量,比如我們這合理可以添加一個 namespace
變量,其值可以從 k8s_namespace_phase
這個數據流中獲取,如下圖所示:
當然現在我們需要去修改下面板的 PromQL 查詢語句,需要將變量 namespace
傳入,更改成:sum(k8s_pod_memory_usage{k8s_namespace_name =~ "$namespace"}) by (k8s_namespace_name)
即可:
現在我們就可以在面板上通過篩選 namespace
變量來查看不同命名空間的內存使用情況了:
接下來還有鏈路追蹤的數據,因爲上面我們安裝的 OpenTelemetry
的 Collector
已經自動爲我們創建了自動埋點的 Instrumentation
對象,如下所示:
$ kubectl get instrumentation -n openobserve-collector
NAME AGE ENDPOINT SAMPLER SAMPLER ARG
openobserve-dotnet 99m http://o2c-openobserve-collector-gateway-collector.openobserve-collector.svc.cluster.local:4318 parentbased_traceidratio 1
openobserve-go 99m http://o2c-openobserve-collector-gateway-collector.openobserve-collector.svc.cluster.local:4318 parentbased_traceidratio 1
openobserve-java 99m http://o2c-openobserve-collector-gateway-collector.openobserve-collector.svc.cluster.local:4318 parentbased_traceidratio 1
openobserve-nodejs 99m http://o2c-openobserve-collector-gateway-collector.openobserve-collector.svc.cluster.local:4317 parentbased_traceidratio 1
openobserve-python 99m http://o2c-openobserve-collector-gateway-collector.openobserve-collector.svc.cluster.local:4318 parentbased_traceidratio 1
可以看到上面的 Instrumentation
對象已經配置了端點地址、採樣器和採樣器參數,地址就是我們的 OpenTelemetry
的 Collector
的地址(gateway
類型的),採樣器是 parentbased_traceidratio
,參數是 1
,表示採樣率爲 1
。
針對上面的這些語言編寫的應用,我們就可以進行自動埋點,只需要在應用的 Pod
中添加對應的 Annotation
即可:
-
Java:
instrumentation.opentelemetry.io/inject-java: "openobserve-collector/openobserve-java"
-
DotNet:
instrumentation.opentelemetry.io/inject-dotnet: "openobserve-collector/openobserve-dotnet"
-
NodeJS:
instrumentation.opentelemetry.io/inject-nodejs: "openobserve-collector/openobserve-nodejs"
-
Python:
instrumentation.opentelemetry.io/inject-python: "openobserve-collector/openobserve-python"
-
Go (Uses eBPF):
-
instrumentation.opentelemetry.io/inject-go: "openobserve-collector/openobserve-go"
-
instrumentation.opentelemetry.io/otel-go-auto-target-exe: "/path/to/container/executable"
這裏我們可以部署一個微服務 HOT Commerce 來演示在 Kubernetes 環境中如何使用 OpenTelemetry Operator 進行自動埋點,並將數據發送到 OpenObserve 中。
這個應用包含 5 個簡單的微服務,每個微服務都是用不同的編程語言編寫的:
/-> review (python)
/
frontend (go) -> shop (nodejs) -> product (java)
\
\-> price (dotnet)
該應用對應的 Kubernetes 資源清單文件如下:
# hotcommerce.yaml
apiVersion: v1
kind: Service
metadata:
name: price
namespace: hotcommerce
spec:
selector:
app: price
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: price
namespace: hotcommerce
spec:
replicas: 1
selector:
matchLabels:
app: price
template:
metadata:
labels:
app: price
annotations:
instrumentation.opentelemetry.io/inject-dotnet: "openobserve-collector/openobserve-dotnet"
spec:
containers:
- name: price
image: public.ecr.aws/zinclabs/sample-price-service-dotnet:3
imagePullPolicy: Always
ports:
- containerPort: 80
resources:
limits:
cpu: "1"
memory: "544Mi"
requests:
cpu: "100m"
memory: "448Mi"
---
apiVersion: v1
kind: Service
metadata:
name: review
namespace: hotcommerce
spec:
selector:
app: review
ports:
- protocol: TCP
port: 80
targetPort: 8004
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: review
namespace: hotcommerce
spec:
replicas: 1
selector:
matchLabels:
app: review
template:
metadata:
labels:
app: review
annotations:
instrumentation.opentelemetry.io/inject-python: "openobserve-collector/openobserve-python"
spec:
containers:
- name: review
image: public.ecr.aws/zinclabs/sample-review-service:51
imagePullPolicy: Always
ports:
- containerPort: 8004
resources:
limits:
cpu: "1"
memory: "544Mi"
requests:
cpu: "100m"
memory: "448Mi"
---
apiVersion: v1
kind: Service
metadata:
name: product
namespace: hotcommerce
spec:
selector:
app: product
ports:
- protocol: TCP
port: 80
targetPort: 8003
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: product
namespace: hotcommerce
spec:
replicas: 1
selector:
matchLabels:
app: product
template:
metadata:
labels:
app: product
annotations:
instrumentation.opentelemetry.io/inject-java: "openobserve-collector/openobserve-java"
spec:
containers:
- name: product
image: public.ecr.aws/zinclabs/sample-product-service-java:53
imagePullPolicy: Always
env:
- name: REVIEW_SERVICE_URL
value: "http://review.hotcommerce.svc.cluster.local"
- name: PRICE_SERVICE_URL
value: "http://price.hotcommerce.svc.cluster.local"
ports:
- containerPort: 8003
resources:
limits:
cpu: "1"
memory: "1048Mi"
requests:
cpu: "100m"
memory: "1048Mi"
---
apiVersion: v1
kind: Service
metadata:
name: shop
namespace: hotcommerce
spec:
selector:
app: shop
ports:
- protocol: TCP
port: 80
targetPort: 8002
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: shop
namespace: hotcommerce
spec:
replicas: 1
selector:
matchLabels:
app: shop
template:
metadata:
labels:
app: shop
annotations:
instrumentation.opentelemetry.io/inject-nodejs: "openobserve-collector/openobserve-nodejs"
spec:
containers:
- name: shop
image: public.ecr.aws/zinclabs/sample-shop-service-nodejs:51
imagePullPolicy: Always
env:
- name: PRODUCT_SERVICE_URL
value: "http://product.hotcommerce.svc.cluster.local"
ports:
- containerPort: 8002
resources:
limits:
cpu: "1"
memory: "544Mi"
requests:
cpu: "100m"
memory: "448Mi"
---
apiVersion: v1
kind: Service
metadata:
name: frontend
namespace: hotcommerce
spec:
type: NodePort
selector:
app: frontend
ports:
- protocol: TCP
port: 80
targetPort: 8001
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: hotcommerce
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
annotations:
instrumentation.opentelemetry.io/inject-go: "openobserve-collector/openobserve-go"
instrumentation.opentelemetry.io/otel-go-auto-target-exe: "/app"
spec:
containers:
- name: frontend
image: public.ecr.aws/zinclabs/sample-frontend-service-go:51
imagePullPolicy: Always
env:
- name: SHOP_SERVICE_URL
value: "http://shop.hotcommerce.svc.cluster.local"
ports:
- containerPort: 8001
resources:
limits:
cpu: "1"
memory: "543Mi"
requests:
cpu: "100m"
memory: "438Mi"
注意上面的每個 Deployment 應用中,我們都添加了對應的 instrumentation.opentelemetry.io/inject-xxx
的 Annotation
,這樣就可以實現自動埋點了。
直接使用下面命令部署 HOT Commerce 應用即可:
kubectl create ns hotcommerce
kubectl apply -f hotcommerce.yaml
部署完成後,我們先查看所有的服務是否正常運行:
$ kubectl get pods -n hotcommerce
NAME READY STATUS RESTARTS AGE
frontend-57c47854f7-8cwbp 1/1 Running 0 6m56s
price-5d99b949b8-gzqr6 1/1 Running 0 6m56s
product-85f94894f-7s8hw 1/1 Running 0 6m56s
review-98bc7596f-ptbhk 1/1 Running 0 6m57s
shop-966895886-hgpxt 1/1 Running 0 6m56s
$ kubectl get svc -n hotcommerce
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend NodePort 10.96.3.25 <none> 80:30826/TCP 4m42s
price ClusterIP 10.96.1.147 <none> 80/TCP 4m43s
product ClusterIP 10.96.3.134 <none> 80/TCP 4m42s
review ClusterIP 10.96.1.22 <none> 80/TCP 4m43s
shop ClusterIP 10.96.2.4 <none> 80/TCP 4m42s
我們可以通過 http://<NodeIP>:30826
訪問 frontend
服務了,當我們訪問 frontend
服務時,OpenTelemetry
會自動爲我們的應用程序生成鏈路追蹤數據,並將其發送到 OpenTelemetry Collector,然後 Collector 會將數據發送到 OpenObserve 中。
$ curl http://192.168.0.111:30826/item/1
{"description":"This is a sample product.","id":1,"in_stock":10,"name":"Sample Product","price":100,"rating":5,"review":"This is a great product!","warehouse_location":"A1-B2"}
然後我們就可以在 O2
中查看到有 traces
類型的數據流了。切換到追蹤頁面,就可以看到我們採集到的鏈路追蹤數據了:
點擊一個 Trace ID,就可以查看這個鏈路追蹤的詳細信息了:
這裏我們可以看到這個鏈路追蹤的詳細信息,包括每個服務的調用時間、調用耗時、調用結果等信息。
到這裏我們就實現了在 OpenObserve 中查看我們的 K8s 集羣的觀測數據,當然同樣的對於非 K8s 集羣的應用也可以直接將數據採集到 OpenObserve 中,比如 Fluentd、Vector、Prometheus、OpenTelemetry Collector 等。
此外 O2 還有很多其他功能,比如報警、函數、前端性能監控等,可以關注後續文章。
參考文檔
https://openobserve.ai/docs/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/pNliVYhA9-aYaxubPJ9FMg