可观测性
指标
安装Prometheus和Grafana组件用来收集和可视化查看日志。
默认情况下,istio定义并生成一组标准指标,但您也可以使用Telemetry API自定义标准指标并创建新指标。
自动生成
参照准备部署httpbin和sleep服务,并从sleep访问httpbin服务。
$ kubectl exec -it $(kubectl get po -l app=sleep -o jsonpath={.items[0].metadata.name}) -c sleep -- curl http://httpbin:8000/headers
等待一会,查看是否自动生成了istio_request_total
指标
警告
基于Kind部署的测试集群,可能会存在istio_request
等指标无法自动生成的情况。
指标含义
指标 | 含义 | 范围 |
---|---|---|
istio_requests_total | 请求数:用于记录Istio代理处理的总请求数。 | REQUEST_COUNT |
istio_request_duration_milliseconds | 请求时长:用于测量请求的持续时间。 | REQUEST_DURATION |
istio_request_bytes | 请求体大小:用来测量HTTP请求主体大小。 | REQUEST_SIZE |
istio_response_bytes | 响应体大小:用来测量HTTP响应主体大小。 | RESPONSE_SIZE |
istio_request_messages_total | gRPC 请求消息数:用于记录从客户端发送的gRPC消息总数。 | GRPC_REQUEST_MESSAGES |
istio_response_messages_total | gRPC 响应消息数:用于记录从服务端发送的gRPC消息总数。 | GRPC_RESPONSE_MESSAGES |
istio_tcp_sent_bytes_total | TCP 发送字节大小:用于测量在TCP连接情况下响应期间发送的总字节数。 | TCP_SENT_BYTES |
istio_tcp_received_bytes_total | TCP 接收字节大小:用于测量在TCP连接情况下请求期间接收到的总字节数。 | TCP_RECEIVED_BYTES |
istio_tcp_connections_opened_total | TCP 已打开连接数:用于记录TCP已打开的连接总数。 | TCP_OPENED_CONNECTIONS |
istio_tcp_connections_closed_total | TCP 已关闭连接数:用于记录TCP已关闭的连接总数。 | TCP_CLOSED_CONNECTIONS |
TelemetryApi
使用TelemetryApi实现对指标中标签的新增、覆盖和禁用操作。
覆盖标签
- 去除
istio_requests_total
指标中请求响应
的source_cluster
标签
$ kubectl apply -f - <<EOF
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: remove-tags
spec:
metrics:
- providers:
- name: prometheus
overrides:
- match:
mode: CLIENT_AND_SERVER # 匹配请求和响应
metric: REQUEST_COUNT
tagOverrides:
source_cluster:
operation: REMOVE
EOF
metrics的取值来自指标含义中的范围
再次请求httpbin服务后,等待约15s,继续查看istio_requests_total
指标,发现标签source_cluster
已经不在了。
- 去除
istio_tcp_connections_opened_total
指标中请求
的source_cluster
标签
安装tcp-echo服务后,执行命令访问tcp服务
$ kubectl exec -it "$(kubectl get po -l app=sleep -o jsonpath={.items..metadata.name})" -c sleep -- sh -c 'echo "port 9000" | nc tcp-echo 9000'
查看prometheus对应的指标结果
警告
TCP相关的指标也是由Envoy自动生成的
配置Telemetry规则,将请求指标中的source_cluster
去除
$ kubectl apply -f - <<EOF
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: remove-tags
spec:
metrics:
- providers:
- name: prometheus
overrides:
- match:
mode: CLIENT # 匹配请求
metric: TCP_OPENED_CONNECTIONS # 匹配TCP_OPEN相关指标
tagOverrides:
source_cluster:
operation: REMOVE
EOF
再次执行命令,查看prometheus查询结果
CLIENT端的
source_cluster
已经不在,但SERVER端的source_cluster
仍在。
添加标签
- 为
istio_requests_total
添加source_x
和destination_x
标签
$ kubectl apply -f - <<EOF
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: custom-tags
spec:
metrics:
- overrides:
- match:
metric: REQUEST_COUNT
mode: CLIENT
tagOverrides:
destination_x:
value: upstream_peer.labels['app'].value
- match:
metric: REQUEST_COUNT
mode: SERVER
tagOverrides:
source_x:
value: downstream_peer.labels['app'].value
providers:
- name: prometheus
EOF
自定义标签的值支持如下参数,通过upstream_peer/downstream_peer调用
字段 类型 值 name
string
Pod 的名字。 namespace
string
Pod 运行的命名空间。 labels
map
工作负载标签。 owner
string
工作负载所有者。 workload_name
string
工作负载名称。 platform_metadata
map
带有前缀键的平台元数据。 istio_version
string
代理的版本标识符。 mesh_id
string
网格的唯一标识符。 app_containers
list<string>
应用程序容器的短名称列表。 cluster_id
string
此工作负载所属的集群的标识符。
再次访问httpbin服务,查看prometheus结果
警告
如果自定义标签一直无法出现,说明受到其他TelemetryApi
规则影响,建议删除其他规则避免影响。
禁用标签
禁用请求和响应端的istio_requests_total
指标
$ kubectl apply -f - <<EOF
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: remove-request-count
spec:
metrics:
- providers:
- name: prometheus
overrides:
- disabled: true
match:
mode: CLIENT_AND_SERVER
metric: REQUEST_COUNT
EOF
日志
提示
OpenTelemetry是CNCF的一个观测性项目,旨在提供可观测性领域的标准化方案,以简化在分布式系统中生成、收集、处理、导出跟踪和度量数据的过程。
istio中支持配置Envoy代理以OpenTelemetry格式
导出访问日志,并发送到指定的OpenTelemetry收集器
基于Enovy访问日志记录
安装sleep和httpbin服务,并部署otel-collector组件用于日志数据的采集和处理。
部署Telemetry资源告诉istio将访问日志发送到otel-collector收集器。
$ kubectl apply -f - <<EOF
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: sleep-logging
spec:
selector:
matchLabels:
app: sleep # 匹配需要导出访问日志的服务
accessLogging:
- providers:
- name: otel # 指定istio配置的provider
EOF
执行命令从sleep访问http
$ kubectl exec -it $(kubectl get po -l app=sleep -ojsonpath={.items[0].metadata.name}) -c sleep -- curl httpbin:8000/status/418
查看otel-collector输出的访问日志
$ kubectl -n istio-system logs -f --tail 200 -l app=opentelemetry-collector
访问日志如下所示(去除了不重要的数据)
Body: [2024-01-25T06:03:13.551Z] "GET /status/418 HTTP/1.1" 418 - via_upstream - "-" 0 135 9 8 "-" "curl/8.5.0" "c52dd60d-c5e7-98e6-8122-3c57483ddab2" "httpbin:8000" "10.244.0.53:80" outbound|8000||httpbin.default.svc.cluster.local 10.244.0.50:33034 10.96.67.124:8000 10.244.0.50:41772 - default
警告
从sleep访问httpbin服务,访问日志会出现两条,分别是sleep的出站和httpbin的入站访问日志。因为envoy会代理出入站流量
。
访问日志格式
日志运算符 | 对应sleep中的访问日志 | httpbin 中的访问日志 |
---|---|---|
[%START_TIME%] | [2020-11-25T21:26:18.409Z] | [2020-11-25T21:26:18.409Z] |
"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" | "GET /status/418 HTTP/1.1" | "GET /status/418 HTTP/1.1" |
%RESPONSE_CODE% | 418 | 418 |
%RESPONSE_FLAGS% | - | - |
%RESPONSE_CODE_DETAILS% | via_upstream | via_upstream |
%CONNECTION_TERMINATION_DETAILS% | - | - |
"%UPSTREAM_TRANSPORT_FAILURE_REASON%" | "-" | "-" |
%BYTES_RECEIVED% | 0 | 0 |
%BYTES_SENT% | 135 | 135 |
%DURATION% | 4 | 3 |
%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% | 4 | 1 |
"%REQ(X-FORWARDED-FOR)%" | "-" | "-" |
"%REQ(USER-AGENT)%" | "curl/7.73.0-DEV" | "curl/7.73.0-DEV" |
"REQ(X-REQUEST-ID)%" | "84961386-6d84-929d-98bd-c5aee93b5c88" | "84961386-6d84-929d-98bd-c5aee93b5c88" |
"REQ(:AUTHORITY)%" | "httpbin:8000" | "httpbin:8000" |
"UPSTREAM_HOST%" | "10.44.1.27:80" | "127.0.0.1:80" |
%UPSTREAM_CLUSTER% | outbound|8000||httpbin.foo.svc.cluster.local | inbound|8000|| |
%UPSTREAM_LOCAL_ADDRESS% | 10.44.1.23:37652 | 127.0.0.1:4185 |
%DOWNSTREAM_LOCAL_ADDRESS% | 10.0.45.184:800 | 10.44.1.27:80 |
%DOWNSTREAM_REMOTE_ADDRESS% | 10.44.1.23:46520 | 10.44.1.23:37652 |
%REQUESTED_SERVER_NAME% | - | outbound_.8000_._.httpbin.foo.svc.cluster.local |
%ROUTE_NAME% | default | default |
默认格式如上所示,同样我们也可以自定义需要显示的日志格式
$ kubectl -n istio-system apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: istio
namespace: istio-system
data:
mesh: |-
defaultConfig:
discoveryAddress: istiod.istio-system.svc:15012
tracing:
zipkin:
address: zipkin.istio-system:9411
enablePrometheusMerge: true
accessLogFile: /dev/stdout
extensionProviders:
- name: otel
envoyOtelAls:
service: opentelemetry-collector.istio-system.svc.cluster.local
port: 4317
logFormat:
text: "[%START_TIME%]:\"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\""
rootNamespace: istio-system
trustDomain: cluster.local
EOF
再次发起服务请求,并查看访问日志
Body: [2024-01-25T07:42:35.182Z]:"GET /status/418 HTTP/1.1"
访问日志持久化
安装grafana-loki来存储otel收集的访问日志,并通过grafana来查看。在浏览器中输入IP:30000
来访问grafana,添加数据源loki,查询访问日志结果如下:
通过label标签匹配日志信息,也可以开启右上角的
live
功能,有访问日志会立刻刷新在控制台。
TelemetryApi
启用访问日志记录
$ kubectl -n istio-system apply -f - <<EOF
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: mesh-logging-default
spec:
accessLogging:
- providers:
- name: otel
EOF
不定义selector,默认匹配ns下的所有服务。
如果是根空间(istio-system),则所有命令空间都生效
。
禁用服务日志记录
$ kubectl apply -f - <<EOF
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: disable-sleep-logging
spec:
selector:
matchLabels:
app: sleep
accessLogging:
- providers:
- name: otel
disabled: true
EOF
禁用default下的app=sleep的服务的访问日志记录。那么sleep的
出入站日志
都不会被记录。
禁用出/入站日志记录
$ kubectl apply -f - <<EOF
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: disable-httpbin-logging
spec:
selector:
matchLabels:
app: httpbin
accessLogging:
- providers:
- name: otel
match:
mode: SERVER
disabled: true
EOF
参数 CLIENT SERVER CLIENT_AND_SERVER 含义 出站 入站 出站和入站 配合disabled使用,表示禁用
出站、入站或出入站
的访问日志记录。
根据条件记录日志
$ kubectl apply -f - <<EOF
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: filter-sleep-logging
spec:
selector:
matchLabels:
app: sleep
accessLogging:
- providers:
- name: otel
filter:
expression: response.code <= 200
EOF
通过sleep服务发起的请求,只有响应码
<=200
的才会被记录,sleep处理其他服务发起的请求则不受影响。更多
分布式追踪
Istio基于Envoy实现用户对跨多个分布式服务网格的1个请求
进行追踪分析。进而可以通过可视化的方式更加深入地了解请求的延迟,序列化和并行度。
上下文传递
警告
应用程序无法自动传播追踪请求头,所以在应用程序中进行下游调用时,请传递追踪的请求头,来保证调用链的完整。
不同的追踪组件,追踪的请求头不同,应用程序必须按照下表要求转发请求头。
请求头 | 组件 |
---|---|
x-request-id | Envoy |
x-b3-traceid x-b3-spanid x-b3-parentspanid x-b3-sampled x-b3-flags | Zipkin Jaeger skywalking |
x-datadog-trace-id x-datadog-parent-id x-datadog-sampling-priority | Datadog |
x-ot-span-context | Lightstep |
sw8 | skywalking |
Envoy专用请求头
x-request-id
必须转发,用于对日志和追踪进行一致的采样。其他的请求头根据各自的组件选择转发。
TelemetryApi
部署zipkin,istio将根据配置发送追踪信息到该组件。
启动链路追踪
$ kubectl apply -f - <<EOF
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: mesh-default
namespace: istio-system
spec:
tracing:
- providers:
- name: "zipkin"
EOF
部署在
istio-system
根目录下,默认对所有ns下的服务都生效。
自定义采样率
$ kubectl apply -f - <<EOF
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: mesh-default
namespace: istio-system
spec:
tracing:
- providers:
- name: "zipkin"
randomSamplingPercentage: 100.0 # 0 -> 100.0
EOF
默认采样率是1%,即100次请求记录一次。
执行命令
$ kubectl exec -it $(kubectl get po -l app=sleep -ojsonpath={.items[0].metadata.name}) -c sleep -- curl httpbin:8000/headers
httpbin服务将我们的请求头参数全部返回,其中就包含了zipkin支持的b3*
的请求头。
{
"headers": {
"Accept": "*/*",
"Host": "httpbin:8000",
"User-Agent": "curl/8.5.0",
"X-B3-Parentspanid": "97aa916a8756def2",
"X-B3-Sampled": "1",
"X-B3-Spanid": "55b07652e65cbb6e",
"X-B3-Traceid": "bc805d24301ad17f97aa916a8756def2",
"X-Envoy-Attempt-Count": "1",
"X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/httpbin;Hash=65030e2dbc6f613f147a35df8cf93350ca733a50109bab4c3d36633c08c392c6;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/sleep"
}
}
"X-B3-Sampled": "1"
表示访问记录被zipkin采样。
访问IP:30014查看链路追踪流程。
$ kubectl exec -it $(kubectl get po -l app=sleep -ojsonpath={.items[0].metadata.name}) -c sleep -- curl httpbin:8000/status/418
自定义追踪标签
$ kubectl apply -f - <<EOF
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: mesh-default
namespace: istio-system
spec:
tracing:
- providers:
- name: "zipkin"
randomSamplingPercentage: 100.0
customTags:
"provider":
literal:
value: "zipkin123"
EOF
再次发起请求,然后查看链路追踪数据,能看到自定义的provider标签已经根据Span创建。