点赞
评论
收藏
分享
举报
采用 NGINX Ingress Controller for Kubernetes 支持 OpenTracing?
发表于2021-08-23 11:04

浏览 38.6k

近年来,Kubernetes的关注度稳健增长,日益获得业内青睐,许多企业纷纷在生产环境中采用该平台与微服务架构。然而,采用分布式服务也带来了新的挑战。充分理解和调试微服务应用程序的运行并非易事,尤其在服务数量多的情况下。想要识别故障或性能问题,我们需要分布式的追踪工具——当数据在构成应用的微服务之间传输时,这个工具能够端到端地追踪请求。

OpenTracing 是一个用于分布式跟踪的规范和api集。在此前发表的一篇博文中,我们展示了如何使用OpenTracing社区创建的开源模块(nginx-opentracing)为NGINX Open Source 和 NGINX Plus代理和负载平衡的应用程序启用分布式跟踪。在撰写本文时,OpenTracing 提供 9 种编程语言的类库。

现在,为了在使用 NGINX 和 NGINX Plus Ingress Controllers for Kubernetes 时对集群中的流量执行负载均衡,我们还在 Kubernetes 集群中添加了对 HTTP 和 gRPC 请求 OpenTracing 的原生支持。

使用Open Tracing现有多种用例,此处我们将重点讨论如何使用请求上下文传播跟踪服务器端点。在分布式环境中,集群内的每个应用均被视为不同的服务器。设想一下,两个应用或服务都参与处理来自客户端的请求。例如,在下图所示拓扑结构中,应用 1 是一台 既可处理 HTTP 请求并将其重定向至应用 2的Web服务器。这两个应用均在 NGINX Ingress Controller所执行负载均衡的 Kubernetes 集群中运行,并启用了 OpenTracing。因此我们可在来自 Ingress Controller的请求通过应用 1 并到达应用 2 时对其进行跟踪。

有关系统组件执行的任何操作(例如服务)的信息将会被 OpenTracing 所谓的 span 捕获。将这些 span 链接在一起,我们即可在信息穿过集群微服务的整个过程中对其进行识别和跟踪。

注:在撰写本文时,OpenTracing 仅在 NGINX Ingress Controller的 edge 版本中可用。


将 OpenTracing 构建到 NGINX Ingress Controller镜像中

搭配使用OpenTracing 和我们的 Ingress Controller需要将 OpenTracing 模块结合到 NGINX 或 NGINX Plus Ingress Controller的 Docker 镜像中,并指定所用跟踪器。

在Ingress Controller的 GitHub 存储库中,我们为 NGINX 和 NGINX Plus 提供了单独的 Dockerfile。虽然二者均将开源 OpenTracing 模块整合到 Docker 镜像中,但处理的方式不同:

● 在NGINX系统中, DockerfileWithOpentracing 从 GitHub 下载 OpenTracing 模块,并在 Docker 的第一阶段构建中对其进行手动汇集。

● 在NGINX Plus系统中,DockerfileWithOpentracingForPlus 使用软件保管系统获取NGINX 使用开源和 OpenTracing 模块所构建并维护的动态模块。

执行以下步骤:

1. (可选)指定一个Jaeger默认以外的跟踪器。插件也适用于 Datadog、LightStep 和 Zipkin。使用不同的跟踪器需根据 OpenTracing 启用说明中前提条件部分修改 Dockerfile。

2. 遵照 Ingress Controller存储库中的说明构建 Docker 镜像。在第 3 步中,需指定相应的 Dockerfile。

NGINX:

$ make clean

$ make DOCKERFILE=DockerfileWithOpentracing PREFIX=YOUR-PRIVATE-REGISTRY/nginx-ingress

NGINX Plus:

$ make clean

$ make DOCKERFILE=DockerfileWithOpentracingForPlus PREFIX=YOUR-PRIVATE-REGISTRY/nginx-plus-ingress

3. 按照 Ingress Controller存储库中的说明安装镜像。

在运行说明第 3 节中的 kubectl apply 命令前,切记更新 YAML 文件,以指定已引入 OpenTracing 的新建镜像:

containers:

- image: IMAGE_WITH_OPENTRACING


部署 Jaeger 跟踪器

