7、Istio可观测性
更新于:2023年12月7日08:
Istio可观测性
前言
Istio 为网格内所有的服务通信生成详细的遥测数据。这种遥测技术提供了服务行为的可观测性,使运维人员能够排查故障、维护和优化应用程序,而不会给开发人员带来其他额外的负担。通过 Istio,运维人员可以全面了解到受监控的服务如何与其他服务以及 Istio 组件进行交互。
Istio 生成以下类型的遥测数据,以提供对整个服务网格的可观测性:
- Metrics(指标):Istio 基于 4 个监控的黄金标识(延迟、流量、错误、饱和)生成了一系列服务指标,Istio 还为网格控制平面提供了更详细的指标。除此以外还提供了一组默认的基于这些指标的网格监控仪表板。
- Tracing(分布式追踪):Istio 为每个服务生成分布式追踪 span,运维人员可以理解网格内服务的依赖和调用流程。
- Log(访问日志):当流量流入网格中的服务时,Istio 可以生成每个请求的完整记录,包括源和目标的元数据,该信息使运维人员能够将服务行为的审查控制到单个工作负载实例的级别。
接下来我们将分别来学习 Istio 的指标、分布式追踪和访问日志是如何工作的。
1、指标
指标提供了一种以聚合的方式监控和理解行为的方法。为了监控服务行为,Istio 为服务网格中所有出入网格,以及网格内部的服务流量都生成了指标,这些指标提供了关于行为的信息,例如总流量、错误率和请求响应时间。除了监控网格中服务的行为外,监控网格本身的行为也很重要。Istio 组件还可以导出自身内部行为的指标,以提供对网格控制平面的功能和健康情况的洞察能力。
指标类别
整体上 Istio 的指标可以分成 3 个级别:代理级别、服务级别、控制平面级别。
1、代理级别指标
Istio 指标收集从 Envoy Sidecar 代理开始,每个代理为通过它的所有流量(入站和出站)生成一组丰富的指标。代理还提供关于它本身管理功能的详细统计信息,包括配置信息和健康信息。
Envoy 生成的指标提供了资源(例如监听器和集群)粒度上的网格监控。因此,为了监控 Envoy 指标,需要了解网格服务和 Envoy 资源之间的连接。
Istio 允许运维人员在每个工作负载实例上选择生成和收集哪些 Envoy 指标。默认情况下,Istio 只支持 Envoy 生成的统计数据的一小部分,以避免依赖过多的后端服务,还可以减少与指标收集相关的 CPU 开销。但是运维人员可以在需要时轻松地扩展收集到的代理指标数据。这样我们可以有针对性地调试网络行为,同时降低了跨网格监控的总体成本。
2、服务级别指标
除了代理级别指标之外,Istio 还提供了一组用于监控服务通信的面向服务的指标。这些指标涵盖了四个基本的服务监控需求:延迟、流量、错误和饱和情况。而且 Istio 还自带了一组默认的仪表板,用于监控基于这些指标的服务行为。默认情况下,标准 Istio 指标会导出到 Prometheus。而且服务级别指标的使用完全是可选的,运维人员可以根据自身的需求来选择关闭指标的生成和收集。
3、控制平面指标
另外 Istio 控制平面还提供了一组自我监控指标。这些指标允许监控 Istio 自己的行为。
通过 Prometheus 查询指标
Istio 默认使用 Prometheus 来收集和存储指标。Prometheus 是一个开源的系统监控和警报工具包,它可以从多个源收集指标,并允许运维人员通过 PromQL 查询语言来查询收集到的指标。
- 首先要确保 Istio 的
prometheus
组件已经启用,如果没有启用可以通过以下命令启用:
[root@master1 ~]#cd istio-1.19.3/[root@master1 istio-1.19.3]#ls samples/addons/extrasgrafana.yamljaeger.yamlkiali.yamlloki.yamlprometheus.yamlREADME.md#部署kubectlapply-fsamples/addons
上面的命令会安装 Kiali,包括 Prometheus、Grafana 以及 jaeger。当然这仅仅只能用于测试环境,在生产环境可以单独安装 Prometheus 进行有针对性的配置优化。
- 安装后可以通过以下命令查看 Prometheus 服务状态:
$kubectlgetsvcprometheus-nistio-systemNAMETYPECLUSTER-IPEXTERNAL-IPPORT(S) AGEprometheusClusterIP10.106.228.196<none>9090/TCP25d$kubectlgetpods-nistio-system-lapp=prometheusNAMEREADYSTATUSRESTARTSAGEprometheus-5d5d6d6fc-2gtxm2/2Running025d
- 首先在浏览器中访问
http:# 也可以创建 Ingress 或者 Gateway 来访问 Prometheus UI[root@master1 istio-1.19.3]#istioctl dashboard prometheushttp:Failedtoopenbrowser;openhttp:C[root@master1istio-1.19.3]#istioctldashboardprometheus--address0.0.0.0http:Failedtoopenbrowser;openhttp:NAMETYPECLUSTER-IPEXTERNAL-IPPORT(S) AGEgrafanaClusterIP10.96.197.74<none>3000/TCP25d$kubectl-nistio-systemgetpods-lapp=grafanaNAMEREADYSTATUSRESTARTSAGEgrafana-5f9b8c6c5d-jv65v1/1Running025d
- 然后我们可以通过以下命令来打开 Grafana UI:
istioctldashboardgrafana# 也可以创建 Ingress 或者 Gateway 来访问 Grafanaistioctldashboardgrafana--address0.0.0.0
然后我们就可以在浏览器中打开 Grafana UI 了,默认情况下 Grafana 已经配置了 Prometheus 数据源,所以我们可以直接使用 Prometheus 数据源来查询指标。
- 此外 Grafana 也已经内置了 Istio 的一些仪表盘,我们可以直接使用这些仪表盘来查看指标,比如我们可以打开
Istio Mesh Dashboard
仪表盘来查看网格的指标:
从图中可以看出现在有一些数据,但是并不是很多,这是因为我们现在还没产生一些流量请求。
- 下面我们可以用下面的命令向 productpage 服务发送 100 个请求:
fori in$(seq1100);docurl-s-o/dev/null"http:apiVersion:v1kind:Servicemetadata:labels:component:"server"app:prometheusrelease:prometheuschart:prometheus-19.6.1heritage:Helmname:prometheusnamespace:istio-systemspec:ports:- name:httpport:9090protocol:TCPtargetPort:9090selector:component:"server"app:prometheusrelease:prometheussessionAffinity:Nonetype:"ClusterIP"---# Source:prometheus/templates/deploy.yamlapiVersion:apps/v1kind:Deploymentmetadata:labels:component:"server"app:prometheusrelease:prometheuschart:prometheus-19.6.1heritage:Helmname:prometheusnamespace:istio-systemspec:selector:matchLabels:component:"server"app:prometheusrelease:prometheusreplicas:1strategy:type:RecreaterollingUpdate:nulltemplate:metadata:labels:component:"server"app:prometheusrelease:prometheuschart:prometheus-19.6.1heritage:Helmsidecar.istio.io/inject:"false"spec:enableServiceLinks:trueserviceAccountName:prometheuscontainers:- name:prometheus-server-configmap-reloadimage:"jimmidyson/configmap-reload:v0.8.0"imagePullPolicy:"IfNotPresent"args:- --volume-dir=/etc/config- --webhook-url=http:resources:{}volumeMounts:- name:config-volumemountPath:/etc/configreadOnly:true- name:prometheus-serverimage:"prom/prometheus:v2.41.0"imagePullPolicy:"IfNotPresent"args:- --storage.tsdb.retention.time=15d- --config.file=/etc/config/prometheus.yml##配置文件- --storage.tsdb.path=/data- --web.console.libraries=/etc/prometheus/console_libraries- --web.console.templates=/etc/prometheus/consoles- --web.enable-lifecycleports:- containerPort:9090readinessProbe:httpGet:path:/-/readyport:9090scheme:HTTPinitialDelaySeconds:0periodSeconds:5timeoutSeconds:4failureThreshold:3successThreshold:1livenessProbe:httpGet:path:/-/healthyport:9090scheme:HTTPinitialDelaySeconds:30periodSeconds:15timeoutSeconds:10failureThreshold:3successThreshold:1resources:{}volumeMounts:- name:config-volumemountPath:/etc/config- name:storage-volumemountPath:/datasubPath:""dnsPolicy:ClusterFirstsecurityContext:fsGroup:65534runAsGroup:65534runAsNonRoot:truerunAsUser:65534terminationGracePeriodSeconds:300volumes:- name:config-volumeconfigMap:name:prometheus- name:storage-volumeemptyDir:{} ##临时的# 省略了部分配置
从上面的资源清单中可以看出 Prometheus 服务的核心配置文件为 --config.file=/etc/config/prometheus.yml
,而该配置文件是通过上面的 prometheus
这个 ConfigMap 以 volume
形式挂载到容器中的。
- 所以我们重点是查看这个 ConfigMap 的配置,如下所示:
# Source:prometheus/templates/cm.yamlapiVersion:v1kind:ConfigMapmetadata:labels:component:"server"app:prometheusrelease:prometheuschart:prometheus-19.6.1heritage:Helmname:prometheusnamespace:istio-systemdata:allow-snippet-annotations:"false"alerting_rules.yml:|{}alerts:|{}prometheus.yml:|global:evaluation_interval:1mscrape_interval:15sscrape_timeout:10srule_files:- /etc/config/recording_rules.yml- /etc/config/alerting_rules.yml- /etc/config/rules- /etc/config/alertsscrape_configs:- job_name:prometheusstatic_configs:- targets:- localhost:9090- bearer_token_file:/var/run/secrets/kubernetes.io/serviceaccount/tokenjob_name:kubernetes-apiserverskubernetes_sd_configs:- role:endpointsrelabel_configs:- action:keepregex:default;kubernetes;httpssource_labels:- __meta_kubernetes_namespace- __meta_kubernetes_service_name- __meta_kubernetes_endpoint_port_namescheme:httpstls_config:ca_file:/var/run/secrets/kubernetes.io/serviceaccount/ca.crtinsecure_skip_verify:true- bearer_token_file:/var/run/secrets/kubernetes.io/serviceaccount/tokenjob_name:kubernetes-nodeskubernetes_sd_configs:- role:noderelabel_configs:- action:labelmapregex:__meta_kubernetes_node_label_(.+)- replacement:kubernetes.default.svc:443target_label:__address__- regex:(.+)replacement:/api/v1/nodes/$1/proxy/metricssource_labels:- __meta_kubernetes_node_nametarget_label:__metrics_path__scheme:httpstls_config:ca_file:/var/run/secrets/kubernetes.io/serviceaccount/ca.crtinsecure_skip_verify:true- bearer_token_file:/var/run/secrets/kubernetes.io/serviceaccount/tokenjob_name:kubernetes-nodes-cadvisorkubernetes_sd_configs:- role:noderelabel_configs:- action:labelmapregex:__meta_kubernetes_node_label_(.+)- replacement:kubernetes.default.svc:443target_label:__address__- regex:(.+)replacement:/api/v1/nodes/$1/proxy/metrics/cadvisorsource_labels:- __meta_kubernetes_node_nametarget_label:__metrics_path__scheme:httpstls_config:ca_file:/var/run/secrets/kubernetes.io/serviceaccount/ca.crtinsecure_skip_verify:true- honor_labels:truejob_name:kubernetes-service-endpointskubernetes_sd_configs:- role:endpointsrelabel_configs:- action:keepregex:truesource_labels:- __meta_kubernetes_service_annotation_prometheus_io_scrape- action:dropregex:truesource_labels:- __meta_kubernetes_service_annotation_prometheus_io_scrape_slow- action:replaceregex:(https?)source_labels:- __meta_kubernetes_service_annotation_prometheus_io_schemetarget_label:__scheme__- action:replaceregex:(.+)source_labels:- __meta_kubernetes_service_annotation_prometheus_io_pathtarget_label:__metrics_path__- action:replaceregex:(.+?)(?::\d+)?;(\d+)replacement:$1:$2source_labels:- __address__- __meta_kubernetes_service_annotation_prometheus_io_porttarget_label:__address__- action:labelmapregex:__meta_kubernetes_service_annotation_prometheus_io_param_(.+)replacement:__param_$1- action:labelmapregex:__meta_kubernetes_service_label_(.+)- action:replacesource_labels:- __meta_kubernetes_namespacetarget_label:namespace- action:replacesource_labels:- __meta_kubernetes_service_nametarget_label:service- action:replacesource_labels:- __meta_kubernetes_pod_node_nametarget_label:node- honor_labels:truejob_name:kubernetes-service-endpoints-slowkubernetes_sd_configs:- role:endpointsrelabel_configs:- action:keepregex:truesource_labels:- __meta_kubernetes_service_annotation_prometheus_io_scrape_slow- action:replaceregex:(https?)source_labels:- __meta_kubernetes_service_annotation_prometheus_io_schemetarget_label:__scheme__- action:replaceregex:(.+)source_labels:- __meta_kubernetes_service_annotation_prometheus_io_pathtarget_label:__metrics_path__- action:replaceregex:(.+?)(?::\d+)?;(\d+)replacement:$1:$2source_labels:- __address__- __meta_kubernetes_service_annotation_prometheus_io_porttarget_label:__address__- action:labelmapregex:__meta_kubernetes_service_annotation_prometheus_io_param_(.+)replacement:__param_$1- action:labelmapregex:__meta_kubernetes_service_label_(.+)- action:replacesource_labels:- __meta_kubernetes_namespacetarget_label:namespace- action:replacesource_labels:- __meta_kubernetes_service_nametarget_label:service- action:replacesource_labels:- __meta_kubernetes_pod_node_nametarget_label:nodescrape_interval:5mscrape_timeout:30s- honor_labels:truejob_name:prometheus-pushgatewaykubernetes_sd_configs:- role:servicerelabel_configs:- action:keepregex:pushgatewaysource_labels:- __meta_kubernetes_service_annotation_prometheus_io_probe- honor_labels:truejob_name:kubernetes-serviceskubernetes_sd_configs:- role:servicemetrics_path:/probeparams:module:- http_2xxrelabel_configs:- action:keepregex:truesource_labels:- __meta_kubernetes_service_annotation_prometheus_io_probe- source_labels:- __address__target_label:__param_target- replacement:blackboxtarget_label:__address__- source_labels:- __param_targettarget_label:instance- action:labelmapregex:__meta_kubernetes_service_label_(.+)- source_labels:- __meta_kubernetes_namespacetarget_label:namespace- source_labels:- __meta_kubernetes_service_nametarget_label:service- honor_labels:truejob_name:kubernetes-podskubernetes_sd_configs:- role:podrelabel_configs:- action:keepregex:truesource_labels:- __meta_kubernetes_pod_annotation_prometheus_io_scrape- action:dropregex:truesource_labels:- __meta_kubernetes_pod_annotation_prometheus_io_scrape_slow- action:replaceregex:(https?)source_labels:- __meta_kubernetes_pod_annotation_prometheus_io_schemetarget_label:__scheme__- action:replaceregex:(.+)source_labels:- __meta_kubernetes_pod_annotation_prometheus_io_pathtarget_label:__metrics_path__- action:replaceregex:(\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})replacement:'[$2]:$1'source_labels:- __meta_kubernetes_pod_annotation_prometheus_io_port- __meta_kubernetes_pod_iptarget_label:__address__- action:replaceregex:(\d+);((([0-9]+?)(\.|$)){4})replacement:$2:$1source_labels:- __meta_kubernetes_pod_annotation_prometheus_io_port- __meta_kubernetes_pod_iptarget_label:__address__- action:labelmapregex:__meta_kubernetes_pod_annotation_prometheus_io_param_(.+)replacement:__param_$1- action:labelmapregex:__meta_kubernetes_pod_label_(.+)- action:replacesource_labels:- __meta_kubernetes_namespacetarget_label:namespace- action:replacesource_labels:- __meta_kubernetes_pod_nametarget_label:pod- action:dropregex:Pending|Succeeded|Failed|Completedsource_labels:- __meta_kubernetes_pod_phase- honor_labels:truejob_name:kubernetes-pods-slowkubernetes_sd_configs:- role:podrelabel_configs:- action:keepregex:truesource_labels:- __meta_kubernetes_pod_annotation_prometheus_io_scrape_slow- action:replaceregex:(https?)source_labels:- __meta_kubernetes_pod_annotation_prometheus_io_schemetarget_label:__scheme__- action:replaceregex:(.+)source_labels:- __meta_kubernetes_pod_annotation_prometheus_io_pathtarget_label:__metrics_path__- action:replaceregex:(\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})replacement:'[$2]:$1'source_labels:- __meta_kubernetes_pod_annotation_prometheus_io_port- __meta_kubernetes_pod_iptarget_label:__address__- action:replaceregex:(\d+);((([0-9]+?)(\.|$)){4})replacement:$2:$1source_labels:- __meta_kubernetes_pod_annotation_prometheus_io_port- __meta_kubernetes_pod_iptarget_label:__address__- action:labelmapregex:__meta_kubernetes_pod_annotation_prometheus_io_param_(.+)replacement:__param_$1- action:labelmapregex:__meta_kubernetes_pod_label_(.+)- action:replacesource_labels:- __meta_kubernetes_namespacetarget_label:namespace- action:replacesource_labels:- __meta_kubernetes_pod_nametarget_label:pod- action:dropregex:Pending|Succeeded|Failed|Completedsource_labels:- __meta_kubernetes_pod_phasescrape_interval:5mscrape_timeout:30srecording_rules.yml:|{}rules:|{}---
这个配置文件中描述了 6 个指标抓取任务的配置:
prometheus
:抓取 Prometheus 服务自身的指标。kubernetes-apiservers
:抓取 Kubernetes API 服务器的指标。kubernetes-nodes
:抓取 Kubernetes 节点的指标。kubernetes-nodes-cadvisor
:抓取 Kubernetes 节点的 cadvisor 指标,主要包括容器的 CPU、内存、网络、磁盘等指标。kubernetes-service-endpoints
:抓取 Kubernetes 服务端点的指标。kubernetes-pods
:抓取 Kubernetes Pod 的指标。
这里我们可以重点关注下 kubernetes-pods
这个指标抓取任务的配置,因为我们大部分的指标数据都是通过 Pod 的 Envoy Sidecar 来提供的。
从配置上可以看到这是基于 pod
的服务发现方式:
- 首先只会保留
__meta_kubernetes_pod_annotation_prometheus_io_scrape
这个源标签为true
的指标数据,这个源标签表示的是如果 Pod 的 annotation 注解中有prometheus.io/scrape
标签,且值为true
,则会保留该指标数据,否则会丢弃该指标数据 - 然后根据
prometheus.io/scheme
注解来配置协议为 http 或者 https - 根据
prometheus.io/path
注解来配置抓取路径 - 根据
prometheus.io/port
注解来配置抓取端口; - 将
prometheus.io/param
注解的值映射为 Prometheus 的标签; - 然后还会将 pod 的标签通过
labelmap
映射为 Prometheus 的标签;最后还会将 pod 的 namespace 和 pod 的名称映射为 Prometheus 的标签。 - 最后需要判断 Pod 的 phase 状态,只有当 Pod 的 phase 状态为
Running
时才会保留该指标数据,否则会丢弃该指标数据。
比如我们查询 istio_requests_total{app="productpage",destination_app="details"}
这个指标,如下所示:
- 该查询语句的查询结果为:
istio_requests_total{app="details",connection_security_policy="mutual_tls",destination_app="details",destination_canonical_revision="v1",destination_canonical_service="details",destination_cluster="Kubernetes",destination_principal="spiffe:destination_service="details.default.svc.cluster.local",destination_service_name="details",destination_service_namespace="default",destination_version="v1",destination_workload="details-v1",destination_workload_namespace="default",instance="10.244.2.74:15020",job="kubernetes-pods",namespace="default",pod="details-v1-5f4d584748-9fflw",pod_template_hash="5f4d584748",reporter="destination",request_protocol="http",response_code="200",response_flags="-",security_istio_io_tlsMode="istio",service_istio_io_canonical_name="details",service_istio_io_canonical_revision="v1",source_app="productpage",source_canonical_revision="v1",source_canonical_service="productpage",source_cluster="Kubernetes",source_principal="spiffe:source_version="v1",source_workload="productpage-v1",source_workload_namespace="default",version="v1"} 362
该查询表示的是从 productpage
服务到 details
服务的请求总次数,从查询结果可以看出该指标就是来源于 job="kubernetes-pods"
这个指标抓取任务,那说明这个指标数据是通过服务发现方式从 Pod 中抓取的。
- 我们可以查看下
productpage
Pod 的信息,如下所示:
$kubectlgetpodsproductpage-v1-564d4686f-l8kxr-oyamlapiVersion:v1kind:Podmetadata:annotations:istio.io/rev:defaultkubectl.kubernetes.io/default-container:productpagekubectl.kubernetes.io/default-logs-container:productpageprometheus.io/path:/stats/prometheusprometheus.io/port:"15020"prometheus.io/scrape:"true"sidecar.istio.io/status:'{"initContainers":["istio-init"],"containers":["istio-proxy"],"volumes":["workload-socket","credential-socket","workload-certs","istio-envoy","istio-data","istio-podinfo","istio-token","istiod-ca-cert"],"imagePullSecrets":null,"revision":"default"}'labels:app:productpagepod-template-hash:564d4686fsecurity.istio.io/tlsMode:istioservice.istio.io/canonical-name:productpageservice.istio.io/canonical-revision:v1version:v1name:productpage-v1-564d4686f-l8kxrnamespace:defaultspec:containers:-image:docker.io/istio/examples-bookinfo-productpage-v1:1.18.0imagePullPolicy:IfNotPresent# ......
我们从上面的资源清单中可以看到该 Pod 包含如下几个注解:
prometheus.io/path:/stats/prometheus
prometheus.io/port:"15020"
prometheus.io/scrape:"true"
这些注解就是用来配置 Prometheus 服务发现的,其中 prometheus.io/scrape:"true"
表示该 Pod 的指标数据是需要被抓取的,而 prometheus.io/path:/stats/prometheus
和 prometheus.io/port:"15020"
则是用来配置抓取路径和抓取端口的,当 Prometheus 发现这个 Pod 后根据配置就可以通过 <pod ip>:15020/stats/prometheus
这个路径来抓取该 Pod 的指标数据了,这个路径就是 Envoy Sidecar 提供的 /stats/prometheus
路径,而 15020
则是 Envoy Sidecar 的端口,这个端口是通过 istio-proxy
这个容器配置的静态监听器暴露出来的。
当然定义的标签也被映射为 Prometheus 的标签了,从结果来看除了 Pod 的这些标签之外,Envoy Sidecar 也会自己添加很多相关标签,主要是标明 destination
和 source
的信息,有了这些标签我们就可以很方便的对指标进行查询了。Envoy Sidecar 自行添加的一些主要标签如下所示:
reporter
:标识请求指标的上报端,如果指标由服务端 Istio 代理上报,则设置为destination
,如果指标由客户端 Istio 代理或网关上报,则设置为source
。source_workload
:标识源工作负载的名称,如果缺少源信息,则标识为unknown
。source_workload_namespace
:标识源工作负载的命名空间,如果缺少源信息,则标识为unknown
。source_principal
:标识流量源的对等主体,当使用对等身份验证时设置。source_app
:根据源工作负载的app
标签标识源应用程序,如果源信息丢失,则标识为unknown
。source_version
:标识源工作负载的版本,如果源信息丢失,则标识为unknown
。destination_workload
:标识目标工作负载的名称,如果目标信息丢失,则标识为unknown
。destination_workload_namespace
:标识目标工作负载的命名空间,如果目标信息丢失,则标识为unknown
。destination_principal
:标识流量目标的对等主体,使用对等身份验证时设置。destination_app
:它根据目标工作负载的app
标签标识目标应用程序,如果目标信息丢失,则标识为unknown
。destination_version
:标识目标工作负载的版本,如果目标信息丢失,则标识为unknown
。destination_service
:标识负责传入请求的目标服务主机,例如:details.default.svc.cluster.local
。destination_service_name
:标识目标服务名称,例如details
。destination_service_namespace
:标识目标服务的命名空间。request_protocol
:标识请求的协议,设置为请求或连接协议。response_code
:标识请求的响应代码,此标签仅出现在 HTTP 指标上。connection_security_policy
:标识请求的服务认证策略,当 Istio 使用安全策略来保证通信安全时,如果指标由服务端 Istio 代理上报,则将其设置为mutual_tls
。如果指标由客户端 Istio 代理上报,由于无法正确填充安全策略,因此将其设置为unknown
。response_flags
:有关来自代理的响应或连接的其他详细信息。Canonical Service:工作负载属于一个
Canonical
服务,而Canonical
服务却可以属于多个服务。Canonical 服务具有名称和修订版本,因此会产生以下标签:source_canonical_service
source_canonical_revision
destination_canonical_service
destination_canonical_revision
destination_cluster
:目标工作负载的集群名称,这是由集群安装时的global.multiCluster.clusterName
设置的。source_cluster
:源工作负载的集群名称,这是由集群安装时的global.multiCluster.clusterName
设置的。grpc_response_status
:这标识了gRPC
的响应状态,这个标签仅出现在gRPC
指标上。
对于 Istio 来说包括 COUNTER
和 DISTRIBUTION
两种指标类型,这两种指标类型对应我们比较熟悉的计数器和直方图。
对于 HTTP,HTTP/2 和 GRPC 通信,Istio 生成以下指标:
- 请求数 (
istio_requests_total
): 这都是一个COUNTER
类型的指标,用于记录 Istio 代理处理的总请求数。 - 请求时长 (
istio_request_duration_milliseconds
): 这是一个DISTRIBUTION
类型的指标,用于测量请求的持续时间。 - 请求体大小 (
istio_request_bytes
): 这是一个DISTRIBUTION
类型的指标,用来测量 HTTP 请求主体大小。 - 响应体大小 (
istio_response_bytes
): 这是一个DISTRIBUTION
类型的指标,用来测量 HTTP 响应主体大小。 - gRPC 请求消息数 (
istio_request_messages_total
): 这是一个COUNTER
类型的指标,用于记录从客户端发送的 gRPC 消息总数。 - gRPC 响应消息数 (
istio_response_messages_total
): 这是一个COUNTER
类型的指标,用于记录从服务端发送的 gRPC 消息总数。
对于 TCP 流量,Istio 生成以下指标:
- TCP 发送字节大小 (
istio_tcp_sent_bytes_total
): 这是一个COUNTER
类型的指标,用于测量在 TCP 连接情况下响应期间发送的总字节数。 - TCP 接收字节大小 (
istio_tcp_received_bytes_total
): 这是一个COUNTER
类型的指标,用于测量在 TCP 连接情况下请求期间接收到的总字节数。 - TCP 已打开连接数 (
istio_tcp_connections_opened_total
): 这是一个COUNTER
类型的指标,用于记录 TCP 已打开的连接总数。 - TCP 已关闭连接数 (
istio_tcp_connections_closed_total
): 这是一个COUNTER
类型的指标,用于记录 TCP 已关闭的连接总数。
当我们了解了 Istio 指标数据采集的原理后,我们就可以根据自身的需求来定制了,比如在我们的监控系统采样的是 Prometheus Operator 方式,那么也应该知道该如何来配置采集这些指标数据了。
自定义指标
除了 Istio 自带的指标外,我们还可以自定义指标,要自定指标需要用到 Istio 提供的 Telemetry API,该 API 能够灵活地配置指标、访问日志和追踪数据。Telemetry API 现在已经成为 Istio 中的主流 API。
需要注意的是,Telemetry API 无法与
EnvoyFilter
一起使用,请查看此问题 issue。
从 Istio 版本 1.18 版本开始,Prometheus 的 EnvoyFilter
默认不会被安装, 而是通过 meshConfig.defaultProviders
来启用它,我们应该使用 Telemetry API 来进一步定制遥测流程,新的 Telemetry API 不但语义更加清晰,功能也一样没少。
对于 Istio 1.18 之前的版本,应该使用以下的 IstioOperator
配置进行安装:
apiVersion:install.istio.io/v1alpha1kind:IstioOperatorspec:values:telemetry:enabled:truev2:enabled:false
Telemetry 资源对象的定义如下所示:
$ kubectl explain Telemetry.specGROUP:telemetry.istio.ioKIND:TelemetryVERSION:v1alpha1FIELD:spec <Object>DESCRIPTION:Telemetry configuration for workloads. See more details at:https:FIELDS:accessLogging <[]Object>Optional.metrics <[]Object>Optional.selector <Object>Optional.tracing <[]Object>Optional.
可以看到 Telemetry 资源对象包含了 accessLogging
、metrics
、selector
和 tracing
四个字段,其中 accessLogging
和 tracing
字段用于配置访问日志和追踪数据,而 metrics
字段用于配置指标数据,selector
字段用于配置哪些工作负载需要采集指标数据。
我们这里先来看下 metrics
字段的配置,该字段的定义如下所示:
$ kubectl explain Telemetry.spec.metricsGROUP:telemetry.istio.ioKIND:TelemetryVERSION:v1alpha1FIELD:metrics <[]Object>DESCRIPTION:Optional.FIELDS:overrides <[]Object>Optional.providers <[]Object>Optional.reportingInterval <string>Optional.
可以看到 metrics
字段包含了 overrides
、providers
和 reportingInterval
三个字段。
overrides
字段用于配置指标数据的采集方式。providers
字段用于配置指标数据的提供者,这里一般配置为prometheus
。reportingInterval
字段用于配置指标数据的上报间隔,可选的。目前仅支持 TCP 度量,但将来可能会将其用于长时间的 HTTP 流。默认持续时间为 5 秒。
1.删除标签
🚩 实战:自定义指标-删除标签-2023.12.4(测试成功)
实验环境:
k8sv1.27.6(containerd:istiov1.19.3(--setprofile=demo)
实验软件:
现在我们可以通过 Telemetry API 来配置,如下所示:
#remove-tags.yamlapiVersion:telemetry.istio.io/v1alpha1kind:Telemetrymetadata:name:remove-tagsnamespace:istio-systemspec:metrics:- providers:- name:prometheus# 指定指标数据的提供者overrides:- match:# 提供覆盖的范围,可用于选择个别指标,以及生成指标的工作负载模式(服务器和/或客户端)。如果未指定,则overrides 将应用于两种操作模式(客户端和服务器)的所有指标。metric:ALL_METRICS# Istio 标准指标之一mode:CLIENT_AND_SERVER# 控制选择的指标生成模式:客户端和/或服务端。tagOverrides:# 要覆盖的标签列表destination_canonical_service:operation:REMOVE# disabled:true # 是否禁用指标
在上面的 Telemetry 资源对象中我们指定了一个 metrics
字段,表示用来自定义指标的,然后通过 providers.name
字段指定指标数据的提供者为 prometheus
,然后最重要的是 overrides
字段,用于配置指标数据的采集方式。
其中 overrides.match.metric
字段用来指定要覆盖的 Istio 标准指标,支持指标如下所示:
名称 | 描述 |
---|---|
ALL_METRICS | 使用这个枚举表示应将覆盖应用于所有 Istio 默认指标。 |
REQUEST_COUNT | 对应用程序的请求计数器,适用于 HTTP、HTTP/2 和 GRPC 流量。Prometheus 提供商将此指标导出为:istio_requests_total 。Stackdriver 提供商将此指标导出为:istio.io/service/server/request_count (服务器模式)istio.io/service/client/request_count (客户端模式) |
REQUEST_DURATION | 请求持续时间的直方图,适用于 HTTP、HTTP/2 和 GRPC 流量。Prometheus 提供商将此指标导出为:istio_request_duration_milliseconds 。Stackdriver 提供商将此指标导出为:istio.io/service/server/response_latencies (服务器模式)istio.io/service/client/roundtrip_latencies (客户端模式) |
REQUEST_SIZE | 请求体大小的直方图,适用于 HTTP、HTTP/2 和 GRPC 流量。Prometheus 提供商将此指标导出为:istio_request_bytes 。Stackdriver 提供商将此指标导出为:istio.io/service/server/request_bytes (服务器模式)istio.io/service/client/request_bytes (客户端模式) |
RESPONSE_SIZE | 响应体大小的直方图,适用于 HTTP、HTTP/2 和 GRPC 流量。Prometheus 提供商将此指标导出为:istio_response_bytes 。Stackdriver 提供商将此指标导出为:istio.io/service/server/response_bytes (服务器模式)istio.io/service/client/response_bytes (客户端模式) |
TCP_OPENED_CONNECTIONS | 工作负载生命周期中打开的 TCP 连接计数器。Prometheus 提供商将此指标导出为:istio_tcp_connections_opened_total 。Stackdriver 提供商将此指标导出为:istio.io/service/server/connection_open_count (服务器模式)istio.io/service/client/connection_open_count (客户端模式) |
TCP_CLOSED_CONNECTIONS | 工作负载生命周期中关闭的 TCP 连接计数器。Prometheus 提供商将此指标导出为:istio_tcp_connections_closed_total 。Stackdriver 提供商将此指标导出为:istio.io/service/server/connection_close_count (服务器模式)istio.io/service/client/connection_close_count (客户端模式) |
TCP_SENT_BYTES | TCP 连接期间发送的响应字节计数器。Prometheus 提供商将此指标导出为:istio_tcp_sent_bytes_total 。Stackdriver 提供商将此指标导出为:istio.io/service/server/sent_bytes_count (服务器模式)istio.io/service/client/sent_bytes_count (客户端模式) |
TCP_RECEIVED_BYTES | TCP 连接期间接收的请求字节计数器。Prometheus 提供商将此指标导出为:istio_tcp_received_bytes_total 。Stackdriver 提供商将此指标导出为:istio.io/service/server/received_bytes_count (服务器模式)istio.io/service/client/received_bytes_count (客户端模式) |
GRPC_REQUEST_MESSAGES | 每发送一个 gRPC 消息时递增的客户端计数器。Prometheus 提供商将此指标导出为:istio_request_messages_total |
GRPC_RESPONSE_MESSAGES | 每发送一个 gRPC 消息时递增的服务器计数器。Prometheus 提供商将此指标导出为:istio_response_messages_total |
比如我们这里配置的指标为 ALL_METRICS
则表示要覆盖所有的 Istio 标准指标。
overrides.match.mode
则表示选择网络流量中底层负载的角色,如果负载是流量的目标(从负载的角度看,流量方向是入站),则将其视为作为 SERVER
运行。如果负载是网络流量的源头,则被视为处于 CLIENT
模式(流量从负载出站)。
名称 | 描述 |
---|---|
CLIENT_AND_SERVER | 选择适用于工作负载既是网络流量的源头,又是目标的场景。 |
CLIENT | 选择适用于工作负载是网络流量的源头的场景。 |
SERVER | 选择适用于工作负载是网络流量的目标的场景。 |
另外的 tagOverrides
字段表示要覆盖选定的指标中的标签名称和标签表达式的集合,该字段中的 key 是标签的名称,value 是对标签执行的操作,可以添加、删除标签,或覆盖其默认值。
字段 | 类型 | 描述 | 是否必需 |
---|---|---|---|
operation | Operation | 操作控制是否更新/添加一个标签,或者移除它。 | 否 |
value | string | 当操作为 UPSERT 时才考虑值。值是基于属性的 CEL 表达式。例如:string(destination.port) 和 request.host 。Istio 暴露所有标准的 Envoy 属性。此外,Istio 也将节点元数据作为属性暴露出来。更多信息请参见 自定义指标文档。 | 否 |
对应的操作 Operator
可以配置 UPSERT
和 REMOVE
两个操作:
名称 | 描述 |
---|---|
UPSERT | 使用提供的值表达式插入或更新标签。如果使用 UPSERT 操作,则必须指定 value 字段。 |
REMOVE | 指定标签在生成时不应包含在指标中。 |
- 现在我们直接应用上面的这个资源对象,然后我们再去访问下 productpage 应用,再次验证下指标数据中是否包含我们移除的
destination_canonical_service
标签。
istioctldashboardprometheus--address0.0.0.0
看下当前指标:(是含有这个destination_canonical_service
标签的)
部署资源,再次验证:
[root@master1 istio]#kubectl apply -f remove-tags.yaml telemetry.telemetry.istio.io/remove-tagscreated[root@master1 istio]#kubectl get telemetries.telemetry.istio.io -nistio-systemNAMEAGEremove-tags21s#重新去访问一次istioctldashboardprometheus--address0.0.0.0
从上面的结果可以看到,我们已经成功删除了 destination_canonical_service
标签,这样就可以减少指标数据的基数了,可以用同样的方法再去删除一些不需要的标签。
另外需要注意在 Telemetry 对象中我们还可以通过
selector
字段来配置哪些工作负载应用这个遥测策略,如果未设置,遥测策略将应用于与遥测策略相同的命名空间中的所有工作负载,当然如果是在istio-system
命名空间中则会应用于所有命名空间中的工作负载。
测试结束。😘
2.添加指标
🚩 实战:自定义指标-删除标签-2023.12.4
实验环境:
k8sv1.27.6(containerd:istiov1.19.3(--setprofile=demo)
实验软件: