采用 NGINX Ingress Controller for Kubernetes 支持 OpenTracing?
116 次浏览
发表于 2021-08-23 11:04

近年来,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 Controlleredge 版本中可用。


将 OpenTracing 构建到 NGINX Ingress Controller镜像中

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

Ingress ControllerGitHub 存储库中,我们为 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 开始请求的跟踪有助于您全面了解来自集群外部请求通过每个服务时的情况。


发表评论
发表者

NGINX官方账号

NGINX官方账号

  • 55

    文章

  • 2

    关注

  • 125

    粉丝

活动推荐
版权所有©F5 Networks,Inc.保留所有权利。京ICP备16013763号-5