本博文所使用的是Jaeger默认跟踪器。为简单起见,我们将其部署在集群内部,但也您也可以将其部署在集群外部。Ingress Controller Pod 和任何使用 OpenTracing 的 Pod 必须有访问跟踪器的权限。

同样为简单起见,我们将使用 Jaeger 提供的一体化模板在集群中设立非生产 Jaeger 实例。最终适合开发环境的部署将创建一个 Jaeger Pod 及访问该 Pod 所需的服务,并在默认命名空间中设立最新 Jaeger 版本,其具有内存存储容量和有限功能。

$ kubectl create -f https://raw.githubusercontent.com/jaegertracing/jaeger-kubernetes/master/all-in-one/jaeger-all-in-one-template.yml

在生产环境中,我们推荐使用 Jaeger Operator 进行安装。获取更多有关 Jaeger 的信息,请访问 Jaeger 网站。


启用 OpenTracing

以下针对 NGINX Ingress Controller的 ConfigMap (nginx-config.yaml) 全局启用 OpenTracing,并在 data 部分中添加了三个新的 ConfigMap 键名:

● opentracing 键为所有在集群中创建的 Ingress 资源启用 OpenTracing。

● opentracing-tracer 键指定前往跟踪器库路径,并在您构建它时将跟踪器库下载并复制到 Ingress 控制器镜像中。

● opentracing-tracer-config 键嵌入了跟踪器配置。service_name 字段定义与实际 span 相关的服务;reporter 字段指定跟踪器地址和端口(在此示例中是上一部分 Jaeger 服务一体式模板部署的的地址和端口)。sampler 字段指定客户端采样配置;为简单起见,我们将配置可供所有 trace 进行采样的“常量”采样器 (常项)。

kind: ConfigMap

apiVersion: v1

metadata:

name: nginx-config

namespace: nginx-ingress

data:

opentracing: "True"

opentracing-tracer: "/usr/local/lib/libjaegertracing_plugin.so"

opentracing-tracer-config: |

{

"service_name": "nginx-ingress",

"sampler": {

"type": "const",

"param": 1

},

"reporter": {

"localAgentHostPort": "jaeger-agent.default.svc.cluster.local:6831"

}

}

应用,只需运行:

$ kubectl apply –f nginx-config.yaml


部署示例应用

为简单起见,我们将使用 NGINX 实例作为我们的后端应用,其中有两个不同应用——应用 1 配置将所有 HTTP 流量重定向到应用 2。

两个应用均使用 ConfigMap 和数据卷 配置在 Pod 内运行的 NGINX 实例。 其中一个 ConfigMap 采用 NGINX 配置,另一个则用于为每个 NGINX 实例指定跟踪器配置(我们在每个应用中采用该配置,因为如前所述,应用 Pod 发送有关请求的信息需访问跟踪器)。

部署应用 1

以下为第一个应用的 YAML 清单 (app1.yaml):

apiVersion: v1

kind: ConfigMap

metadata:

name: app1-config

data:

nginx.conf: |-

user nginx;

worker_processes 1;

load_module modules/ngx_http_opentracing_module.so;

error_log /var/log/nginx/error.log warn;

pid /var/run/nginx.pid;

events {

worker_connections 1024;

}

http {

opentracing_load_tracer /usr/local/lib/libjaegertracing_plugin.so

/etc/jaeger-config.json;

opentracing on;

server {

listen 80;

server_name example.com;

location / {

opentracing_propagate_context;

proxy_set_header Host $host;

proxy_pass http://app2-svc:80;

}

}

}

---

apiVersion: v1

kind: ConfigMap

metadata:

name: jaeger-config-app1

data:

jaeger-config.json: |-

{

"service_name": "app1",

"sampler": {

"type": "const",

"param": 1

},

"reporter": {

"localAgentHostPort": "jaeger-agent.default.svc.cluster.local:6831"

}

}

---

apiVersion: apps/v1

kind: Deployment

metadata:

name: app1

spec:

replicas: 1

selector:

matchLabels:

app: app1

template:

metadata:

labels:

app: app1

spec:

containers:

- name: app1

image: opentracing/nginx-opentracing

ports:

- containerPort: 80

volumeMounts:

