"我应该如何调试这个?"
试想一下。周五晚些时候,你正准备关闭你的笔记本电脑,然后......出现了一个问题。警告、提醒、红色。所有这些都是我们这些开发人员最讨厌的。
架构师决定基于微服务来开发这个系统。数以百计的微服务!你,作为一个开发者,会想为什么?为什么建筑师这么讨厌我?然后,就是当下最主要的问题。我应该如何调试这个?
当然,我们都明白微服务架构的好处。但我们也讨厌它的缺点。其中之一就是在数百个服务中进行调试或运行事后分析的过程。这是很乏味和令人沮丧的。
这里有一个例子:
*-我从哪里开始呢?你想,然后你选择了一个明显的候选者来开始分析:*app1*。然后你阅读了按时间段缩减的日志:*:
kubectl logs -l app=app1 --since=3h […]
-什么都没有,一切看起来都很正常。你想,也许问题来自这个其他相关的服务。 然后再想。
kubectl logs -l app=app2 --since=3h […]
-啊哈,我看到了一些奇怪的东西。这个应用程序2向这个其他的应用程序,即应用程序3*,运行了一个请求。让我们来看看。再来一次:
kubectl logs -l app=app3 --since=3h […]
调试需要很长时间。有很多挫折感,直到最后,人们设法弄清楚事情。
正如你所看到的,这个过程很慢。相当低效。前段时间,我们还没有记录和追踪功能。
今天,情况可能会有所不同。有了Grafana Loki、Grafana Tempo和其他工具,我们几乎可以立即调试事情。
可追踪性:你需要的功能
为了能够快速调试,你需要用一个独特的ID来标记请求。这个标记被称为Trace ID。而所有参与请求的元素,添加另一个独特的ID,称为span。
在最后,你能够过滤出产生问题的请求中所涉及的确切痕迹集:

而且不仅如此。你还可以把所有这些画在一个可视化的图表中,以方便了解组成你的系统的各个部分:

如何使用Grafana堆栈做到这一点
你要做的任务是用服务网模拟一个微服务系统。Istio。
你会说。Istio通过Kiali提供可观察性。
对于可观察性,Istio依靠的是Kiali。然而,在微服务的世界里,我们应该始终表明,有一些替代品可以满足要求,至少和默认的一样好。
Grafana Tempo和Grafana Loki是做得很好的日志和追踪后端的例子。无论性能如何比较,以下几点是值得考虑的:
- Tempo和Loki都集成了S3桶来存储数据。这使你不必维护和索引存储,根据你的要求,可能不需要。
- Tempo和Loki是Grafana的一部分。因此,它可以与Grafana仪表盘无缝集成。 (让我们在这里说实话:我们都喜欢并使用Grafana仪表盘。)
现在,让我们看看你如何利用Istio和Grafana Stack加快调试过程。
这将是你的架构:

先决条件
准备Istio
你需要让Istio启动并运行。
让我们安装Istio操作器:
istioctl operator init
现在,让我们实例化服务网。Istio代理在x-b3-traceid 。注意,你将设置访问日志来注入该跟踪ID作为日志消息的一部分:
kubectl apply -f - << 'EOF'
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: istio-operator
namespace: istio-system
spec:
profile: default
meshConfig:
accessLogFile: /dev/stdout
accessLogFormat: |
[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %RESPONSE_CODE_DETAILS% %CONNECTION_TERMINATION_DETAILS% "%UPSTREAM_TRANSPORT_FAILURE_REASON%" %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%" %UPSTREAM_CLUSTER% %UPSTREAM_LOCAL_ADDRESS% %DOWNSTREAM_LOCAL_ADDRESS% %DOWNSTREAM_REMOTE_ADDRESS% %REQUESTED_SERVER_NAME% %ROUTE_NAME% traceID=%REQ(x-b3-traceid)%
enableTracing: true
defaultConfig:
tracing:
sampling: 100
max_path_tag_length: 99999
zipkin:
address: otel-collector.tracing.svc:9411
EOF
让我们创建命名空间,并给它贴上标签以自动注入Istio代理:
kubectl create ns bookinfo
kubectl label namespace bookinfo istio-injection=enabled --overwrite
现在是演示应用程序bookinfo:
kubectl apply -n bookinfo -f https://raw.githubusercontent.com/istio/istio/release-1.10/samples/bookinfo/platform/kube/bookinfo.yaml
为了通过Istio访问该应用程序,你需要对其进行配置。它需要一个网关和一个虚拟服务:
kubectl apply -f - << 'EOF'
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
namespace: bookinfo
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*" # Mind the hosts. This matches all
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
namespace: bookinfo
spec:
hosts:
- "*"
gateways:
- tracing/bookinfo-gateway
- bookinfo-gateway
http:
- match:
- uri:
prefix: "/"
route:
- destination:
host: productpage.bookinfo.svc.cluster.local
port:
number: 9080
EOF
为了访问该应用程序,让我们打开一个通往Istio ingress网关(网状结构的入口)的隧道:
kubectl port-forward svc/istio-ingressgateway -n istio-system 8080:80
安装Grafana栈
现在,让我们来创建Grafana组件。让我们从Tempo开始,这是我们之前提到的追踪后端:
kubectl create ns tracing
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
helm install tempo grafana/tempo --version 0.7.4 -n tracing -f - << 'EOF'
tempo:
extraArgs:
"distributor.log-received-traces": true
receivers:
zipkin:
otlp:
protocols:
http:
grpc:
EOF
下一个组件?让我们创建一个Loki的简单部署:
helm install loki grafana/loki-stack --version 2.4.1 -n tracing -f - << 'EOF'
fluent-bit:
enabled: false
promtail:
enabled: false
prometheus:
enabled: true
alertmanager:
persistentVolume:
enabled: false
server:
persistentVolume:
enabled: false
EOF
现在,让我们部署Opentelemetry Collector。你用这个组件在你的基础设施上分布追踪:
kubectl apply -n tracing -f https://raw.githubusercontent.com/antonioberben/examples/master/opentelemetry-collector/otel.yaml
kubectl apply -n tracing -f - << 'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: otel-collector-conf
labels:
app: opentelemetry
component: otel-collector-conf
data:
otel-collector-config: |
receivers:
zipkin:
endpoint: 0.0.0.0:9411
exporters:
otlp:
endpoint: tempo.tracing.svc.cluster.local:55680
insecure: true
service:
pipelines:
traces:
receivers: [zipkin]
exporters: [otlp]
EOF
下面的组件是fluent-bit。你将使用这个组件从你的集群中刮取日志痕迹:
(注意:在配置中,你指定只取符合以下模式的容器/var/log/containers/*istio-proxy*.log)
helm repo add fluent https://fluent.github.io/helm-charts
helm repo update
helm install fluent-bit fluent/fluent-bit --version 0.16.1 -n tracing -f - << 'EOF'
logLevel: trace
config:
service: |
[SERVICE]
Flush 1
Daemon Off
Log_Level trace
Parsers_File custom_parsers.conf
HTTP_Server On
HTTP_Listen 0.0.0.0
HTTP_Port {{ .Values.service.port }}
inputs: |
[INPUT]
Name tail
Path /var/log/containers/*istio-proxy*.log
Parser cri
Tag kube.*
Mem_Buf_Limit 5MB
outputs: |
[OUTPUT]
name loki
match *
host loki.tracing.svc
port 3100
tenant_id ""
labels job=fluentbit
label_keys $trace_id
auto_kubernetes_labels on
customParsers: |
[PARSER]
Name cri
Format regex
Regex ^(?[^ ]+) (?stdout|stderr) (?[^ ]*) (?.*)$
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L%z
EOF
现在,Grafana查询。这个组件已经被配置为连接到Loki和Tempo:
helm install grafana grafana/grafana -n tracing --version 6.13.5 -f - << 'EOF'
datasources:
datasources.yaml:
apiVersion: 1
datasources:
- name: Tempo
type: tempo
access: browser
orgId: 1
uid: tempo
url: http://tempo.tracing.svc:3100
isDefault: true
editable: true
- name: Loki
type: loki
access: browser
orgId: 1
uid: loki
url: http://loki.tracing.svc:3100
isDefault: false
editable: true
jsonData:
derivedFields:
- datasourceName: Tempo
matcherRegex: "traceID=(\\w+)"
name: TraceID
url: "$${__value.raw}"
datasourceUid: tempo
env:
JAEGER_AGENT_PORT: 6831
adminUser: admin
adminPassword: password
service:
type: LoadBalancer
EOF
测试它
安装完成后,让我们为Grafana查询打开一个转发端口的隧道:
kubectl port-forward svc/grafana -n tracing 8081:80
使用你在安装时配置的凭证访问它:
- 用户:admin
- 密码:password
你会被提示到探索标签。在那里,你可以选择Loki显示在一侧,然后点击分割,选择Tempo显示在另一侧:

你会看到像这样的东西:

最后,让我们用我们已经创建的隧道创建一些流量到bookinfo应用程序。
刷新(硬刷新以避免缓存)该页面数次,直到你能看到进入Loki的痕迹。记得添加过滤器到ProductPage ,以看到其访问日志的痕迹:

点击日志,会出现一个Tempo按钮:

随即,TraceID将被传递到Tempo仪表盘上,显示出追踪和图示:


最后的想法
通过微服务显示请求中涉及的所有元素的图表,可以提高发现bug的速度,或者在运行事后分析时了解系统中发生了什么。
通过减少这个时间,你提高了效率,这样你的开发者就可以继续工作并产生更多的业务需求。
在我个人看来,这就是关键点:提高业务生产力。
可追溯性,以及在这种情况下,Grafana Stack帮助你实现这一目标。
现在,让我们让它为生产做好准备。