1、概述

  在《应用程序通过 Envoy 代理和 Jaeger 进行分布式追踪(一)》一文中,我们详细介绍了单个应用程序如何通过 Envoy 和 Jaeger 实现链路追踪的过程。然而,单独追踪单个应用程序的链路在实际场景中往往显得不够有意义。因此,在本文中,我们将进一步扩展链路追踪范围,演示如何将 Nginx Ingress Controller 与之前提到的应用程序一起使用,从而实现更为复杂的分布式链路追踪。

2、 通过 Nginx Ingress Controller 代理访问 http_request_printer 服务

2.1 Nginx Ingress Controller 组件不注入边车,http_request_printer 服务不注入边车

流量走向: 客户端 ——》Nginx Ingress contorller Pod 中的业务容器 ——》http_request_printer Pod 中的业务容器

1)创建 Nginx Ingress contorller 资源使其能够管理 tracing 命名空间下的 Ingress 资源,注意 Nginx Ingress contorller 资源对象不要注入边车,步骤略

2)创建Ingress资源对象,并代理到 http_request_printer 服务

[root@master1 ~]# kubectl get ingress -n=tracing http-request-printer -o yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
......
name: http-request-printer
namespace: tracing
spec:
rules:
- host: http-request-printer.xx.xx.xx.xx.nip.io
http:
paths:
- backend:
service:
name: http-request-printer
port:
number: 80
path: /
pathType: ImplementationSpecific

3)通过 Ingress 访问 http_request_printer 服务

4)通过容器日志查看请求信息

可以看到除了自定义 Header 和谷歌浏览器里面的 Postman 插件加了一些 Header 信息外 Nginx Ingress Controller 组件还帮我们加了一些 Header 信息,尤其注意  Nginx Ingress Controller 组件默认会给一个请求生成 X-Request-Id Header 头信息,并且它加的这个 X-Request-Id Header 头信息和  Envoy 产生的 X-Request-Id Header 头信息(xxx-xxx-xxx)格式不一致。

注意,由于 Nginx Ingress Controller 和 http_request_printer 都没接入 Jaeger,所以此时不管怎么访问在 Jaeger 里面都是查不到链路信息的。

2.2 Nginx Ingress Controller 组件不注入边车,http_request_printer 服务注入边车

流量走向: 客户端 ——》Nginx Ingress contorller Pod 中的业务容器 ——》http_request_printer Pod 中的 Envoy 边车容器入站流量劫持 ——》http_request_printer Pod 中的业务容器

1)重复执行2.1中的步骤1)-3),唯一不同的是 http_request_printer 注入边车

2)通过容器日志查看请求信息

查看 http_request_printer 服务对应容器日志,和2.1示例日志不一样在于除了自定义 Header、谷歌浏览器里面的 Postman 插件加了一些 Header 信息、以及 Nginx Ingress Controller 组件加的一些 Header 信息外 http_request_printer 服务注入的边车 Envoy 加了和链路追踪相关的 Header 头信息 。

查看 Nginx Ingress Controller 组件对应容器日志,可以看到 http_request_printer 服务使用的 X-Request-Id Header 头信息是  Nginx Ingress Controller 组件生成并传递给 http_request_printer 这个上游服务的,注意  Nginx Ingress Controller 组件它加的这个 X-Request-Id Header 头信息和  Envoy 产生的 X-Request-Id Header 头信息(xxx-xxx-xxx)格式不一致。

3) 查看 http_request_printer 服务上报的链路信息

整个请求访问链由于只有 http_request_printer 组件注入了边车会向 jaeger-collector 组件上报链路信息,所以整个请求链只有1个 span。

2.3 Nginx Ingress Controller 组件注入边车,http_request_printer 服务注入边车

流量走向: 客户端 ——》Nginx Ingress contorller Pod 中的 Envoy 边车容器入站流量劫持 ——》Nginx Ingress contorller Pod 中的业务容器 ——》Nginx Ingress contorller Pod 中的 Envoy 边车容器出站流量劫持 ——》http_request_printer Pod 中的 Envoy 边车容器入站流量劫持 ——》http_request_printer Pod 中的业务容器

