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. 2022-05-20:给定一个正数数组arr,长度为N,依次代表N个任务的难度,给定一个正数k, 你只能从0任务开始,依次处理到N-1号任务结束,就是一定要从左往右处理任务, 只不过,难度差距绝对值不

    2022-05-20:给定一个正数数组arr,长度为N,依次代表N个任务的难度,给定一个正数k, 你只能从0任务开始,依次处理到N-1号任务结束,就是一定要从左往右处理任务, 只不过,难度差距绝对值不 ...

  2. 2021-11-29:给定一个单链表的头节点head,每个节点都有value(>0),给定一个正数m, value%m的值一样的节点算一类, 请把所有的类根据单链表的方式重新连接好,返回每一类的头节点

    2021-11-29:给定一个单链表的头节点head,每个节点都有value(>0),给定一个正数m, value%m的值一样的节点算一类, 请把所有的类根据单链表的方式重新连接好,返回每一类的 ...

  3. Kotlin难点

    目录 高阶函数 双冒号 函数引用 类引用 属性引用 匿名函数 Lambda 表达式 例子 作用域函数 高阶函数 高阶函数是将函数用作参数或返回值的函数,还可以把函数赋值给一个变量. 所有函数类型都有一 ...

  4. https 原理与实践

    https 原理与实践 经典三问,是什么,为什么,怎么做? 是什么 是一种http的安全协议,在tcp ip网络模型里,http应用层是在tcp 传输层之上的,https协议规定了在tcp传输层之上还 ...

  5. vue iview 单击table行变色 获取行数据

    用到两个事件: 代码如下: 1 <Table :columns="columns" :data="tableData" @on-row-click=&qu ...

  6. 安装vue后 vue -V查不到版本号 添加环境变量没反应

    萌新一枚,今天听老大说后续有项目要用vue,于是找教程自己先看看, 验证vue是否安装成功时,提示 'vue' 不是内部命令,也不是可运行的程序 有说把vue路径添加环境变量的,试了一下,不行(后来看 ...

  7. C++面试八股文:C和C++有哪些区别?

    某日小二参加XXX科技公司的C++高级工程师开发岗位1面: 面试官:请问C和C++的区别有哪些? 小二:C++是C的超集. 面试官:还有吗? 小二:... 面试官:面试结束,回去等消息吧. 小二:淦. ...

  8. PyInstaller 完美打包 Python 脚本,输出结构清晰、便于二次编辑的打包程序

    引入问题 如果我要写一个 Python 项目,打包成 exe 运行(方便在没有 Python 的电脑上使用),我需要打包出的根目录结构美观,没有多余的.杂乱的依赖文件在那里碍眼,而且需要在发现 bug ...

  9. 前端vue uni-app基于uQRCode封装简单快速实用全端二维码生成插件

    快速实现基于uQRCode封装简单快速实用全端二维码生成插件; 下载完整代码请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id=12677 效果图 ...

  10. 1. Spring相关概念

    1. 初始 Spring ‍ 1.1 Spring 家族 ‍ 官网:​https://spring.io,从官网我们可以大概了解到: Spring 能做什么:用以开发 web.微服务以及分布式系统等, ...