Istio可觀測性
阿新 • • 發佈:2020-09-03
# Istio可觀測性
Istio的可觀測性包括metrics,日誌,分散式鏈路跟蹤以及視覺化展示。下面主要介紹如何在istio中部署基於Prometheus的metrics監控,基於jaeger的鏈路跟蹤和基於kiali的視覺化介面。
[TOC]
## Prometheus
### 配置說明
在istio網格中,每個元件都會暴露一個提供metrics的endpoint。Prometheus可以從這些endpoints上抓取metrics(通過[Prometheus配置檔案](https://prometheus.io/docs/prometheus/latest/configuration/configuration/)來設定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`](https://github.com/helm/charts/tree/master/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,如下:
>
> ```yaml
> prometheus.io/path: /stats/prometheus
> prometheus.io/port: 15020
> prometheus.io/scrape: true
> ```
>
> 但istiod的埠為15014,ingress-gateway和egress-gateway的埠為15090。總體來說與官方[埠描述](https://istio.io/latest/docs/ops/deployment/requirements/#ports-used-by-istio)一致。
該選項會以明文方式暴露所有的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`](https://raw.githubusercontent.com/istio/istio/release-1.7/manifests/charts/istio-telemetry/prometheus/templates/configmap.yaml)。
該配置會新增抓取控制面以及所有Envoy sidecar的metrcis的功能。此外,還配置了一個job,用來抓取添加了`prometheus.io` annotation的所有資料面pod的應用metrics。
##### TLS設定
控制面,閘道器和Envoy sidecar的metrics都以明文方式暴露。然而,應用metrics會遵循istio對負載的配置。例如如果啟用了[Strict mTLS](https://istio.io/latest/docs/tasks/security/authentication/authn-policy/#globally-enabling-istio-mutual-tls-in-strict-mode),那麼Prometheus需要使用istio證書來配置scrape
對於自建的Prometheus,參考[為沒有sidecar的應用程式提供證書和金鑰](https://istio.io/latest/blog/2020/proxy-cert/)一文來為Prometheus提供證書,並新增TLS scraping配置。
### 總結
istio的metrics分為兩類:istio自身的metrics和應用產生的metrics,前者以明文方式暴露,後者遵循對應負載的配置,即,如果負載啟用了TLS,則Prometheus也需要配置TLS才能獲取應用的metrics。
istio的metrics主要通過[kubernetes_sd_config](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#kubernetes_sd_config)服務發現進行採集。其中`prometheus.io/path`和`prometheus.io/port` annotation分別對應metrics `meta_kubernetes_pod_annotation_prometheus_io_scrape`和`meta_kubernetes_pod_annotation_prometheus_io_path` 。簡單配置如下:
```yaml
- 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
```
更多配置可以參見官方提供的[配置](https://raw.githubusercontent.com/istio/istio/release-1.7/manifests/charts/istio-telemetry/prometheus/templates/configmap.yaml)。
## Jaeger
### 概述
分散式跟蹤使使用者可以通過分佈在多個服務中的網格跟蹤請求。通過這種方式可以瞭解請求延遲,並通過視覺化實現序列化和並行。
Istio利用[Envoy的分散式跟蹤](https://www.envoyproxy.io/docs/envoy/v1.12.0/intro/arch_overview/observability/tracing)特性提供開箱即用的跟蹤整合。特別地,istio提供了選項來安裝不同的跟蹤後端,以及配置代理來發送這些後端自動傳送跟蹤span。檢視[Zipkin](https://istio.io/latest/docs/tasks/observability/distributed-tracing/zipkin/), [Jaeger](https://istio.io/latest/docs/tasks/observability/distributed-tracing/jaeger/)和[Lightstep](https://istio.io/latest/docs/tasks/observability/distributed-tracing/lightstep/)來了解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](https://opencensus.io/) (如Stackdriver)的跟蹤整合需要傳遞下面首部:
- `x-cloud-trace-context`
- `traceparent`
- `grpc-trace-bin`
如果檢視istio的`productpage`例子的Python原始碼,可以看到應用會使用[OpenTracing](https://opentracing.io/)庫從HTTP請求中抽取需要的首部:
```python
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`做類似的事情:
```java
@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](https://istio.io/latest/docs/examples/bookinfo/)。
### 部署
1. 使用如下方式快速部署一個用於演示的Jaeger。當然也可以參考[Jaeger](https://www.jaegertracing.io/)官方檔案進行自定義部署。
```shell
$ kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.7/samples/addons/jaeger.yaml
```
2. 可以參考[此處](https://istio.io/latest/docs/tasks/observability/distributed-tracing/configurability/#customizing-trace-sampling)修改取樣率
### 訪問Jaeger
上面部署的Jaeger對應的k8s service名為`tracing`,檢視該service,可以看到容器和service暴露的埠均為16686。
```shell
# 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: