亚马逊AWS官方博客
如何利用指标和日志排查App Mesh相关网络问题
Amazon App Mesh是亚马逊云科技的托管服务网格解决方案。通过使用Sidecar部署方式,App Mesh可以在不对应用程序进行更改的前提下,提供网络流量控制,流量加密和可观测性,帮助您轻松运行服务,而无需修改应用源代码。
Amazon App Mesh使用开源的Envoy代理来接管进出容器的网络流量,以达到进行流量控制的目的。但由于流量需要通过Envoy进行转发,在相对复杂的网络环境下,Envoy和应用自身产生的非正常返回值(如503, 504等)会混杂在一起,导致很难判断具体故障。
Envoy有着完善的可观测性功能,会以通用的Prometheus格式暴露指标。管理员可以通过指标直观的查看Envoy的运行状况并定位故障。Envoy也同时提供访问日志功能,可以更详细的查找每条请求的来源,目标,返回值等基本信息。对于非正常返回的请求,也会通过自定义Header或在报错中包含的方式,提示问题根因。
本文会介绍如何在Amazon Elastic Kubernetes Service (以下简称Amazon EKS) 环境下收集App Mesh暴露的指标和日志,并通过这些资源分析问题。其他运行环境(Amazon Elastic Container Service,Amazon EC2)下仅有采集方式不同,分析方式相对一致,故在此不再赘述。
先决条件
- 拥有管理员权限的亚马逊云科技账号
- 正在运行的Amazon EKS集群,版本为1.21以上
- 已安装
kubectl
和helm
客户端 - 使用者对Amazon EKS和Amazon App Mesh有基本了解
部署示例应用
部署Amazon App Mesh Controller
在Amazon EKS环境,可以使用Amazon App Mesh Controller创建并管理Amazon App Mesh资源,并自动为启动的Pod注入Envoy。Amazon App Mesh Controller可以通过Helm Chart部署。请参考此文档以部署Amazon App Mesh Controller。
部署示例应用
亚马逊云科技提供了示例应用以演示Amazon App Mesh的功能。运行以下命令以部署howto-k8s-connection-pools
应用,该应用会演示连接池功能。请将123456789012
替换为您的12位亚马逊云科技账户ID,us-west-2
替换为您Amazon EKS 集群所在的区域。
这一部署脚本会构建应用镜像,推送至Amazon ECR,并将应用部署到Amazon EKS。Amazon App Mesh Controller会自动在Pod中插入Envoy。
可以通过kubectl get all -n howto-k8s-connection-pools
检查是否部署完成:
部署完成后,将创建的Service打上标签以便下一步进行服务发现。运行下列命令:
利用Prometheus抓取Amazon App Mesh数据平面指标
Amazon App Mesh采用Envoy作为数据平面。Envoy通过/stats
接口提供数百个指标以展现Envoy自身和处理的连接状况。连接会根据其状况(返回值,是否触发连接池,是否重试,中断原因等)被添加到某项指标中。 Envoy支持通过statsd和Prometheus格式暴露指标。在Amazon EKS环境下,可以使用Prometheus收集指标,并使用Grafana可视化分析。
安装Prometheus
使用kube-prometheus快速部署完整的Prometheus集群。该方案会部署Prometheus Operator,并通过Operator部署Prometheus实例。同时会部署node-exporter, kube-state-metrics, alertmanager和Grafana,快速构建完整的监控体系。在终端运行以下命令:
默认情况下,创建的Prometheus没有持久化存储,会导致数据在Pod重启后丢失。可参考文档 编辑manifests/prometheus-prometheus.yaml
,自行为Prometheus添加持久化存储。
为访问Prometheus查询指标,需要将Prometheus通过负载均衡器对外暴露。修改manifests/prometheus-service.yaml
:
默认情况下,Prometheus无法抓取来自其他Namespace的内容。需要为Prometheus提供更多权限。将manifestsprometheus-clusterRole.yaml
替换成以下内容:
修改完成后,进行部署:
组件默认会部署在monitoring
命名空间。部署完成后,可使kubectl get po -n monitoring
检查Pod运行状况:
可以通过kubectl get svc prometheus-k8s -n monitoring
获取访问Prometheus的地址,并通过http://<Prometheus地址>:9090/
访问:
利用Prometheus获取Envoy指标
Envoy默认将指标通过/stats/prometheus
接口以Prometheus兼容格式将指标暴露出来。通过配置ServiceMonitor
,Prometheus可以通过服务发现的形式,自动抓取Service对应的Pod,从而捕获Envoy暴露的指标。
创建servicemonitor.yaml
,内容如下:
运行kubectl apply -f servicemonitor.yaml
将其部署至集群。部署完成后,在Prometheus界面中的Status
– Targets
应当可以看到运行的Pod。 返回Graph,运行查询envoy_server_live{}
,结果数量应与目前部署Pod数量一致。 此时,Envoy的指标已被Prometheus所捕获,可以通过Prometheus对指标进行分析。
启用Envoy访问日志
Amazon App Mesh允许用户快速启用Envoy访问日志。默认日志的格式为:
可以参考此Envoy文档 获取日志各字段的详细含义。其中对故障排查作用较大的为RESPONSE_CODE
和RESPONSE_FLAGS
,这两个指标描述了返回值和非正常返回时的报错原因。
可以通过修改Virtual Node的参数以启用访问日志。运行以下命令编辑创建好的Virtual Node:
kubectl edit virtualnode green -n howto-k8s-connection-pools
该配置生效后,Envoy会将访问日志输出至标准输出,可以通过kubectl logs <Pod名> -c envoy
命令查看。
可以通过Fluent Bit等日志收集器将日志收集到其他存储,或使用Log Hub等日志解决方案进行收集。
注:目前通过Amazon App Mesh Controller创建的Virtual Node无法自定义日志格式。
通过指标和日志进行分析
下面会以连接池场景为例,测试如何根据指标和日志分析错误原因。样例应用已经为green
Virtual Node配置了连接池,详细配置可以通过kubectl get virtualnode green -n howto-k8s-connection-pools -o yaml
查看。具体配置如下所示:
可以看到,该配置允许最多10个并发请求,在连接池中还可以有10个请求在等待。
在部署示例应用时,同时在default
命名空间部署了一个fortio
Pod。Fortio 是一个负载测试组件,可以进行基于http或grpc的负载测试。您可以利用部署的fortio生成远超于该并发数的流量以进行测试,以模拟流量过载的场景。运行以下命令:
此时您可以新建一个终端窗口,模拟其他用户访问:
多运行几次,会发现访问出错,错误日志如下所示:
根据返回HTTP头中的server
字段,可以判断该报错是由Envoy返回。您可以从报错信息和Envoy添加的自定义HTTP头 x-envoy-overloaded: true
中了解到错误原因是overflow
。通过查询Envoy文档,可以发现该错误来源于断路器,当连接池满时会产生该报错。
您可以检查Envoy访问日志以进一步确认:
可以看到,该请求返回值是503,错误码是UO
。通过查询Envoy访问日志文档,UO错误码代表Upstream overflow (circuit breaking) in addition to 503 response code.
,同样显示断路器开启,导致Envoy直接返回503。
除了访问日志外,您还可以通过指标查找错误原因。由于断路器工作在Cluster层面,您可以从Cluster的指标列表中找到相关指标,在Prometheus上运行: envoy_cluster_circuit_breakers_default_cx_open{pod~="green-.*"}
此时可以看到,标注为envoy_cluster_name="cds_ingress_howto-k8s-connection-pools_green_howto-k8s-connection-pools_http_8080"
的值为1
。根据App Mesh的命名规则,带Ingress前缀的Cluster的作用是Envoy向应用发送入站请求。该指标置1意味着入站断路器开启,Envoy阻断了发往应用的请求。
为检查应用本身的运行状况,可以运行下列查询:
envoy_cluster_upstream_rq_timeout{pod~="green-.*", envoy_cluster_name="cds_ingress_howto-k8s-connection-pools_green_howto-k8s-connection-pools_http_8080"}
envoy_cluster_upstream_cx_connect_fail{pod~="green-.*", envoy_cluster_name="cds_ingress_howto-k8s-connection-pools_green_howto-k8s-connection-pools_http_8080"}}
这两条查询会反馈Envoy向应用发出的请求是否超时或连接失败。可以看到,这两次查询返回值都是0,也就意味着应用正常工作。
综合以上分析可以得知,此时应用仍然正常工作,但受断路器限制,连接在Envoy处由于连接池满,被提前终止,从而返回503错误。通过修改Virtual Node中的ConnectionPool
配置,问题解决。
常见的故障分析流程
从刚才的示例中您可以看到,Envoy会通过多种手段暴露错误信息以便排查。在真实环境,不知道错误来源的情况下,可以按照以下步骤进行排查:
- 如果可以获得报错时的完整响应Header和消息,则Envoy会尽可能的将错误原因通过自定义Header(一般为
x-envoy
开头)返回。可以根据错误原因查找对应的指标或日志错误码。 - 可以通过分布式跟踪,日志搜索或指标监控确定报错时访问到的Pod,通过查找访问日志确定问题来源和根因。
- 如果无法获得访问日志,则需要通过指标查询来确认具体问题根因。由于涉及到的指标较多,建议提前对关键的报错指标设置告警。
清理
为防止创建的资源产生额外费用,您可以清理创建的资源。
- 在终端中,运行
kubectl delete all -n howto-k8s-connection-pools
以删除部署的示例应用,负载均衡器及Amazon App Mesh资源。 - 运行以下命令以删除部署的Prometheus实例。
- 进入Amazon ECR控制台,删除创建的镜像仓库。
总结
Envoy提供了指标,错误消息和访问日志三种方式,来帮助管理员分析异常返回的具体原因。本文简单介绍了如何使用Prometheus监控Envoy指标,如何开启访问日志,以及在故障发生时如何利用这三种手段快速定位问题。限于篇幅,本文并未详细介绍Envoy的其他指标和日志含义,各位可以从Envoy官方文档和社区资源中自行探索。