原文作者:Raúl Marrero Rodríguez of F5
原文連結:采用 NGINX Ingress Controller for Kubernetes 支援 OpenTracing? - NGINX
轉載來源:NGINX 官方網站
摘要
近年來,許多企業紛紛在生産環境中采用該平台與微服務架構。然而,采用分布式服務也帶來了新的挑戰。想要識别故障或性能問題,我們需要分布式的追蹤工具。
OpenTracing 是一個用于分布式跟蹤的規範和api集。為了在使用 NGINX 和 NGINX Plus Ingress Controllers for Kubernetes 時對叢集中的流量執行負載均衡,我們在 Kubernetes 叢集中添加了對 HTTP 和 gRPC 請求 OpenTracing 的原生支援。
使用Open Tracing現有多種用例,本文将重點讨論如何使用請求上下文傳播跟蹤伺服器端點。
近年來,Kubernetes 的關注度穩健增長日益獲得業内青睐,許多企業紛紛在生産環境中采用該平台與微服務架構。然而,采用分布式服務也帶來了新的挑戰。充分了解和調試微服務應用程式的運作并非易事,尤其在服務數量多的情況下。想要識别故障或性能問題,我們需要分布式的追蹤工具 —— 當資料在構成應用的微服務之間傳輸時,這個工具能夠端到端地追蹤請求。
OpenTracing 是一個用于分布式跟蹤的規範和api集。在此前發表的一篇博文中,我們展示了如何使用OpenTracing社群建立的開源子產品(nginx-opentracing 為 NGINX Open Source 和 NGINX Plus 代理和負載平衡的應用程式啟用分布式跟蹤。在撰寫本文時,OpenTracing 提供 9 種程式設計語言的類庫。
現在,為了在使用 NGINX 和 NGINX Plus Ingress Controllers for Kubernetes 時對叢集中的流量執行負載均衡,我們還在 Kubernetes 叢集中添加了對 HTTP 和 gRPC 請求 OpenTracing 的原生支援。
使用 OpenTracing 現有多種用例,此處我們将重點讨論如何使用請求上下文傳播跟蹤伺服器端點。在分布式環境中,叢集内的每個應用均被視為不同的伺服器。設想一下,兩個應用或服務都參與處理來自用戶端的請求。例如,在下圖所示拓撲結構中,應用 1 是一台 既可處理 HTTP 請求并将其重定向至應用 2 的 Web 伺服器。這兩個應用均在 NGINX Ingress Controller 所執行負載均衡的 Kubernetes 叢集中運作,并啟用了 OpenTracing。是以我們可在來自 Ingress Controller 的請求通過應用 1 并到達應用 2 時對其進行跟蹤。
有關系統元件執行的任何操作(例如服務)的資訊将會被 OpenTracing 所謂的 span 捕獲。将這些 span 連結在一起,我們即可在資訊穿過叢集微服務的整個過程中對其進行識别和跟蹤。
注:在撰寫本文時,OpenTracing 僅在 NGINX Ingress Controller 的 edge 版本中可用。
将 OpenTracing 建構到 NGINX Ingress Controller 鏡像中
搭配使用 OpenTracing 和我們的 Ingress Controller 需要将 OpenTracing 子產品結合到 NGINX 或 NGINX Plus Ingress Controller 的 Docker 鏡像中,并指定所用跟蹤器。
在 Ingress Controller 的 GitHub 存儲庫中,我們為 NGINX 和 NGINX Plus 提供了單獨的 Dockerfile。雖然二者均将開源 OpenTracing 子產品整合到 Docker 鏡像中,但處理的方式不同:
- 在 NGINX 系統中,DockerfileWithOpentracing 從 GitHub 下載下傳 OpenTracing 子產品,并在 Docker 的第一階段建構中對其進行手動彙集。
- 在 NGINX Plus 系統中,DockerfileWithOpentracingForPlus 使用軟體保管系統擷取 NGINX 使用開源和 OpenTracing 子產品所建構并維護的動态子產品。
執行以下步驟:
- (可選)指定一個 Jaeger 預設以外的跟蹤器。插件也适用于 Datadog、LightStep 和 Zipkin。使用不同的跟蹤器需根據 OpenTracing 啟用說明中前提條件部分修改 Dockerfile。
-
遵照 Ingress Controller 存儲庫中的說明建構 Docker 鏡像。在第 3 步中,需指定相應的 Dockerfile。
NGINX:
$ make clean
$ make DOCKERFILE=DockerfileWithOpentracing PREFIX=YOUR-PRIVATE-REGISTRY/nginx-ingress
NGINX Plus:
$ make clean
$ make DOCKERFILE=DockerfileWithOpentracingForPlus PREFIX=YOUR-PRIVATE-REGISTRY/nginx-plus-ingress
3. 按照 Ingress Controller 存儲庫中的說明安裝鏡像。
在運作說明第 3 節中的 kubectlapply 指令前,切記更新 YAML 檔案,以指定已引入 OpenTracing 的建立鏡像:
containers:
- image: IMAGE_WITH_OPENTRACING
部署 Jaeger 跟蹤器
本博文所使用的是 Jaeger 預設跟蹤器。為簡單起見,我們将其部署在叢集内部,但也您也可以将其部署在叢集外部。Ingress Controller Pod 和任何使用 OpenTracing 的 Pod 必須有通路跟蹤器的權限。
同樣為簡單起見,我們将使用 Jaeger 提供的一體化模版在叢集中設立非生産 Jaeger 執行個體。最終适合開發環境的部署将建立一個 Jaeger Pod 及通路該 Pod 所需的服務,并在預設命名空間中設立最新 Jaeger 版本,其具有記憶體存儲容量和有限功能。
$ kubectl create -f https://raw.githubusercontent.com/jaegertracing/jaeger-kubernetes/master/all-in-one/jaeger-all-in-one-template.yml
在生産環境中,我們推薦使用 Jaeger Operator 進行安裝。擷取更多有關 Jaeger 的資訊,請通路 Jaeger 網站。
啟用 OpenTracing
以下針對 NGINX Ingress Controller 的 ConfigMap (nginx-config.yaml) 全局啟用 OpenTracing,并在 data部分中添加了三個新的 ConfigMap 鍵名:
- opentracing 鍵為所有在叢集中建立的 Ingress 資源啟用 OpenTracing。
- opentracing-tracer 鍵指定前往跟蹤器庫路徑,并在您建構它時将跟蹤器庫下載下傳并複制到 Ingress 控制器鏡像中。
- opentracing-tracer-config 鍵嵌入了跟蹤器配置。service_name 字段定義與實際 span 相關的服務;reporter 字段指定跟蹤器位址和端口(在此示例中是上一部分 Jaeger 服務一體式模闆部署的的位址和端口)。sampler字段指定用戶端采樣配置;為簡單起見,我們将配置可供所有 trace 進行采樣的“常量”采樣器(常項)。
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-config
namespace: nginx-ingress
data:
opentracing: "True"
opentracing-tracer: "/usr/local/lib/libjaegertracing_plugin.so"
opentracing-tracer-config: |
{
"service_name": "nginx-ingress",
"sampler": {
"type": "const",
"param": 1
},
"reporter": {
"localAgentHostPort": "jaeger-agent.default.svc.cluster.local:6831"
}
}
應用,隻需運作:
$kubectl apply –fnginx-config.yam
部署示例應用
為簡單起見,我們将使用NGINX執行個體作為我們的後端應用,其中有兩個不同應用——應用 1 配置将所有 HTTP 流量重定向到應用 2。
以下為第一個應用的 YAML 清單(s 和資料卷配置在 Pod 内運作的 NGINX 執行個體。其中一個 ConfigMap 采用 NGINX 配置,另一個則用于為每個 NGINX 執行個體指定跟蹤器配置(我們在每個應用中采用該配置,因為如前所述,應用 Pod 發送有關請求的資訊需通路跟蹤器)。
部署應用 1
以下為第一個應用的YAML 清單 (app1.yaml):
apiVersion: v1
kind: ConfigMap
metadata:
name: app1-config
data:
nginx.conf: |-
user nginx;
worker_processes 1;
load_module modules/ngx_http_opentracing_module.so;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
opentracing_load_tracer /usr/local/lib/libjaegertracing_plugin.so
/etc/jaeger-config.json;
opentracing on;
server {
listen 80;
server_name example.com;
location / {
opentracing_propagate_context;
proxy_set_header Host $host;
proxy_pass http://app2-svc:80;
}
}
}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: jaeger-config-app1
data:
jaeger-config.json: |-
{
"service_name": "app1",
"sampler": {
"type": "const",
"param": 1
},
"reporter": {
"localAgentHostPort": "jaeger-agent.default.svc.cluster.local:6831"
}
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app1
spec:
replicas: 1
selector:
matchLabels:
app: app1
template:
metadata:
labels:
app: app1
spec:
containers:
- name: app1
image: opentracing/nginx-opentracing
ports:
- containerPort: 80
volumeMounts:
- name: config-app1
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
readOnly: true
- name: config-jaeger
mountPath: /etc/jaeger-config.json
subPath: jaeger-config.json
readOnly: true
volumes:
- name: config-app1
configMap:
name: app1-config
- name: config-jaeger
configMap:
name: jaeger-config-app1
---
apiVersion: v1
kind: Service
metadata:
name: app1-svc
spec:
ports:
- port: 80
targetPort: 80
selector:
app: app1
運作以下指令部署第一個應用:
$kubectl apply –fapp1.yaml
部署應用 2
以下為第二個應用的 YAML 清單 (app2.yaml):
apiVersion: v1
kind: ConfigMap
metadata:
name: app2-config
data:
nginx.conf: |-
user nginx;
worker_processes 1;
load_module modules/ngx_http_opentracing_module.so;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
opentracing_load_tracer /usr/local/lib/libjaegertracing_plugin.so
/etc/jaeger-config.json;
opentracing on;
server {
listen 80;
server_name example.com;
location / {
opentracing_propagate_context;
opentracing_tag app app2;
return 200 "Success!\n";
}
}
}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: jaeger-config-app2
data:
jaeger-config.json: |-
{
"service_name": "app2",
"sampler": {
"type": "const",
"param": 1
},
"reporter": {
"localAgentHostPort": "jaeger-agent.default.svc.cluster.local:6831"
}
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app2
spec:
replicas: 1
selector:
matchLabels:
app: app2
template:
metadata:
labels:
app: app2
spec:
containers:
- name: app2
image: opentracing/nginx-opentracing
ports:
- containerPort: 80
volumeMounts:
- name: config-app2
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
readOnly: true
- name: config-jaeger
mountPath: /etc/jaeger-config.json
subPath: jaeger-config.json
readOnly: true
volumes:
- name: config-app2
configMap:
name: app2-config
- name: config-jaeger
configMap:
name: jaeger-config-app2
---
apiVersion: v1
kind: Service
metadata:
name: app2-svc
spec:
ports:
- port: 80
targetPort: 80
selector:
app: app2
運作以下指令部署第二個應用:
$kubectl apply -fapp2.yaml
部署 Ingress 資源
為了支援叢集外部對應用 1 的通路,我們将建立以下 Ingress 資源 (opentracing-ingress.yaml):
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: opentracing-ingress
annotations:
nginx.org/location-snippets: |
opentracing_propagate_context;
spec:
rules:
- host: example.com
http:
paths:
- path: /
backend:
serviceName: app1-svc
servicePort: 80
在這裡,我們在 Ingress Controller 使用了 nginx.org/location-snippets 注釋啟用跟蹤上下文傳播。代碼段注釋是将自定義代碼添加到 Ingress Controller 中最終 NGINX 配置的一種有效方法。
最後,我們通過運作以下指令來應用 Ingress 資源:
$kubectl apply -fopentracing-ingress.yaml
驗證應用 1 和應用 2 是否均正常運作:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
app1-68fd9db45c-szqpr 1/1 Running 0 53m
app2-67c7788789-lvbgw 1/1 Running 0 53m
跟蹤請求
現在,我們隻需通過 Ingress Controller 向應用 1 送出請求,其中:
- IC_HTTP_PORT 是 Ingress 控制器 Pod 中的 HTTP 端口(預設為 80)
- IC_IP_ADDRESS是 Ingress 控制器 Pod 的 IP 位址。如果使用minikube,則采用 minikube IP 位址。
$curl --resolveexample.com:IC_HTTP_PORT:IC_IP_ADDRESShttp://example.com:IC_HTTP_PORT/--insecure
Success!
檢視trace
我們運作以下指令來通路 Jaeger 使用者界面,其中 JAEGER_POD 是我們通過部署 Jaeger 跟蹤器一體式模闆所建立的Pod中的“類型/名稱”值:
$kubectl port-forwardJAEGER_POD 16686:16686
每個請求都會建立一個新的 trace。您可在浏覽器中在 http://localhost:16686 打開 Jaeger 使用者界面去檢視剛剛送出請求的 trace,在左欄 Service 字段中鍵入 nginx-egress,然後點選欄底部的 FindTraces 按鈕。
點選搜尋視窗右欄中的 nginx-ingress,選擇 trace。在打開的視窗(下圖)中,我們看到我們請求的三種 span:棕色代表 Ingress Controller,藍色代表應用 1,黃色代表應用 2。
擷取更多相關各個 span 的詳細資訊,包括 HTTP 狀态代碼、主機名、IP 位址和 Jaeger 版本,請點選其 span 的按鈕。
結語
在 Kubernetes 中為您的服務啟用 OpenTracing 可支援您和您的團隊及時了解應用運作的情況并快速排除故障。
更多資源
- 官網:nginx.org.cn
- 微信公衆号:https://mp.weixin.qq.com/s/XVE5yvDbmJtpV2alsIFwJg
- 微信群:https://www.nginx.org.cn/static/pc/images/homePage/QR-code.png?v=1621313354
- B 站:https://space.bilibili.com/628384319