本文介绍如何使用 OpenTelemetry 对 Nginx 进行链路追踪。 Nginx 是一个高性能、轻量级的开源 Web 服务器和反向代理服务器,支持通过模块以扩展其功能。Nginx OTel 模块支持采集 Nginx 的调用链并通过 OpenTelemetry Collector 转发上报至可观测链路 OpenTelemetry 版。
使用限制
Nginx OTel 模块目前仅支持 gRPC 方式上报,不支持 HTTP 方式上报。
Nginx OTel 模块暂不支持设置 gRPC 鉴权 Token,因此您需要部署 OpenTelemetry Collector。将 Nginx OTel 采集到的 Nginx 调用链通过 OpenTelemetry Collector 转发上报至可观测链路 OpenTelemetry 版。详细步骤,请参见三、部署 OpenTelemetry Collector。
前提条件
接入步骤
一、下载 Nginx OTel 模块
Alibaba Cloud Linux、RedHat、RHEL 及其衍生版本
sudo yum install nginx-module-otel
Debian、Ubuntu 及其衍生版本
sudo apt install nginx-module-otel
二、启用 Nginx OTel 模块
若要为 Nginx 启用链路追踪,您需要在 Nginx 主配置文件/etc/nginx/nginx.conf
中加载 OTel 模块并添加配置项。关于 OTel 模块的更多参数配置信息,请参见ngx_otel_module 模块文档。
全局配置:为所有 HTTP 请求开启链路追踪。
说明请替换配置中的两个变量:
${OTEL_COLLECTOR_GRPC_RECEIVER_ENDPOINT}
:OpenTelemetry Collector gRPC 上报点。此上报点为您部署的 OpenTelemetry Collector 的 gRPC 上报点,例如localhost:4317
,而不是前提条件中获取的可观测链路 OpenTelemetry 版的接入点。${SERVICE_NAME
:应用名称。此名称将会作为 Nginx 的应用名称在可观测链路 OpenTelemetry 版控制台中展示。
load_module modules/ngx_otel_module.so; # 加载 ngx_otel_module ... http { ... otel_exporter { endpoint ${OTEL_COLLECTOR_GRPC_RECEIVER_ENDPOINT}; # OpenTelemetry Collector 的上报地址,例如 localhost:4317 } otel_trace on; # 开启链路追踪 otel_service_name ${SERVICE_NAME} # 应用名 otel_trace_context inject; # 向下游服务注入Trace上下文 ... }
单个 Location 配置:为单个 Location 开启链路追踪。
说明请替换配置中的两个变量:
${OTEL_COLLECTOR_GRPC_RECEIVER_ENDPOINT}
:OpenTelemetry Collector gRPC 上报点。此上报点为您部署的 OpenTelemetry Collector 的 gRPC 上报点,例如localhost:4317
,而不是前提条件中获取的可观测链路 OpenTelemetry 版的接入点。${SERVICE_NAME
:应用名称。此名称将会作为 Nginx 的应用名称在可观测链路 OpenTelemetry 版控制台中展示。
load_module modules/ngx_otel_module.so; # 加载 ngx_otel_module ... http { otel_exporter { endpoint ${OTEL_COLLECTOR_GRPC_RECEIVER_ENDPOINT}; # OpenTelemetry Collector 的上报地址,例如 localhost:4317 } server { listen 127.0.0.1:80; location /hello { otel_trace on; # 只为 127.0.0.1:80/hello 开启链路追踪 otel_service_name ${SERVICE_NAME} # 应用名 otel_trace_context inject; # 向下游服务注入Trace上下文 ... } } }
三、部署 OpenTelemetry Collector
下文以 Docker 方式为例,介绍如何部署 OpenTelemetry Collector。更多部署方式,请参见下载并部署OpenTelemetry Collector。
创建
opentelemetry-config.yaml
文件,并将下面的内容拷贝至文件。该文件用于定义和配置OpenTelemetry Collector的行为和功能,包括如何接收、处理和导出数据。
说明请将
${GRPC_ENDPOINT}
和${GRPC_ENDPOINT_TOKEN}
替换为前提条件中获取的 gRPC 接入点和鉴权 Token。receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 exporters: otlp: endpoint: ${GRPC_ENDPOINT} tls: insecure: true headers: "Authentication": "${GRPC_ENDPOINT_TOKEN}" processors: batch: service: pipelines: traces: receivers: [otlp] processors: [batch] exporters: [otlp]
启动 OpenTelemetry Collector。
docker run -v $(pwd)/opentelemetry-config.yaml:/etc/otelcol-contrib/config.yaml otel/opentelemetry-collector-contrib:0.105.0
四、查看 Nginx 调用链
完成以上配置并重启 Nginx 后,您可向 Nginx 发送请求,以生成调用链。然后登录可观测链路 OpenTelemetry 版控制台,查看由 OpenTelemetry 生成的 Nginx 调用链。
在应用列表页面查看 Nginx 应用。
在调用链分析页面打开 Nginx 的调用链,查看请求耗时、客户端 IP、 HTTP 状态码等信息。如果您的后端服务也接入了可观测链路 OpenTelemetry 版,您将会看到串联在一起的 Nginx 与后端服务调用链。
实践教程
接下来将通过案例演示如何采集 Nginx 及后端应用的调用链,并上报至可观测链路 OpenTelemetry 版。
一、准备工作
确认已安装 Git、Docker 和 Docker Compose。
二、项目结构
nginx-otel-demo
│
├── docker-compose.yml # Docker Compose 配置文件
│
├── nginx_conf/ # nginx 配置文件
│ ├── default.conf
│ └── nginx.conf
│
├── otel_conf/ # OpenTelemetry Collector 配置文件
│ └── config.yaml
│
└── backend/ # Node.js 后端服务
├── Dockerfile
├── main.js
├── package.json
└── package-lock.json
创建文件夹:
mkdir nginx-otel-demo && cd nginx-otel-demo
mkdir -p nginx_conf otel_conf backend
三、创建 Nginx 配置
创建 Nginx 主配置文件
nginx.conf
。cat << 'EOF' > nginx_conf/nginx.conf load_module modules/ngx_otel_module.so; user nginx; worker_processes auto; error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; otel_exporter { endpoint otel-collector:4317; } otel_trace on; otel_trace_context inject; otel_service_name nginx; include /etc/nginx/conf.d/*.conf; } EOF
创建 Nginx 配置文件
default.conf
。cat << 'EOF' > nginx_conf/default.conf server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; } # 在这里添加 location /hello { proxy_pass http://backend-api:7001/hello; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } EOF
四、创建 OpenTelemetry Collector 配置
创建 OpenTelemetry Collector 配置文件,该配置文件定义了数据如何被接收、处理和上报。
请将${GRPC_ENDPOINT}
和${GRPC_ENDPOINT_TOKEN}
替换为前提条件中获取的 gRPC 接入点和鉴权 Token。
cat << 'EOF' > otel_conf/config.yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
exporters:
otlp:
endpoint: ${GRPC_ENDPOINT}
tls:
insecure: true
headers:
"Authentication": "${GRPC_ENDPOINT_TOKEN}"
processors:
batch:
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
EOF
五、创建后端服务(Node.js)
创建 package.json 文件。文件描述了项目的配置信息,包括项目名称、版本、依赖项等。
cat << 'EOF' > backend/package.json { "name": "backend", "version": "1.0.0", "main": "index.js", "scripts": {}, "keywords": [], "author": "", "license": "ISC", "description": "", "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/auto-instrumentations-node": "^0.52.0", "axios": "^1.7.7", "express": "^4.21.1" } } EOF
创建 main.js 文件,包含一个基本的 Express 框架 Web 应用程序。
cat << 'EOF' > backend/main.js "use strict"; const axios = require("axios").default; const express = require("express"); const app = express(); app.get("/", async (req, res) => { const result = await axios.get("http://localhost:7001/hello"); return res.status(201).send(result.data); }); app.get("/hello", async (req, res) => { console.log("hello world!") res.json({ code: 200, msg: "success" }); }); app.use(express.json()); app.listen(7001, () => { console.log("Listening on http://localhost:7001"); }); EOF
创建 Dockerfile 文件。
cat << 'EOF' > backend/Dockerfile FROM node:20.16.0 WORKDIR /app COPY package*.json ./ RUN npm install COPY . . ENV OTEL_TRACES_EXPORTER="otlp" ENV OTEL_LOGS_EXPORTER=none ENV OTEL_METRICS_EXPORTER=none ENV OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=grpc ENV OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="http://otel-collector:4317" ENV OTEL_NODE_RESOURCE_DETECTORS="env,host,os" ENV OTEL_SERVICE_NAME="ot-nodejs-demo" ENV NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register" EXPOSE 7001 CMD ["node", "main.js"] EOF
六、创建 Docker Compose 文件
该文件定义了一个多容器应用程序的配置,包括 Nginx 反向代理、OpenTelemetry Collector 和 Node.js 后端服务,以及它们之间的网络连接和端口映射。
cat << 'EOF' > docker-compose.yml
version: "3"
services:
nginx:
image: nginx:1.27.2-alpine-otel # 默认包含 opentelemetry 模块的 nginx 镜像
volumes:
- ./nginx_conf/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx_conf/default.conf:/etc/nginx/conf.d/default.conf:ro
ports:
- "80:80"
networks:
- nginx-otel-demo
otel-collector:
image: otel/opentelemetry-collector-contrib:latest
volumes:
- ./otel_conf/config.yaml:/etc/otelcol-contrib/config.yaml # 挂载 OpenTelemetry Collector 配置文件
ports:
- "4317:4317" # OTLP gRPC receiver
networks:
- nginx-otel-demo
backend-api:
build:
context: ./backend
dockerfile: Dockerfile
environment:
- NODE_ENV=production
ports:
- "7001:7001"
networks:
- nginx-otel-demo
networks:
nginx-otel-demo:
driver: bridge
EOF
七、启动服务
在 nginx-otel-demo 目录中执行以下命令。
docker compose up -d
预期输出:
访问应用。
curl http://localhost:80/hello
预期输出:
{"code":200,"msg":"success"}
登录可观测链路 OpenTelemetry 版控制台查看 Nginx 及后端服务的调用链。
在本例中,Nginx 在应用列表页面的名称为 nginx,后端应用名称为 ot-nodejs-demo。
常见问题
在 Nginx 配置文件中添加 Nginx OTel 模块配置后,Nginx 启动失败。
请使用
nginx -t
命令检查 Nginx 配置是否正确,或查看 Nginx 日志中的错误信息。sudo tail -n 50 /var/log/nginx/error.log
启用 Nginx OTel 模块后,在可观测链路 OpenTelemetry 版控制台没有看到 Nginx 的调用链。
请检查 Nginx 配置中 otel_exporter.endpoint 是否配置正确。该地址由 OpenTelemetry Collector 地址以及 gRPC 接收器端口组成,例如
localhost:4317
。可通过查看 Nginx 日志确认是否配置正确,当出现如下报错时,说明 otel_exporter.endpoint 未配置正确。Nginx 的调用链无法与其他应用串联。
请确保 Nginx 配置中添加了
otel_trace_context inject;
,并确认其他应用使用的链路透传协议与 Nginx 的透传协议是否相同。Nginx OTel 模块使用 OpenTelemetry W3C 作为透传协议,这需要其他应用也要使用 OpenTelemetry W3C 透传协议才能串联。Nginx OTel 插件模块是否会对 Nginx 的性能产生影响?
Nginx OTel 插件模块为 Nginx 原生模块,官方提示该模块对 Nginx 性能的影响限制在10-15%。详细信息,请参见NGINX Native OpenTelemetry (OTel) Module。