Istio可觀測性

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 //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. 在瀏覽器上多次訪問//$GATEWAY_URL/productpage來生成跟蹤信息

    為了查看跟蹤數據,需要服務發送請求。請求的數量取決於istio的採樣率,採樣率是在安裝istio的時候設置的,默認為1%,即在看到第一個trace之前需要至少發送100個請求。使用如下命令向productpage發送100個請求:

    $ for i in $(seq 1 100); do curl -s -o /dev/null "//$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 //raw.githubusercontent.com/istio/istio/release-1.7/samples/addons/prometheus.yaml

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

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

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

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

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

生成服務圖

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

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

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

    • 使用如下curl命令

      $ curl //$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 //raw.githubusercontent.com/istio/istio/release-1.7/samples/addons/kiali.yaml