使用SkyWalking监控Nginx链路信息

使用SkyWalking监控Nginx链路信息

1、前言

本篇只记录如何安装及配置Nginx LUA Agent展开,详细的记录了nginx lua模块的安装过程及如配置Nginx LUA Agent,并全程使用docker+k8s进行部署,SkyWalking的服务端也采用k8s部署,数据存储使用7.10的es完成,ES连接方式为HTTPS,具体踩坑过程后续进行记录;

2、SkyWalking简介与架构

官方手册:SkyWalking Overview

  • SkyWalking:一个开放源代码的可观察性平台,用于收集,分析,聚合和可视化来自服务和云本机基础结构的数据。SkyWalking提供了一种简便的方法来维护您的分布式系统的清晰视图,即使在整个云中也是如此。它是一个现代的APM,专门为基于云的基于容器的分布式系统而设计,如下图:
    image_1evop0psr14426t59l814ub3es9.png-242.1kB

从逻辑上讲,SkyWalking分为四个部分:探针,服务后端,存储和UI,如下图:

  • 探针:收集数据并重新格式化以符合SkyWalking的要求(不同的探针支持不同的来源);
  • 服务后端:支持数据聚合,分析和流处理,涵盖跟踪,指标和日志;
  • 存储:支持ElasticSearch,H2,MySQL,TiDB,InfluxDB存储SkyWalking数据
  • UI:是一个高度可定制的基于Web的界面,允许SkyWalking最终用户可视化和管理SkyWalking数据。
    image_1evop2dcg1eui14ki6j81s82q4dm.png-272.8kB

3、为什么要使用SkyWalking?

  • SkyWalking提供了用于在许多不同情况下观察和监视分布式系统的解决方案。首先,与传统方法一样,SkyWalking为服务提供自动仪器代理,例如Java,C#,Node.js,Go,PHP和Nginx LUA。在多语言,持续部署的环境中,云本机基础架构变得越来越强大,但也越来越复杂。SkyWalking的服务网格接收器使SkyWalking能够从Istio / Envoy和Linkerd等服务网格框架接收遥测数据,从而使用户能够了解整个分布式系统,
  • SkyWalking使用服务名称,服务实例,端点提供可观察性功能,详细含义如下:
    • 服务名称:表示一组工作负载,SkyWalking也可以使用您在Istio等平台中定义的名称;
    • 服务实例:服务组中的每个单独工作负载都称为实例,像pods在Kubernetes中的定义一样;
    • 端点:服务中用于传入请求的路径,例如HTTP URI路径或gRPC服务类+方法签名;

4、部署环境介绍

平台 IP NGINX版本 Agent版本 SkyWalking版本
CentOS Linux release 7.7.1908 192.168.6.10 1.12.1 skywalking-nginx-lua-0.3.0 8.1.0

5、编译NGINX

5.1、安装luajit编译器

1
2
3
4
5
6
7
8
9
10
#下载luajit编译器
wget http://luajit.org/download/LuaJIT-2.1.0-beta3.tar.gz
#解压源码包
tar xzvf LuaJIT-2.1.0-beta3.tar.gz
cd LuaJIT-2.1.0-beta3
#安装路径:/usr/local/luajit
make PREFIX=/usr/local/luajit
make install PREFIX=/usr/local/luajit
#构建库文件软连接
ln -s /usr/local/luajit/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2

5.2、增加环境变量

1
2
3
4
#增加LUAJIT环境变量
echo 'export LUAJIT_LIB=/usr/local/luajit/lib' >> /etc/profile
echo 'export LUAJIT_INC=/usr/local/luajit/include/luajit-2.1' >> /etc/profile
source /etc/profile

5.3、安装nginx lua模块

1
2
3
4
wget https://github.com/simpl/ngx_devel_kit/archive/v0.3.0.tar.gz -O ngx_devel_kit-0.3.0.tar.gz
wget https://github.com/openresty/lua-nginx-module/archive/v0.10.14.tar.gz -O lua-nginx-module-0.10.14.tar.gz
tar xzvf ngx_devel_kit-0.3.0.tar.gz
tar xzvf lua-nginx-module-0.10.14.tar.gz

5.4、Bulid Nginx