1)重复执行2.1中的步骤1)-3),唯一不同的是 Nginx Ingress Controller 组件和 http_request_printer 服务都会注入边车。

注意 1, 定义 Nginx Ingress Contorller  svc 资源对象时需要指定 Nginx Ingress Controller 服务应用层协议,因为 istio 需要知道服务提供什么七层协议,从而来为其配置相应协议的 filter chain,千万不要写成 tcp 协议,否则不会上报链路信息,详情参见《 Istio 为服务指定协议 》这篇博文。

apiVersion: v1
kind: Service
metadata:
name: nginx-ingress-controller
spec:
ports:
- name: http-80 #需要指定服务应用层协议,千万不要写成tcp协议,否则不会上报链路信息
port: 80
protocol: TCP
targetPort: 80
- name: http-443
port: 443
protocol: TCP
targetPort: 443
- name: http-10254
port: 10254
protocol: TCP
targetPort: 10254
selector:
app: nginx-ingress-controller
sessionAffinity: None
type: ClusterIP

2)通过容器日志查看请求信息

查看 http_request_printer 服务对应容器日志,和2.2示例日志不一样在于多了 X-B3-Parentspanid(父跨度ID)字段 。

查看 Nginx Ingress Controller 组件对应容器日志,可以看到 Nginx Ingress Controller 组件的 X-Request-Id Header头信息是 Nginx Ingress Controller 组件边车生成的,然后 Nginx Ingress Controller 组件将 X-Request-Id Header 头信息传递给 http_request_printer 这个上游服务的。

3) 查看 http_request_printer 服务上报的链路信息

整个请求Nginx Ingress contorller Pod 中的 Envoy 边车容器入站流量劫持、Nginx Ingress contorller Pod 中的 Envoy 边车容器出站流量劫持、http_request_printer Pod 中的 Envoy 边车容器入站流量劫持都会向 jaeger-collector 组件上报链路信息,所以整个请求链有3个 span。

下面简单分析下这三个span。

Nginx Ingress contorller Pod 中的 Envoy 边车容器入站流量劫持 span:

Nginx Ingress contorller Pod 中的 Envoy 边车容器出站流量劫持 span:

http_request_printer Pod 中的 Envoy 边车容器入站流量劫持 span:

注意 1:通过2.2和2.3章节我们知道,即使 Nginx Ingress Controller 组件不注入边车,默认也会给一个请求生成 X-Request-Id Header 头信息,并且它加的这个 X-Request-Id Header 头信息是非标准形式形式的。而 Nginx Ingress Controller 组件注入边车的话,流量先经过 Istio-Proxy 容器,自动加上标准形式的 X-Request-Id Header 头信息,再经过 Nginx 容器时,因为请求头中已经有了 X-Request-Id Header 头信息,因此就不会使用 Nginx 生成的非标准 requestID。

注意 2:为什么 Ingress 注入 Sidecar 跟不注入 Sidecar,X-Request-Id 形式不一样呢?

当请求访问 Ingress 时,会先经过一个 Sidecar Istio-Proxy Container 后,产生一个标准 ID(xxx-xxx-xxx)。请求转发至 Ingress Controller 的 Container,此时请求已经有了 RequestID,因此不会被 Nginx 覆盖。Nginx 配置文件如下:

# Reverse proxies can detect if a client provides a X-Request-ID header, and pass it on to the backend server.
# If no such header is provided, it can provide a random value.
map $http_x_request_id $req_id { # http_x_request_id 是请求进来的requestId
default $http_x_request_id; # 默认使用请求头中的requestID,即将http_x_request_id的值赋给req_id "" $request_id; # http_x_request_id是空,那么使用 request_id,request_id是Nginx默认的自带的变量,一个16位比特的随机数,用32位的16进制数表示。 ...
}
proxy_set_header X-Request-ID $req_id;

注意 3:要使用 Nginx Ingress Controller 作为 Istio 网格入口的话需要在 ingress 资源上添加如下注解,详情参见《利用Nginx Ingress Controller作为 Istio 网格入口》这篇博文。

nginx.ingress.kubernetes.io/service-upstream: "true"
nginx.ingress.kubernetes.io/upstream-vhost: http-request-printer.tracing.svc.cluster.local

