Istio可觀測性

charlieroro發表於2020-09-03

Istio可觀測性

Istio的可觀測性包括metrics,日誌,分散式鏈路跟蹤以及視覺化展示。下面主要介紹如何在istio中部署基於Prometheus的metrics監控,基於jaeger的鏈路跟蹤和基於kiali的視覺化介面。

Prometheus

配置說明

在istio網格中,每個元件都會暴露一個提供metrics的endpoint。Prometheus可以從這些endpoints上抓取metrics(通過Prometheus配置檔案來設定scraping,埠以及TLS等)。

為了採集整個網格的metrics,需要配置Prometheus scraping元件:

  1. 控制面(istiod deployment)
  2. ingress和egress閘道器
  3. Envoy sidecar
  4. 使用者應用(如果該應用也可以暴露Prometheus metrics的話)

為了簡化metrics的配置,istio提供瞭如下兩種操作模式:

Option 1:合併metrics

為了簡化配置,istio可以通過prometheus.io annotations來控制所有scraping。這使Istio的scraping可以使用標準配置(例如Helm stable/prometheus charts提供的配置)來做到開箱即用。

該選項預設是啟用的,但可以在安裝期間通過傳入--set meshConfig.enablePrometheusMerge=false來禁用該功能。當啟用時,會在所有的控制面pod上新增prometheus.io annotations來配置scraping。如果已經存在這些annotations,則會被覆蓋。通過該選項,Envoy sidecar會將istio的metrics和應用的metrics進行合併,合併後的metrics暴露地址為:/stats/prometheus:15020.

通過kubect describe pod命令可以檢視pod的annotation,需要注意的是控制面和資料暴露的埠是不同的。資料面暴露的埠為15020,如下:

      prometheus.io/path: /stats/prometheus
      prometheus.io/port: 15020
      prometheus.io/scrape: true

但istiod的埠為15014,ingress-gateway和egress-gateway的埠為15090。總體來說與官方埠描述一致。

該選項會以明文方式暴露所有的metrics。

下面特性可能並不適用於所有場景:

  • 在抓取metrcis時啟用TLS
  • 應用暴露的metrics與istio的metrics的名稱相同。例如,應用暴露了一個名為istio_requests_total的metric,可能是因為應用本身也執行了Envoy
  • 部署的Prometheus沒有基於標準的prometheus.io annotation抓取metrics。

如果有必要,則可以在pod上新增prometheus.istio.io/merge-metrics: "false" annotation來禁用metrics合併功能。

Option 2:自定義抓取metrics配置

內建的demo profile會安裝Prometheus,幷包含了所有必要的scraping配置。可以在使用istioctl部署istio時傳入引數--set values.prometheus.enabled=true來部署Prometheus。

但內建的Prometheus缺少高階自定義配置功能,如認證的持久化等,導致其不大合適在生產環境中使用。為了使用已經存在的Prometheus,需要在Prometheus配置中新增scraping配置prometheus/configmap.yaml

該配置會新增抓取控制面以及所有Envoy sidecar的metrcis的功能。此外,還配置了一個job,用來抓取新增了prometheus.io annotation的所有資料面pod的應用metrics。

TLS設定

控制面,閘道器和Envoy sidecar的metrics都以明文方式暴露。然而,應用metrics會遵循istio對負載的配置。例如如果啟用了Strict mTLS,那麼Prometheus需要使用istio證照來配置scrape

對於自建的Prometheus,參考為沒有sidecar的應用程式提供證照和金鑰一文來為Prometheus提供證照,並新增TLS scraping配置。

總結

istio的metrics分為兩類:istio自身的metrics和應用產生的metrics,前者以明文方式暴露,後者遵循對應負載的配置,即,如果負載啟用了TLS,則Prometheus也需要配置TLS才能獲取應用的metrics。

istio的metrics主要通過kubernetes_sd_config服務發現進行採集。其中prometheus.io/pathprometheus.io/port annotation分別對應metrics meta_kubernetes_pod_annotation_prometheus_io_scrapemeta_kubernetes_pod_annotation_prometheus_io_path 。簡單配置如下:

- job_name: 'kubernetes-pods'

        kubernetes_sd_configs:
        - role: pod

        relabel_configs:
        - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
          action: keep
          regex: true
        - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
          action: replace
          target_label: __metrics_path__
          regex: (.+)
        - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
          action: replace
          regex: ([^:]+)(?::\d+)?;(\d+)
          replacement: $1:$2
          target_label: __address__
        - action: labelmap
          regex: __meta_kubernetes_pod_label_(.+)
        - source_labels: [__meta_kubernetes_namespace]
          action: replace
          target_label: kubernetes_namespace
        - source_labels: [__meta_kubernetes_pod_name]
          action: replace
          target_label: kubernetes_pod_name

更多配置可以參見官方提供的配置

Jaeger

概述

分散式跟蹤使使用者可以通過分佈在多個服務中的網格跟蹤請求。通過這種方式可以瞭解請求延遲,並通過視覺化實現序列化和並行。

Istio利用Envoy的分散式跟蹤特性提供開箱即用的跟蹤整合。特別地,istio提供了選項來安裝不同的跟蹤後端,以及配置代理來傳送這些後端自動傳送跟蹤span。檢視Zipkin, JaegerLightstep來了解istio如何與這些跟蹤系統共同工作。

跟蹤上下文的傳遞

雖然istio代理可以自動傳送span,但它們需要一些提示來將整個跟蹤聯絡在一起。應用需要傳遞合適的HTTP首部,這樣當代理髮送span資訊時,這些span可以正確地關聯到單個跟蹤中。

為了實現上述目的,應用需要在傳入請求中收集並傳遞如下首部到任何傳出請求中:

  • x-request-id
  • x-b3-traceid
  • x-b3-spanid
  • x-b3-parentspanid
  • x-b3-sampled
  • x-b3-flags
  • x-ot-span-context

此外,基於OpenCensus (如Stackdriver)的跟蹤整合需要傳遞下面首部:

  • x-cloud-trace-context
  • traceparent
  • grpc-trace-bin

如果檢視istio的productpage例子的Python原始碼,可以看到應用會使用OpenTracing庫從HTTP請求中抽取需要的首部:

def getForwardHeaders(request):
    headers = {}

    # x-b3-*** headers can be populated using the opentracing span
    span = get_current_span()
    carrier = {}
    tracer.inject(
        span_context=span.context,
        format=Format.HTTP_HEADERS,
        carrier=carrier)

    headers.update(carrier)

    # ...

    incoming_headers = ['x-request-id', 'x-datadog-trace-id', 'x-datadog-parent-id', 'x-datadog-sampled']

    # ...

    for ihdr in incoming_headers:
        val = request.headers.get(ihdr)
        if val is not None:
            headers[ihdr] = val

    return headers

reviews應用會使用requestHeaders做類似的事情:

@GET
@Path("/reviews/{productId}")
public Response bookReviewsById(@PathParam("productId") int productId, @Context HttpHeaders requestHeaders) {

  // ...

  if (ratings_enabled) {
    JsonObject ratingsResponse = getRatings(Integer.toString(productId), requestHeaders);

當在應用程式中執行下游呼叫時,需要包含這些首部。

使用Jaeger

本例將使用Bookinfo

部署

  1. 使用如下方式快速部署一個用於演示的Jaeger。當然也可以參考Jaeger官方檔案進行自定義部署。

    $ kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.7/samples/addons/jaeger.yaml
    
  2. 可以參考此處修改取樣率

訪問Jaeger

上面部署的Jaeger對應的k8s service名為tracing,檢視該service,可以看到容器和service暴露的埠均為16686。

# oc describe svc tracing
Name:              tracing
Namespace:         istio-system
Labels:            app=jaeger
Annotations:       kubectl.kubernetes.io/last-applied-configuration:
                     {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app":"jaeger"},"name":"tracing","namespace":"istio-system"},"s...
Selector:          app=jaeger
Type:              ClusterIP
IP:                10.84.179.208
Port:              http-query  80/TCP
TargetPort:        16686/TCP
Endpoints:         10.80.2.226:16686
Session Affinity:  None
Events:            <none>

在openshift上建立一個route(ingress),即可訪問該Jaeger。

使用Boofinfo生成traces

  1. 在瀏覽器上多次訪問http://$GATEWAY_URL/productpage來生成跟蹤資訊

    為了檢視跟蹤資料,需要服務傳送請求。請求的數量取決於istio的取樣率,取樣率是在安裝istio的時候設定的,預設為1%,即在看到第一個trace之前需要至少傳送100個請求。使用如下命令向productpage傳送100個請求:

    $ for i in $(seq 1 100); do curl -s -o /dev/null "http://$GATEWAY_URL/productpage"; done
    
  2. 在dashboard的左邊,在Service下拉選單中選擇productpage.default,並點選Find Traces,可以看到生成了兩條span

  3. 點選最近時間內到/productpage的請求的細節

    此外還可以點選右上角的Alternate Views切換檢視,可以更直觀地看到請求的訪問情況:

  4. trace由一組span構成,每個span對應一個Bookinfo服務,在執行到/productpage的請求或內部Istio元件(如istio-ingressgateway)時生成。

Kiali

本節展示如何視覺化istio網格的方方面面。

本節將安裝Kiali外掛並使用基於Web的圖形使用者介面檢視網格和Istio配置物件的服務圖,最後,使用Kiali Developer API以consumable JSON的形式生成圖形資料。

本任務並沒有涵蓋Kiali的所有特性,更多參見Kiali website

本節將使用Boofinfo應用。

部署

Kiali依賴Prometheus,因此首先要部署Prometheus。使用如下命令快速部署一個用於演示的Prometheus:

$ kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.7/samples/addons/prometheus.yaml

使用如下方式快速部署一個用於演示的Kiali。如果要用於生產環境,建議參考quick start guidecustomizable installation methods

$ kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.7/samples/addons/kiali.yaml

注:由於Kiali依賴Prometheus,因此需要將Kiali和Prometheus關聯起來。修改上面kiali.yaml中的如下欄位,然後部署即可:

    custom_metrics_url: http://prometheus.istio-system.svc.cluster.local:9090
    url: http://prometheus.istio-system.svc.cluster.local:9090

同樣地,為名為kiali的k8s service建立一個route即可訪問,埠為20001。

生成服務圖

  1. 使用如下命令檢查kiali的service

    $ kubectl -n istio-system get svc kiali
    
  2. 可以使用如下三種方式向網格傳送流量

    • 通過瀏覽器訪問http://$GATEWAY_URL/productpage

    • 使用如下curl命令

      $ curl http://$GATEWAY_URL/productpage
      
    • 使用watch持續訪問

      $ watch -n 1 curl -o /dev/null -s -w %{http_code} $GATEWAY_URL/productpage
      
  3. Overview頁面瀏覽網格概況,該頁面展示了網格中所有名稱空間下的服務。可以看到default名稱空間下有流量(Bookinfo應用安裝到的default名稱空間下)

  4. 為了檢視一個名稱空間的圖表,在Boofinfo所在的名稱空間中檢視bookinfo的圖表如下,三角形表示service,方形表示app

  5. 可以在Display中選擇不同的Edge來展示metrics的概況,如上圖顯示了Response Time。unknow是因為沒有走istio的gateway,而使用了openshift的route

  6. 為了顯示服務網格中的不同型別的圖表,在Graph Type下拉框中可以選擇如下圖示型別:App, Versioned App, Workload, Service

    • App圖表型別會將所有版本的app聚合為一個圖表節點。下圖可以看到,它使用一個reviews 節點來表示三個版本的reviews app

    • Versioned App圖表型別使用一個node展示了不同版本的app,同時對特定app的不同版本進行分組。下圖展示了reviews 組,其包含3個小的節點,三個節點表示三個版本的reviews app

    • Workload 圖表型別使用節點展示了服務網格中的每個負載。該圖形型別不要求使用appversion標籤,因此如果選擇不在元件上使用這些標籤時,就可以使用該圖表型別。

    • Service 圖表型別使用節點展示網格中的每個服務,但排除所有應用程式和工作負載

      image-20200902155441754

檢查Istio配置

為了檢視Istio配置的詳細配置,可以在左邊選單欄中點選 Applications, WorkloadsServices。下圖展示了Bookinfo應用的資訊

建立加權路由

可以使用Kiali加權路由嚮導來定義指定百分比的請求流量來路由到兩個或更多負載。

  1. 將bookinfo圖表切換為Versioned app graph

    • 確保在Display下拉框中選擇了Requests percentage來檢視路由到每個負載的流量百分比

    • 確保在Display下拉框中選擇了Service Nodes來顯示service節點

  2. 通過點選reviews服務(三角形)關注bookinfo圖表中的reviews服務

  3. 在右上角的下拉框中選擇Show Details進入ratings的service設定

  4. Action下拉框中,選擇Create Weighted Routing來訪問加權路由嚮導

  5. 通過拖動滑塊來調整到負載的流量百分比。將reviews-v1設定為30%,reviews-v2設定為0%,將reviews-v3設定為70%。

  6. 點選Create建立該路由。對應會在istio中建立用於流量劃分的一個VirtualService和一個DestinationRule:

    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      labels:
        kiali_wizard: weighted_routing
      name: reviews
      namespace: default
    spec:
      hosts:
      - reviews.default.svc.cluster.local
      http:
      - route:
        - destination:
            host: reviews.default.svc.cluster.local
            subset: v1
          weight: 30
        - destination:
            host: reviews.default.svc.cluster.local
            subset: v2
          weight: 0
        - destination:
            host: reviews.default.svc.cluster.local
            subset: v3
          weight: 70
    
    kind: DestinationRule
    metadata:
      labels:
        kiali_wizard: weighted_routing
      name: reviews
      namespace: default
    spec:
      host: reviews.default.svc.cluster.local
      subsets:
      - labels:
          version: v1
        name: v1
      - labels:
          version: v2
        name: v2
      - labels:
          version: v3
        name: v3
    
  7. 點選左邊導航欄的Graph按鈕返回到bookinfo圖表

  8. 向bookinfo應用傳送請求。例如使用如下命令每秒傳送一個請求:

    $ watch -n 1 curl -o /dev/null -s -w %{http_code} $GATEWAY_URL/productpage
    
  9. 一段時間後,可以看到流量百分比會體現為新的流量路由,即v1版本接收到30%的流量,v2版本沒有流量,v3版本接收到70%的流量

驗證Istio配置

Kiali可以驗證Istio的資源來確保它們遵循正確的約定和語義。根據配置錯誤的嚴重性,可以將Istio資源配置中檢測到的任何問題標記為錯誤或警告。

下面將嘗試對服務埠名稱進行無效性修改來檢視Kiali如何報告錯誤:

  1. details服務的埠名稱從http修改為foo

    # kubectl patch service details -n default --type json -p '[{"op":"replace","path":"/spec/ports/0/name", "value":"foo"}]'
    
  2. 點選左側導航欄的Services 轉到服務列表

  3. 選擇bookinfo所在的名稱空間

  4. 注意在details一行中顯示的錯誤圖示

  5. 點選Name一欄對應的details來檢視詳細資訊

  6. 將埠名稱切換回http,可以看到bookinfo又變的正常了

    # kubectl patch service details -n default --type json -p '[{"op":"replace","path":"/spec/ports/0/name", "value":"http"}]'
    

檢視和修改Istio的配置YAML

Kiali提供了一個YAML編輯器,可以用於檢視和修改Istio的配置資源。YAML編輯器也提供了校驗配置的功能。

  1. 建立一條Bookinfo的destination rules

    $ kubectl apply -f samples/bookinfo/networking/destination-rule-all.yaml
    
  2. 點選導航欄左邊的Istio Config轉到istio的配置列表

  3. 選擇bookinfo所在的名稱空間

  4. 注意在右上角有提示配置的錯誤和告警資訊

  5. 將滑鼠懸停在detailsConfiguration 列中的錯誤圖示上,可以檢視其他訊息。

  6. 單擊Name列中的details連結,導航到details的destination rule檢視。

  7. 可以看到有校驗未通過的錯誤提示

  8. 點選YAML檢視Istio的destination rule規則,Kiali用顏色高亮除了未通過有效性校驗的行

  9. 將滑鼠懸停在紅色圖示上可以檢視工具提示訊息,該訊息提示觸發錯誤的驗證檢查。

  10. 刪除建立的bookinfo的destination rule,進行環境恢復

    $ kubectl delete -f samples/bookinfo/networking/destination-rule-all.yaml
    

在官方文件中,上述YAML中是存在黃色的告警圖示,但實際部署時並沒有出現。

關於Kiali Developer API

為了生成表示圖表和其他指標,健康,以及配置資訊的JSON檔案,可以參考Kiali Developer API。例如,可以通過訪問$KIALI_URL/api/namespaces/graph?namespaces=default&graphType=app來獲取使用app 圖表型別的JSON表示格式。

Kiali Developer API建立在Prometheus查詢之上,並取決於標準的Istio metric配置,它還會執行kubernetes API呼叫來獲取服務的其他詳細資訊。為了更好地使用Kiali,請在自己的應用元件中使用metadata labels appversion

請注意,Kiali Developer API可能在不同版本間傳送變更,且不保證向後相容。

其他特性

Kiali還有其他豐富的特性,如與Jaeger跟蹤的整合

更多細節和特性,參見Kiali官方文件

解除安裝

$ kubectl delete -f https://raw.githubusercontent.com/istio/istio/release-1.7/samples/addons/kiali.yaml

相關文章