1
2
#nginx编译参数如下(这里包含了其他模块,具体各个模块的安装这里不记录):
./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_stub_status_module --with-http_ssl_module --without-mail_pop3_module --without-mail_smtp_module --without-mail_imap_module --with-http_realip_module --add-module=/soft/naxsi-master/naxsi_src --add-module=/soft/nginx-limit-upstream-master --add-module=/soft/nginx-upstream-jvm-route-master --add-module=/soft/ngx_http_proxy_connect_module-0.0.2 --add-module=/soft/ngx_devel_kit-0.3.0 --add-module=/soft/lua-nginx-module-0.10.14 --with-http_v2_module && make && make install

5.5、Test Nginx Lua

1
2
3
4
5
6
7
8
9
10
11
12
13
#在nginx.conf,server段中增加如下配置
location /lua {
default_type text/html;
content_by_lua_block {
ngx.say("Hello Lua!")
}
}
#重载nginx
/usr/loca/nginx/sbin/nginx -s reload
#访问测试
curl http://127.0.0.1/lua
#如下返回表示lua安装正常
Hello Lua!

5.5、下载skywalking lua脚本

1
2
wget https://github.com/apache/skywalking-nginx-lua/archive/v0.3.0.tar.gz
tar xzvf v0.3.0.tar.gz -C /usr/local/

5.6、修改nginx.conf配置文件

提示:配置项(lua_package_path、metadata_buffer:set、startBackendTimer)要根据实际部署情况进行调整;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#user  www;
worker_processes 2;
error_log /usr/local/nginx/logs/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /usr/local/nginx/conf/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 /usr/local/nginx/logs/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /usr/local/nginx/conf/conf.d/*.conf;
############################################################################################
#LUA脚本存放路径
lua_package_path "/usr/local/skywalking-nginx-lua-0.3.0/lib/?.lua;;";
lua_shared_dict tracing_buffer 100m;
init_worker_by_lua_block {
local metadata_buffer = ngx.shared.tracing_buffer
#服务名称
metadata_buffer:set('serviceName', 'szzt_nginx112')
#实例名称
metadata_buffer:set('serviceInstanceName', 'centos2009-858f6fcf97-m69tp')
#skywalking后端地址
require("skywalking.client"):startBackendTimer("http://10.244.1.19:12800")
}

server {
listen 60000;
#lua_code_cache off;
location /ingress {
default_type text/html;
rewrite_by_lua_block {
require("skywalking.tracer"):start("upstream service")
}
proxy_pass http://127.0.0.1:60000/tier2/lb;
body_filter_by_lua_block {
if ngx.arg[2] then
require("skywalking.tracer"):finish()
end
}
log_by_lua_block {
require("skywalking.tracer"):prepareForReport()
}
}

location /tier2/lb {
default_type text/html;

rewrite_by_lua_block {
require("skywalking.tracer"):start("backend service")
}

proxy_pass http://127.0.0.1:60000/backend;

body_filter_by_lua_block {
if ngx.arg[2] then
require("skywalking.tracer"):finish()
end
}

log_by_lua_block {
require("skywalking.tracer"):prepareForReport()
}
}

# ------------------------------------------------------
# -- Mock backend business service as the upsteeam
# ------------------------------------------------------
location /backend {
default_type text/html;
content_by_lua_block {
ngx.say("<p>Backend service for testing only.</p>")
ngx.say("<p>Backend sw8 received headers: " .. ngx.req.get_headers()["sw8"] .. "</p>")
}
}


# ------------------------------------------------------
# -- Mock OAP server to provide register and trace collection
# ------------------------------------------------------
location /v3/management/reportProperties {
default_type text/html;
lua_need_request_body on;

content_by_lua_block {
local cjson = require('cjson')

ngx.log(ngx.DEBUG, 'Instance report request = ', ngx.req.get_body_data())

local reportInfo = {}
ngx.say(cjson.encode(reportInfo))
}
}

location /v3/management/keepAlive {
default_type text/html;
lua_need_request_body on;

content_by_lua_block {
local cjson = require('cjson')
ngx.log(ngx.DEBUG, 'KeepAlive request = ', ngx.req.get_body_data())

local keepAliveInfo = {}
ngx.say(cjson.encode(keepAliveInfo))
}
}

location /v3/segments {
default_type text/html;
lua_need_request_body on;

content_by_lua_block {
local cjson = require('cjson')
ngx.log(ngx.DEBUG, 'Received segment = ', ngx.req.get_body_data())
}
}
}
}

5.7、重载配置文件

1
2
3
4
5
6
7
#重载nginx
/usr/loca/nginx/sbin/nginx -s reload
#访问测试
curl http://127.0.0.1:60000/ingress
#如下返回表示后端服务部署正常,登录UI查看链路数据
<p>Backend service for testing only.</p>
<p>Backend sw8 received headers: 1-Y2JiMjk3YzAtMTRhOS00NmJjLWFkOTEtMWQwZWY5YjQyZGY5-NDY1YTc4YWQtOTNjYy00MzJlLWE4MzYtOTgyNGQ0OTUwNmQ2-1-c3p6dF9uZ2lueDExMg==-Y2VudG9zMjAwOS04NThmNmZjZjk3LW02OXRw-L3RpZXIyL2xi-YmFja2VuZCBzZXJ2aWNl</p>

5.8、进行简单压测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ab -c 100 -n 1000 http://127.0.0.1:60000/ingress
Server Software: nginx/1.12.1
Server Hostname: 127.0.0.1
Server Port: 60000

Document Path: /ingress
Document Length: 272 bytes

Concurrency Level: 100
Time taken for tests: 0.423 seconds
Complete requests: 1000
Failed requests: 0
Write errors: 0
Total transferred: 415000 bytes
HTML transferred: 272000 bytes
Requests per second: 2363.95 [#/sec] (mean)
Time per request: 42.302 [ms] (mean)
Time per request: 0.423 [ms] (mean, across all concurrent requests)
Transfer rate: 958.05 [Kbytes/sec] received

5.7、登录skywalking UI进行查看

提示:实例名可看做是一个容器,一台服务器,一个OS进程,但必须唯一,用于区分和标识,具体UI使用详解,请阅读官方手册:Visualization

image_1evovi773c331r2v1nke1v3o1jpn16.png-136kB

6、使用K8S部署NGINX

提示:使用k8s部署基于skywalking的nginx,存在如下几个关键点,1、必须保证服务实例唯一,服务名称根据项目来定 2、skywalking的地址使用coredns的域名出现无法识别,必须填写clusterIP 3、nginx.conf配置文件是不支持容器变量传递,则放弃使用configmap进行存储和挂载,使用envsubst实现

6.1、准备构建Docker镜像的所需资源文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@centos2009-858f6fcf97-m69tp nginx112]# ll
total 5820
-rw-r--r-- 1 root root 152 Mar 2 10:13 docker-entrypoint.sh -- 容器入口文件
-rw-r--r-- 1 root root 642 Mar 2 10:13 Dockerfile -- 镜像构建文件
-rw-r--r-- 1 root root 885212 Mar 2 09:55 luajit2.1.0.tar.gz -- 将编译好的luajit打包
-rw-r--r-- 1 root root 5012833 Mar 2 09:51 nginx112_skywalking.tar.gz -- 将编译并配置好的nginx打包
-rw-r--r-- 1 root root 45535 Mar 2 09:52 skywalking-nginx-lua-0.3.0.tar.gz -- skywalking lua脚本打包
#镜像构建文件内容
[root@centos2009-858f6fcf97-m69tp nginx112]# cat Dockerfile
# Version 0.0.1
FROM 192.168.6.10/szzt_production/centos:centos7.9.2009
MAINTAINER lisir
ENV LUAJIT_LIB /usr/local/luajit/lib
ENV LUAJIT_INC /usr/local/luajit/include/luajit-2.1
ENV PATH /usr/local/nginx/sbin:$PATH
ADD ./nginx112_skywalking.tar.gz /usr/local/
ADD ./luajit2.1.0.tar.gz /usr/local/
ADD ./skywalking-nginx-lua-0.3.0.tar.gz /usr/local/
COPY ./docker-entrypoint.sh /
RUN useradd -s /sbin/nologin -M www && ln -sf /dev/stdout /usr/local/nginx/logs/access.log && ln -sf /dev/stderr /usr/local/nginx/logs/error.log && chmod 777 /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
WORKDIR /usr/local/nginx
EXPOSE 80
CMD ["nginx","-g","daemon off;"]
#重要:为保证实例名唯一,需提前制作好使nginx.conf.template文件,用envsubst将nginx.conf.template中的内容覆盖nginx.conf文件内容,实现读取环境变量
[root@centos2009-858f6fcf97-m69tp nginx112]# cat docker-entrypoint.sh
#!/usr/bin/env sh
set -eu
envsubst '${SVC_NAME} ${HOSTNAME}' < /usr/local/nginx/conf/nginx.conf.template > /usr/local/nginx/conf/nginx.conf
exec "$@"

6.2、构建基于skywalking的nginx生产镜像

1
2
3
4
#构建过程直接-t打上标签
docker image build -t 192.168.6.33/szzt_production/nginx112:latest .
#上传至私有仓库
docker push 192.168.6.33/szzt_production/nginx112:latest

6.3、部署一个nginx容器进行测试

1
2
3
4
5
6
#用制作好的镜像,create的一个容器
docker container run -d --name nginx-lisir -p 83:60000 -e SVC_NAME=szzt-lisir-nginx -e SW_ADDR=http://10.244.1.19:12800 --restart always 192.168.6.33/szzt_production/nginx112:latest
#访问测试
curl http://127.0.0.1:83/ingress
<p>Backend service for testing only.</p>
<p>Backend sw8 received headers: 1-Y2JiMjk3YzAtMTRhOS00NmJjLWFkOTEtMWQwZWY5YjQyZGY5-Y2JiMjk3YzAtMTRhOS00NmJjLWFkOTEtMWQwZWY5YjQyZGY5-1-c3p6dC1saXNpci1uZ2lueA==-MGUyMTRlOTI3MGU0-L3RpZXIyL2xi-YmFja2VuZCBzZXJ2aWNl</p>

6.4、使用k8s部署

提示:k8s配置文件篇幅过长这里不展示,按照如下指令操作,可完成PVC存储、configmap配置中心、集群暴露端口svc及pod相关等资源的创建;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#按照文件数据顺序,依次使用Kubectl apply -f xxx.yml,即可完成nginx集群部署,重点对6号文件进行调整,里面需增加SVC_NAME、SW_ADDR的ENV,用于配置文件变量替换
[root@DEVOPSSRV01 nginx_deployment]# ll
total 28
-rw-r--r-- 1 root root 292 Jan 7 14:44 1.nginx_pv.yml
-rw-r--r-- 1 root root 217 Jan 7 14:44 2.nginx_pvc_web1.yml
-rw-r--r-- 1 root root 4653 Mar 2 11:04 3.nginx-config.yml
-rw-r--r-- 1 root root 519 Mar 2 11:04 4.www-config.yml
-rw-r--r-- 1 root root 354 Mar 2 11:39 5.nginx_svc.yml
-rw-r--r-- 1 root root 1386 Mar 2 11:13 6.nginx_deployment_v3.yml
#使用命令查看创建后的资源运行状态
[root@DEVOPSSRV01 nginx_deployment]# kubectl get pod,svc -n nginx-production -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/nginx112-59fcbcbccc-5d7ms 1/1 Running 0 5h32m 10.244.1.24 tssrv02.novalocal <none> <none>
pod/nginx112-59fcbcbccc-mfglm 1/1 Running 0 5h32m 10.244.2.195 dbsrv01.novalocal <none> <none>

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/nginx-svc NodePort 10.98.3.73 <none> 60000:30002/TCP,80:30006/TCP 5h36m app=web_server

6.5、登录k8s dashboard查看资源情况

  • pods资源
    image_1evovvggs1ujt6vv1js1e7rpgf1j.png-138.9kB
  • configmaps资源
    image_1evp244544vnfr6re01efg1qdum.png-126.5kB

6.6、登录skywalking UI查看资源情况

  • 可用简单的压测命令进行测试后,在登录查看,在k8s上创建了几个POD,这里应当看到对应的几个实例
    image_1evp3e9m4ism1fr6v8cvhtl8b13.png-137.4kB

7、打完收工

-------------本文结束感谢您的阅读-------------
LiGuanCheng wechat
如有问题,请与我微信交流或通过右下角“daovoice”与我联系~。
请我喝一杯咖啡~