不加这两个注解的话,流量从 nginx ingress controller envoy 出站的时候直接通过 PodIp:Pod端口 访问上游服务,说明没有匹配 envoy 配置规则,这时候在链路追踪UI页面查询upstream_cluster 和 upstream_cluster.name 值的话都是PassthroughCluster。

3、总结

通过《应用程序通过 Envoy 代理和 Jaeger 进行分布式追踪(一)》这篇博文我们知道,Envoy 原生支持 Jaeger,追踪所需 x-b3 开头的 Header 和 x-request-id 在不同的服务之间由业务逻辑进行传递,并由 Envoy 上报给 Jaeger,最终 Jaeger 生成完整的追踪信息。为了将各种追踪 span 整合在一起以获得完整的追踪图,应用程序必须在传入和传出请求之间传播追踪上下文信息。特别是,Istio 依赖于应用程序传播 b3 追踪 Header 以及由 Envoy 生成的请求 ID,即应用程序服务请求时需携带这些 Header。如果请求中没有 B3 HTTP Header,Istio Sidecar 代理(Envoy) 会自动生成初始化的 Headers。

在本文我们进一步扩展链路追踪范围,演示了如何将 Nginx Ingress Controller 与之前提到的应用程序一起使用,从而实现更为复杂的分布式链路追踪。应用程序通过 Envoy 代理实现分布式链路追踪一定要注意以下几点:

  1. Envoy 调用时会帮助应用程序生成 trace 信息,而调用链中关键的就是 trace_id 和 span,如果应用不传递的话,每次 Envoy 都会生成新的 trace_id,导致查看到的结果就是一个调用链中只有一个 span,所以应用程序必须在传入和传出请求之间传播追踪上下文信息,否则整个链路串不起来。
  2. 定义 svc 资源对象时需要指定服务应用层协议,因为 istio 需要知道服务提供什么七层协议,从而来为其配置相应协议的 filter chain,千万不要写成 tcp 协议,否则不会上报链路信息。( 服务指定协议配置详情请参见《 Istio 为服务指定协议 》这篇博文)
  3. 要使用 Nginx Ingress Controller 作为 Istio 网格入口的话需要在 ingress 资源上添加配置nginx.ingress.kubernetes.io/service-upstream、nginx.ingress.kubernetes.io/upstream-vhost注解。 (Nginx Ingress Controller 作为 Istio 网格入口配置详情参见《利用Nginx Ingress Controller作为 Istio 网格入口》这篇博文)

参考:Jaeger讲解

Nginx Ingress Contoller 通过 Envoy 代理和 Jaeger 进行分布式追踪(二)的更多相关文章

  1. ASP.NET Core使用Jaeger实现分布式追踪

    前言 最近我们公司的部分.NET Core的项目接入了Jaeger,也算是稍微完善了一下.NET团队的技术栈. 至于为什么选择Jaeger而不是Skywalking,这个问题我只能回答,大佬们说了算. ...

  2. 使用Nginx反向代理和proxy_cache缓存搭建CDN服务器加快Web访问速度

    碰到问题:移动用户访问web服务器www.osyunwei.com很慢解决办法:1.在移动机房放置一台nginx反向代理服务器2.通过域名DNS智能解析,所有移动用户访问www.osyunwei.co ...

  3. Nginx负载均衡中4层代理和7层代理对比

    1.4层代理和7层代理什么意思? 这里的层是OSI 7层网络模型,OSI 模型是从上往下的,越底层越接近硬件,越往上越接近软件,这七层模型分别是物理层.数据链路层.网络层.传输层.会话层.表示层.应用 ...

  4. Confluence 6 代理和 HTTPS 设置连接器

    很多用户选择将 Confluence 运行在反向代理的后面,同时还启用了 HTTPS.将你的的 Confluence 反向代理配置正确就显得非常必要了,并且能够避免后期在使用 Confluence 遇 ...

  5. 11. Ingress及Ingress Controller(主nginx ingress controller)

    11. Ingress,Ingress Controller拥有七层代理调度能力 什么是Ingress: Ingress是授权入站连接到达集群服务的规则集合 Ingress是一个Kubernetes资 ...

  6. [经验交流] Kubernetes Nginx Ingress 安装与使用

    Ingress 介绍 Kubernetes 上部署的微服务运行在它的私有网络中, 通过Pod实例的hostPort或Service实例的NodePort可以暴露到主机端口上,便于用户访问.但这样的方法 ...

  7. JDK动态代理和CGLIB的区别

    Aspect默认情况下不用实现接口,但对于目标对象,在默认情况下必须实现接口 如果没有实现接口必须引入CGLIB库 我们可以通过Advice中添加一个JoinPoint参数,这个值会由spring自动 ...

  8. JDK动态代理和CGLib动态代理简单演示

    JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期间创建接口的代理实例. 一.首先我们进行JDK动态代理的演示. 现在我们有一个简单的业务接口Saying,如下: package te ...

  9. 总结两种动态代理jdk代理和cglib代理

    动态代理 上篇文章讲了什么是代理模式,为什么用代理模式,从静态代理过渡到动态代理. 这里再简单总结一下 什么是代理模式,给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原 ...

  10. kubernetes nginx ingress 使用记录

    前言 ingress是一种可以暴露k8s集群内部service的方式,用户编辑配置文件定义一个ingress资源即可实现外部网络访问内网service. ingress controller是来管理所 ...

