手摸手教你把Ingress Nginx集成进Skywalking

这篇具有很好参考价值的文章主要介绍了手摸手教你把Ingress Nginx集成进Skywalking。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景

在微服务大行其道的今天,如何观测众多微服务、快速理清服务间的依赖、如何对服务之间的调用性能进行衡量,成了摆在大家面前的难题。对此,Skywalking应运而生,它是托管在 Apache 基金会下的开源项目,旨在帮助开发者监控分布式程序的性能、了解各个服务的调用关系和运行情况。

Skywalking支持多种语言和框架,包含Java、Golang、Python等,功能强大、界面友好等特点使其迅速成为业界最流行的APM软件之一。然而在运用Skywalking的过程中,我们常常更关注服务之间的调用链路、性能数据,往往会忽略流量入口(网关)到服务之间的Trace串联,导致我们经常在网关层面观测到一个错误调用后,无法通过TraceID快速查看本次调用的链路,从而白白浪费宝贵的排障时间。

本文重点介绍如何将 Ingress Nginx 集成进 Skywalking,将其作为 Skywalking 的一个节点,并且在access log 中打印TraceID,从而在出现故障的时候,可以通过日志中的TraceID快速找到调用链路,达到快速故障定位的效果。

注:本文使用的 Kubernetes 版本是 1.24.15,Ingress Nginx controller 版本是 v1.8.1,Skywalking版本是9.2.0。

方案

在介绍方案之前,我们先了解一下相关的背景知识,用于更好的理解集成方案。

  1. Ingress Nginx Configmap:Ingress Nginx 的各种配置存放地,可以通过该Configmap配置logformat、所开启的插件等。
  2. Skywalking Nginx Lua:Skywalking 官方提供的 Lua 版本 lib,提供了一系列的操作,自己可以在Nginx的配置文件中编写Lua脚本,适时创建Span、结束Span,从而把 Nginx 当作Skywalking中的一个服务节点集成进Skywalking。
  3. Ingress Nginx 自定义插件:Lua脚本编写的插件,用于对 Ingress Nginx 做编程,想要使用插件必须要将插件放到 Ingress Controller 容器的 /etc/nginx/lua/plugins/插件名称 目录中,且需要在 Ingress Controller 的configmap中开启它。自定义插件支持以下几个钩子:
  • a. init_worker: 用于对Nginx Worker做一些初始化。
  • b. rewrite: 用于修改请求、更改标头、重定向、丢弃请求、进行身份验证等。
  • c. header_filter: 当接收到后端response header 时调用此函数,通常用来记录和修改后端的response header。
  • d. body_filter: 这是在收到后端response body 时调用的,一般用来记录response body。
  • e. log: 当请求处理完成并将响应传递给客户端时,会调用此函数。
  1. sw8:SkyWalking 跨进程传播的Header Key,它的格式是 1-TRACEID-SEGMENTID-3-PARENT_SERVICE-PARENT_INSTANCE-PARENT_ENDPOINT-IPPORT(其中TraceID、SpanID等都通过base64进行编码),我们可以通过此Header解析出对应的 TraceID。

了解了上述原理后,我们的方案就显而易见了,就是将 Skywalking Nginx Lua 集成进 Ingress Nginx中,并编写插件,在不同阶段执行相关操作:

  • a. 在 rewrite 阶段生成新Span并解析出TraceID将其放在新Header中(方便access log 打印)
  • b. 在 body_filter 阶段结束该Span
  • c. 在log阶段提交对应的数据到Skywalking服务端
  • d. 修改 Nginx log format,将存储 TraceID 的Header 打印出来

步骤

1. 集成Skywalking Nginx Lua进Ingress Nginx

Skywalking Nginx Lua 的核心是它的 lib 目录,里边包含了所有需要用到的函数操作,所以我们需要将该 lib 目录的内容放到 Ingress Nginx 的Pod 中,让我们编写的插件能够调用到它。具体我们可以将 lib 目录放到网盘中,然后通过 Volume 的形式挂载进去,也可以将 lib 的内容写入configmap,然后挂载Volume到Pod中。本文选择第二种方式,将 lib 的内容放到 configmap 中,然后挂载进去,虽说这种方式不够优雅,但好在不用依赖网盘。

我们先clone Skywalking Nginx Lua 这个库,然后将 lib 下的所有.lua文件打平放到同一个目录中