- name: config-app1

mountPath: /etc/nginx/nginx.conf

subPath: nginx.conf

readOnly: true

- name: config-jaeger

mountPath: /etc/jaeger-config.json

subPath: jaeger-config.json

readOnly: true

volumes:

- name: config-app1

configMap:

name: app1-config

- name: config-jaeger

configMap:

name: jaeger-config-app1

---

apiVersion: v1

kind: Service

metadata:

name: app1-svc

spec:

ports:

- port: 80

targetPort: 80

selector:

app: app1


运行以下命令部署第一个应用:

$ kubectl apply –f app1.yaml

部署应用 2

以下为第二个应用的 YAML 清单 (app2.yaml):

apiVersion: v1

kind: ConfigMap

metadata:

name: app2-config

data:

nginx.conf: |-

user nginx;

worker_processes 1;

load_module modules/ngx_http_opentracing_module.so;

error_log /var/log/nginx/error.log warn;

pid /var/run/nginx.pid;

events {

worker_connections 1024;

}

http {

opentracing_load_tracer /usr/local/lib/libjaegertracing_plugin.so

/etc/jaeger-config.json;

opentracing on;

server {

listen 80;

server_name example.com;

location / {

opentracing_propagate_context;

opentracing_tag app app2;

return 200 "Success!\n";

}

}

}

---

apiVersion: v1

kind: ConfigMap

metadata:

name: jaeger-config-app2

data:

jaeger-config.json: |-

{

"service_name": "app2",

"sampler": {

"type": "const",

"param": 1

},

"reporter": {

"localAgentHostPort": "jaeger-agent.default.svc.cluster.local:6831"

}

}

---

apiVersion: apps/v1

kind: Deployment

metadata:

name: app2

spec:

replicas: 1

selector:

matchLabels:

app: app2

template:

metadata:

labels:

app: app2

spec:

containers:

- name: app2

image: opentracing/nginx-opentracing

ports:

- containerPort: 80

volumeMounts:

- name: config-app2

mountPath: /etc/nginx/nginx.conf

subPath: nginx.conf

readOnly: true

- name: config-jaeger

mountPath: /etc/jaeger-config.json

subPath: jaeger-config.json

readOnly: true

volumes:

- name: config-app2

configMap:

name: app2-config

- name: config-jaeger

configMap:

name: jaeger-config-app2

---

apiVersion: v1

kind: Service

metadata:

name: app2-svc

spec:

ports:

- port: 80

targetPort: 80

selector:

app: app2

运行以下命令部署第二个应用:

$ kubectl apply -f app2.yaml

部署 Ingress 资源

为了支持集群外部对应用 1的访问,我们将创建以下 Ingress 资源 (opentracing-ingress.yaml):

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

name: opentracing-ingress

annotations:

nginx.org/location-snippets: |

opentracing_propagate_context;

spec:

rules:

- host: example.com

http:

paths:

- path: /

backend:

serviceName: app1-svc

servicePort: 80

在这里,我们在 Ingress Controller使用了nginx.org/location-snippets 注释启用跟踪上下文传播。代码段注释是将自定义代码添加到 Ingress Controller中最终 NGINX 配置的一种有效方法。

最后,我们通过运行以下命令来应用 Ingress 资源:

$ kubectl apply -f opentracing-ingress.yaml

验证应用 1 和应用 2 是否均正常运行:

$ kubectl get pods

NAME READY STATUS RESTARTS AGE

app1-68fd9db45c-szqpr 1/1 Running 0 53m

app2-67c7788789-lvbgw 1/1 Running 0 53m


跟踪请求

现在,我们只需通过 Ingress Controller向应用 1 发出请求,其中:

● IC_HTTP_PORT 是 Ingress 控制器 Pod 中的 HTTP 端口(默认为 80)

● IC_IP_ADDRESS 是 Ingress 控制器 Pod 的 IP 地址。如果使用 minikube,则采用 minikube IP 地址。

$ curl --resolve example.com:IC_HTTP_PORT:IC_IP_ADDRESS http://example.com:IC_HTTP_PORT/ --insecure

Success!


查看 trace