随机推荐

  1. windows10 docker desktop与本机数据拷贝

    目录 前景提示 一.构建环境 二.安装测试需要的nginx 三. docker文件拷贝到windows本地 总结 前景提示 发现只有docker关于docker拷贝linux内部文件的命令,但是,对于 ...

  2. 为什么有了 HTTP 还要 RPC

    哈喽大家好,我是咸鱼 随着互联网技术的发展,分布式架构越来越被人们所采用.在分布式架构下,为了实现复杂的业务逻辑,应用程序需要分布式通信实现远程调用 而这时候就需要一种协议来支持远程过程调用,以便实现 ...

  3. ACM,我“退役”了

    ACM,我"退役"了 凡是过往 皆为序章. 就在昨天,我把我所有的装备都拿回了宿舍,实验室中我的工位变得干干净净.走出实验室时,我和老唐都有些难受,毕竟,我们这样就"退役 ...

  4. web自动化01-环境搭建

    1.自动化测试是什么? 借助工具实现 借助代码编写脚本实现  2.自动化测试需要掌握那些? web自动化测试基础 移动端自动化基础 pytest自动化测试框架 po设计模式 数据驱动 日志模块使用 自 ...

  5. rest-framework 视图类源码分析

    从miminx 类开始,依次有子类RetrieveModelMixin(单个get 请求)) ,ListModelMixin(LIST请求),CreateModelMixin(POST请求),Upda ...

  6. 海量数据运维要给力,GaussDB(for Cassandra)来助力

    摘要:应用运维管理平台(AOM)和Cassandra是两个不可分割的组成部分,它们共同构成了一个高效的解决方案,可以帮助企业在应用运维业务上取得巨大的优势.在这篇文章中,我们将介绍AOM和Cassan ...

  7. 【技术积累】Java中的JVM【一】

    什么是JVM JVM英文全称为Java Virtual Machine,中文意为Java虚拟机.JVM是一种能够执行Java语言编写的程序的虚拟机器,它首次作为Java语言的一部分,后来又被移植到了许 ...

  8. Python3.9安装

    一.安装python3.9 链接:https://pan.baidu.com/s/1mDkgKt2KSoMrKVxesb76Pg?pwd=ma4n 提取码:ma4n --来自百度网盘超级会员V4的分享 ...

  9. ASP.NET Core 6框架揭秘实例演示[38]:两种不同的限流策略

    承载ASP.NET应用的服务器资源总是有限的,短时间内涌入过多的请求可能会瞬间耗尽可用资源并导致宕机.为了解决这个问题,我们需要在服务端设置一个阀门将并发处理的请求数量限制在一个可控的范围,即使会导致 ...

  10. Java打印出所有的"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该数本身。 例如:153是一个"水仙花数",因为153=1的三次方+5的三次方+3的三次方。

    代码如下: public static void main(String[] args) { int a,b,c; for(int num = 100;num <= 999;num++) { a ...