git clone https://github.com/apache/skywalking-nginx-lua.git
mkdir sk-lua-cm
cp skywalking-nginx-lua/lib/skywalking/*.lua sk-lua-cm/
cp skywalking-nginx-lua/lib/skywalking/dependencies/*.lua sk-lua-cm/
cp skywalking-nginx-lua/lib/resty/*.lua sk-lua-cm/

再通过 kubectl 命令将sk-lua-cm中的所有文件创建到一个configmap中,注意将 -n 后边的参数换成你自己Ingress Nginx 所在的 namespace。

kubectl create cm skywalking-nginx-lua-agent --from-file=./sk-lua-cm/ -n ingress-nginx

2. 编写Ingress Nginx 的插件

引入了 Skywalking 的 lib 后就可以编写对应的 Ingress Nginx 自定义插件了,代码比较简单,以下是代码详情(命名为main.lua)。

local _M = {}

function _M.init_worker()
  local metadata_buffer = ngx.shared.tracing_buffer
  require("skywalking.util").set_randomseed()
  local serviceName = os.getenv("SKY_SERVICE_NAME")
  if not serviceName then
    serviceName="ingress-nginx"
  end
  metadata_buffer:set('serviceName', serviceName)

  local serviceInstanceName = os.getenv("SKY_INSTANCE_NAME")
  if not serviceInstanceName then
    serviceName="ingress-nginx"
  end
  metadata_buffer:set('serviceInstanceName', serviceName)
  metadata_buffer:set('includeHostInEntrySpan', false)

  require("skywalking.client"):startBackendTimer(os.getenv("SKY_OAP_ADDR"))
  skywalking_tracer = require("skywalking.tracer")

end


function _M.rewrite()
  local upstreamName = ngx.var.proxy_upstream_name
  skywalking_tracer:start(upstreamName)
  if ngx.var.http_sw8 ~= "" then
    local sw8Str = ngx.var.http_sw8
    local sw8Item = require('skywalking.util').split(sw8Str, "-")
    if #sw8Item >= 2 then
      ngx.req.set_header("trace_id", ngx.decode_base64(sw8Item[2]))
    end
  end
end

function _M.body_filter()

  if ngx.arg[2] then
    skywalking_tracer:finish()
  end

end

function _M.log()
  skywalking_tracer:prepareForReport()
end

return _M

划重点:在上述代码中获取了几个环境变量,需要记住,后边需要用到。

  • i. SKY_SERVICE_NAME:Ingress Nginx 在 Skywalking 中的 Service 名称
  • ii. SKY_INSTANCE_NAME:Ingress Nginx 实例在 Skywalking 中的实例名称
  • iii. SKY_OAP_ADDR:Skywalking后端地址

编写好插件代码后就可以基于此创建configmap了,依然需要注意 -n 后边的namespace,需要改成你实际Ingress Nginx所在的 namespace。

kubectl create cm skywalking-lua-plug --from-file=main.lua -n ingress-nginx

3. 挂载相关 Lua 脚本进 Ingress Nginx Controller 的 Pod 中

修改 Ingress Nginx Controller 的 Deployment 配置,主要修改以下几点:

a. 环境变量

- name: SKY_OAP_ADDR
  value: http://skywalking-oap.skywalking.svc.cluster.local:12800
- name: SKY_SERVICE_NAME
  value: ingress-nginx
- name: SKY_INSTANCE_NAME
  value: ingress-nginx

b. volumes 声明

- name: sky-nginx-plugin
  configMap:
    name: skywalking-lua-plug
- name: skywalking-nginx-lua-agent
  configMap:
    name: skywalking-nginx-lua-agent

c. volumeMounts 声明

- mountPath: /etc/nginx/lua/plugins/skywalking/main.lua
  subPath: "main.lua"
  name: sky-nginx-plugin
- mountPath: /etc/nginx/lua/resty/http.lua
  subPath: "http.lua"
  name: skywalking-nginx-lua-agent
- mountPath: /etc/nginx/lua/tablepool.lua
  subPath: "tablepool.lua"
  name: skywalking-nginx-lua-agent
- mountPath: /etc/nginx/lua/resty/http_headers.lua
  subPath: "http_headers.lua"
  name: skywalking-nginx-lua-agent
- mountPath: /etc/nginx/lua/resty/jit-uuid.lua
  subPath: "jit-uuid.lua"
  name: skywalking-nginx-lua-agent
- mountPath: /etc/nginx/lua/skywalking/client.lua
  subPath: "client.lua"
  name: skywalking-nginx-lua-agent
- mountPath: /etc/nginx/lua/skywalking/constants.lua
  subPath: "constants.lua"
  name: skywalking-nginx-lua-agent
- mountPath: /etc/nginx/lua/skywalking/correlation_context.lua
  subPath: "correlation_context.lua"
  name: skywalking-nginx-lua-agent
- mountPath: /etc/nginx/lua/skywalking/dependencies/base64.lua
  subPath: "base64.lua"
  name: skywalking-nginx-lua-agent
- mountPath: /etc/nginx/lua/skywalking/management.lua
  subPath: "management.lua"
  name: skywalking-nginx-lua-agent
- mountPath: /etc/nginx/lua/skywalking/segment.lua
  subPath: "segment.lua"
  name: skywalking-nginx-lua-agent
- mountPath: /etc/nginx/lua/skywalking/segment_ref.lua
  subPath: "segment_ref.lua"
  name: skywalking-nginx-lua-agent
- mountPath: /etc/nginx/lua/skywalking/span.lua
  subPath: "span.lua"
  name: skywalking-nginx-lua-agent
- mountPath: /etc/nginx/lua/skywalking/span_layer.lua
  subPath: "span_layer.lua"
  name: skywalking-nginx-lua-agent
- mountPath: /etc/nginx/lua/skywalking/tracer.lua
  subPath: "tracer.lua"
  name: skywalking-nginx-lua-agent
- mountPath: /etc/nginx/lua/skywalking/tracing_context.lua
  subPath: "tracing_context.lua"
  name: skywalking-nginx-lua-agent
- mountPath: /etc/nginx/lua/skywalking/util.lua
  subPath: "util.lua"
  name: skywalking-nginx-lua-agent

4. 修改 Ingress Nginx Controller 所使用的configmap配置

plugins: "skywalking"
lua-shared-dicts: "tracing_buffer: 100m"
main-snippet: |
  env SKY_SERVICE_NAME;
  env SKY_INSTANCE_NAME;
  env SKY_OAP_ADDR;
log-format-upstream: |
  $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length $request_time [$proxy_upstream_name] [$proxy_alternative_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status $request_id $http_trace_id

该配置中配置了如下几个信息:

  • a. plugins:开启skywalking插件
  • b. lua-shared-dicts:声明 trace 使用的变量和大小
  • c. main-snippet:其中声明了需要使用到的环境变量,切记在插件中使用的环境变量必须放到这里来
  • d. log-format-upstream:log 格式,我们在这个里添加了一个 http_trace_id 这个header的打印(上一步解析出来的TraceID)

5. 重启 Pod 生效

把下列的 xxx 换成 Ingress Nginx Controller 的 Pod 名称

kubectl delete pod xxxx -n=ingress-nginx

效果展示

本节展示最终在Skywalking UI 上的展示效果。

  1. 可以在 Skywalking 的拓扑图中看到有一个 Ingress Nginx 的服务节点加入
  1. 在Trace查询页面可以看到有一个 Nginx 的 Span
  1. 如下是打印出来的TraceID

如何更好使用Trace?

通过上述介绍,我们已经把 Ingress Nginx 集成进了Skywalking,接下来介绍一下如何更好的使用Trace数据来快速定位故障。

数据建设

  1. 将Skywalking数据源接入Flashcat,接入的方法很简单,只需要填写对应的地址、账号、密码,然后起一个名字即可 

  2. 采集 Ingress Nginx 日志到 kafka 中,这里可以使用 categraf 的 log 采集器

  3. 将日志接入 Flashcat 的日志分析子系统生成报表,在这张报表中可以看到对应的域名、接口、流量、成功率等(当然,这些维度都可以自定义),在创建报表的时候设置好日志中哪个字段是TraceID字段。

  1. 通过日志报表生成灭火图(IT系统健康度一览表),例如下图就是典型的电商系统核心API健康度一览表。
  1. 通过数据库、Metrics、日志等不同来源建立北极星指标(核心业务指标),例如:电商系统的下单量、支付量等

串联打通

通过Flashcat的串联能力,建立北极星和灭火图的串联。

故障定位路径

当建设好对应的指标和关联后,就可以开启我们的故障定位之旅了。

  1. 当北极星指标故障(核心业务受损)时,北极星页面上对应的指标会飘红且发送报警,例如下图中的商品实时下单量掉底了,该业务卡片会飘红
  1. 此时我们点击曲线上掉底时刻的数据点,可以打开关联的灭火图,一眼就可以看到是订单子系统在飘红(可能发生了故障)
  1. 我们点击飘红的灭火图路径,可以下钻到具体的卡片组中去
  1. 然后可以看到灭火图卡片组中的订单更新DB接口成功率为0,我们点击旁边的详情可以打开对应的详情曲线(通过上一步中的日志报表生成)
  1. 通过详情可以看到,这个时候的成功率已经掉底了,那么我们同样可以点击曲线上掉底的时间点打开日志详情
  1. 在这个页面中,我们可以直接查看异常日志的日志详情,也可以点击右侧的 trace 按钮打开该调用的Trace链路

通过Trace链路可以看到Redis的端口不通导致更新失败了,这个时候我们就需要去排查依赖的Redis是否正常了。

当然,以上只是Flashcat在整合可观测性三大支柱(Metrics、Log、Trace)方面的一个小例子,如果您对Flashcat这套产品感兴趣,可以随时与我们交流:https://flashcat.cloud/contact/。文章来源地址https://www.toymoban.com/news/detail-856348.html

到了这里,关于手摸手教你把Ingress Nginx集成进Skywalking的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 手摸手2-springboot编写基础的增删改查

    创建controller层 实现 test 表中的添加、修改、删除及列表查询接口(未分页) 添加service层接口 service层实现 添加mapper层 mapper层对应的sql 添加扫描注解,对应sql文件的目录

    2024年02月10日
    浏览(47)
  • 不用魔法,快速、手摸手上线Midjourney!【附源码】【示例】

    首先来一波感谢: 感谢laf提供赞助,目前可以免费使用Midjourney进行开发和测试。 感谢白夜、米开朗基杨@sealos.io的耐心解答,让我对laf有了更多的使用与了解。 什么是laf?来了解下。 文末有【示例】 废话不多说,进入正题。 laf在做一个活动,可以使用快速上手Midjourney《人

    2024年02月05日
    浏览(48)
  • 手摸手带你 在Windows系统中安装Istio

    通过负载均衡、服务间的身份验证、监控等方法,Istio 可以轻松地创建一个已经部署了服务的网络,而服务的代码只需很少更改甚至无需更改。 通过在整个环境中部署一个特殊的 sidecar 代理为服务添加 Istio 的支持,而代理会拦截微服务之间的所有网络通信,然后使用其控制

    2024年02月06日
    浏览(50)
  • 手摸手接入Github实现Oauth2第三方登录

    最近在学习oauth2授权登录流程,oauth2简单来说就是接入第三方应用(qq、微信、github、gitee等),不用在本站登录,而是去请求第三方应用的用户信息完成登录。 下面就一起来看一下如何接入github实现第三方登录 首先,我们需要在github中添加OAuth App,登录你的github(如果还有

    2024年02月04日
    浏览(69)
  • 泰裤辣!!!手摸手教学,如何训练一个你的专属AI歌姬~

    最近在做AIGC的项目,不过是与图片相关的,现在的模型效果可比前几年图片替换效果好多了。之前尝试过用 faceswap 工具来进行人脸替换的,具体可以参看下我之前的这篇文章:https://blog.csdn.net/sinat_26918145/article/details/79591717   现代的模型对于图生图的支持效果已经非常好了,

    2024年02月06日
    浏览(58)
  • 使用 Burp Suite 暴力破解密码 撞库攻击 从0到1手摸手教学

    一个学习的过程 增加自己网络安全知识 切勿用于违法用途 设置密码尽量使用6位以上并规避简单数字组合、加强对同一ip的频繁访问次数限制、设置人机验证减小撞库攻击的危害 本地环境 kali 2022 Burp Suite FireFox 靶机环境 一台服务器 CentOS 7 宝塔面板 一个域名(你不会没有吧)

    2024年02月09日
    浏览(41)
  • 【AI帮我写代码,上班摸鱼不是梦】手摸手图解CodeWhisperer的安装使用

    除了借助ChatGPT通过问答的方式生成代码,也可以通过IDEA插件在写代码是直接帮助我们生成代码。 目前,IDEA插件有CodeGeeX、CodeWhisperer、Copilot。其中,CodeGeeX和CodeWhisperer是完全免费的,Copilot是收费的,每月10美元。 下面我们来了解CodeWhisperer的安装和使用,如果你还想了解其他

    2024年02月11日
    浏览(46)
  • 教你把python的代码变成中文

    是不是好看多了? 因为我们想把python的代码变成中文,但是又不可能真的去改python程序本体,所以我在这里使用的方法是自己搭建一个第三方库,然后再同路径下创建一个py文件,这样就可以导入我们刚才的库了。正因如此,第一行的import是真的改不了了。 那么,这个库该怎

    2024年02月11日
    浏览(26)
  • MP4转AVI转AMV教程:教你把B站视频导入你的MP3MP4随身听播放器

    学校不给带手机?去到学校就不能看视频了?我该怎么办? 别慌!UP主教你如何把你喜欢的视频导入到自己的随身听上! 前言:想必很多人都买过或者手上都有MP3/MP4播放器,在学校查手机变态严的中学时代,这个或许是唯一可以替代手机的慰藉了吧……每天晚上听着歌度过

    2023年04月25日
    浏览(44)
  • k8s 对外服务之 ingress|ingress的对外暴露方式|ingress http,https代理|ingress nginx的认证,nginx重写

    service的作用体现在两个方面,对集群内部,它不断跟踪pod的变化,更新endpoint中对应pod的对象,提供了ip不断变化的pod的服务发现机制;对集群外部,他类似负载均衡器,可以在集群内外部对pod进行访问。 在Kubernetes中,Pod的IP地址和service的ClusterIP仅可以在集群网络内部使用,

    2024年02月10日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包