我们运行以下命令来访问 Jaeger 用户界面,其中 JAEGER_POD 是我们通过部署 Jaeger 跟踪器一体式模板所创建的 Pod 中的“类型/名称”值:

$ kubectl port-forward JAEGER_POD 16686:16686

每个请求都会创建一个新的 trace。您可在浏览器中在 http://localhost:16686 打开 Jaeger 用户界面去查看刚刚发出请求的 trace,在左栏 Service 字段中键入 nginx-egress,然后点击栏底部的 Find Traces 按钮。

点击搜索窗口右栏中的 nginx-ingress,选择 trace。在打开的窗口(下图)中,我们看到我们请求的三种 span:棕色代表 Ingress Controller,蓝色代表应用 1,黄色代表应用 2。

获取更多相关各个span的详细信息,包括 HTTP 状态代码、主机名、IP 地址和 Jaeger 版本, 请点击其span的按钮


结语

在 Kubernetes 中为您的服务启用 OpenTracing可支持您和您的团队及时了解应用运行的情况并快速排除故障。

此外,从 Ingress Controller Pod 开始对请求的跟踪有助于您全面地了解来自集群外部请求在通过每个服务时的情况。


已修改于2023-03-04 02:28
本作品系原创
创作不易,留下一份鼓励
NGINX官方账号

暂无个人介绍

关注



写下您的评论
发表评论
全部评论(0)

按点赞数排序

按时间排序

关于作者
NGINX官方账号
这家伙很懒还未留下介绍~
335
文章
21
问答
201
粉丝
相关文章
前言nginx系列之一:nginx入门nginx系列之二:配置文件解读nginx系列之三:日志配置nginx系列之四:web服务器nginx系列之五:负载均衡nginx系列之六:cache服务nginx系列之七:限流配置nginx系列之八:使用upsync模块实现负载均衡转自:在此感谢原博主的整理分享一、nginxreload的问题问题描述nginxreload是有一定损耗的,如果你使用的是长连接的话,那么当reloadnginx时长连接所有的worker进程会进行优雅退出,并当该worker进程上的所有连接都释放时,进程才真正退出。解决办法对于社区版nginx目前有三个选择方式:Tengine的Dyups模块。微博的Upsync+Consul实现动态负载均衡。OpenResty的balancer_by_lua(又拍云使用其开源的slardar(Consulbalancer_by_lua))。本文使用upsync模块来解决配置文件修改后,reloadnginx进程造成性能下降的问题。它的功能是拉取consul的后端server的列表,并更新Nginx的路由信
点赞 4
浏览 11.4k
使用配置:举例:pidlogs/nginx.pid; error_loglogs/nginx-main_error.logdebug; #DevelopmentMode #master_processoff; #daemonoff; worker_processes1; worker_rlimit_core500M; working_directory/tmp; debug_pointsabort; events{ worker_connections1024; #usekqueue;#MacOS useepoll;#Linux } http{ default_typeapplication/octet-stream; access_loglogs/nginx-http_access.log; er
点赞 1
浏览 4.2k
在Nginx的并发优化中,TIME-WAIT是服务器优化必然会谈到的一个话题,而我们常见的问题就是TIME-WAIT过多怎么处理?常见的解决方法就是:1、快速回收2、链接复用而这里有个误区就是到底TIME-WAIT要优化到什么程度,有的童鞋甚至看到TIME-WAIT就觉得需要优化,今天就是想聊一下这个话题要聊明白,还是要从原理来说起TIME-WAIT是TCP链接的一种状态,之前有写文章介绍过TCP的11中链接状态,有兴趣可以再去看下这张图整个展示了所有状态的转换过程,总共分为三个部分,上半部分是建立连接的过程,下面部分分成主动关闭和被动关闭的过程可以看到TIME_WAIT只在主动关闭的过程中出现,实际上TIME_WAIT是TCP为了解决复杂的网络问题提出的一种解决方案解决什么问题呢?看下面两个场景四次挥手中,A发FIN,B响应ACK,B再发FIN,A响应ACK实现连接的关闭。而如果A响应的ACK包丢失,B会以为A没有收到自己的关闭请求,然后会重试向A再发FIN包。如果没有TIME_WAIT状态,A不再保存这个连接的信息,收到一个不存在的连
点赞 3
浏览 9.1k