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. 2021-04-16:摆放着n堆石子。现要将石子有次序地合并成一堆,规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。求出将n堆石子合并成一堆的最小得分(或最大得分)合

    2021-04-16:摆放着n堆石子.现要将石子有次序地合并成一堆,规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分.求出将n堆石子合并成一堆的最小得分(或最大得分)合 ...

  2. 《Linux的文件目录类指令 20条》

    文件目录类的指令 1.pwd指令 查看当前目录 2.ls  指令 查看当前目录所有内容信息 ls -a 显示当前目录所有的文件和目录,包括隐藏的 ls -l 以列表的方式显示信息 ls -al或la ...

  3. Simple Factory Pattern 简单工厂模式简介与 C# 示例【创建型】【设计模式来了】

    〇.简介 1.什么是简单工厂模式? 一句话解释:   客户类和工厂类严格分工,客户类只需知道怎么用,处理逻辑交给工厂类. 简单工厂模式(Simple Factory Pattern)是日常开发中常用的 ...

  4. Python asyncio之协程学习总结

    实践环境 Python 3.6.2 什么是协程 协程(Coroutine)一种电脑程序组件,该程序组件通过允许暂停和恢复任务,为非抢占式多任务生成子程序.协程也可以简单理解为协作的程序,通过协同多任务 ...

  5. Kubernetes 证书详解(鉴权)

    Kubernetes 证书详解(鉴权) 简介 上一篇 系统分析了 Kubernetes 集群中每个证书的作用和证书认证的原理.对于 Kube-apiserver,Kubelet 来说,它们都能提供 H ...

  6. Proteus运行故障分析(电源、程序等)

    问题一.Program file is not specified 原因分析:未加载hex文件. 解决方法:双击芯片,点击Program files,找到hex文件添加进来. 问题二.No power ...

  7. 翻译:REST 和 gRPC 详细比较

    译者注:在微服务架构设计,构建API和服务间通信技术选型时,对 REST 和 gRPC 的理解和应用还存在知识盲区,近期看到国外的这篇文章:A detailed comparison of REST ...

  8. 基于C# 开发的SOL SERVER 操作数据库类(SQLHelp)

    说明:以下是我近两年年来开发中最常用的C#操作sql server数据库访问类,对初学者非常有用,容易扩展,支持多库操作,多研究研究,有什么问题欢迎留言 当前环境为 C#  .NET CORE 3.0 ...

  9. gitlab配置环境及pycharm配置

    一.gitlab介绍 GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务 git.gitlab.GitHub的简单区别 git 是一种基于命令 ...

  10. 创建属于自己的github、使用git提交、更新代码至github、写好readme

    1. 在github上创建一个Repository 点击github网站,你可以用你的邮箱先注册一个账号. 点击New,转到创建一个repository的界面,如下图所示,你可以填写你的Reposit ...