Ingress-nginx工作原理和实践

本文涉及的产品
Elasticsearch Serverless通用抵扣包,测试体验金 200元
日志服务 SLS,月写入数据量 50GB 1个月
简介: 本文记录/分享 目前项目的 K8s 部署结构和请求追踪改造方案

ebdb18e4881afaef26aeca60c6db0529.png


这个图算是一个通用的前后端分离的 k8s 部署结构:


Nginx Ingress 负责暴露服务(nginx前端静态资源服务), 根据十二要素应用的原 则,将后端 api 作为 nginx 服务的附加动态资源。


Ingress vs Ingress-nginx


Ingress 是一种向 k8s 集群外部的客户端公开服务的方法, Ingress 在网络协议栈的应用层工作,


根据请求的主机名 host 和路径 path 决定请求转发到的服务。


52511db766f0aa048779a643d3e461a5.png


在应用Ingress 对象提供的功能之前,必须强调集群中存在Ingress Controller, Ingress资源才能正常工作。


我这里web项目使用的是常见的Ingress-nginx (官方还有其他用途的 Ingress),Ingress-nginx 是使用nginx 作为反向代理和负载均衡器的 K8s Ingress Controller, 作为Pod运行在kube-system 命名空间。


了解 Ingress 工作原理,有利于我们与运维人员打交道。


07bbbab4571eabbf6e19833290eb54eb.jpg


下面通过 Ingress-nginx 暴露 Kibana 服务:


---apiVersion: networking.k8s.io/v1beta1kind: Ingressmetadata:  name: kibana  labels:    app: kibana  annotations:    kubernetes.io/ingress.class: "nginx"    nginx.ingress.kubernetes.io/proxy-connect-timeout: "30"    nginx.ingress.kubernetes.io/proxy-read-timeout: "1800"    nginx.ingress.kubernetes.io/proxy-send-timeout: "1800"    nginx.ingress.kubernetes.io/proxy-body-size: "8m"    nginx.ingress.kubernetes.io/ssl-redirect: "true"spec:  tls:    - hosts:      - 'https://logging.internal.gridsum.com/'      secretName: tls-cert  rules:    - host: 'https://logging.internal.gridsum.com'      http:        paths:          - path: /            backend:              serviceName: kibana              servicePort: 5601


☹️ Ingress-nginx 中最让我困惑的是它的Paths分流rewrite-target注解。


Paths 分流 一般用于 根据特定的 Path,将请求转发到特定的后端服务 Pod,后端服务 Pod 能接收到 Path 这个信息。一般后端服务是作为 api。


rewrite-target 将请求重定向到后端服务, 那有什么用处呢?


答:以上面暴露的 kibana 为例, 我们已经可以在https://logging.internal.gridsum.com/ 访问完整的 Kibana, 如果我想利用这个域名暴露 ElasticSearch 站点,怎么操作?这时就可以利用rewrite-target


---apiVersion: networking.k8s.io/v1beta1kind: Ingressmetadata:  name: elasticsearch  labels:    app: kibana  annotations:    kubernetes.io/ingress.class: "nginx"    nginx.ingress.kubernetes.io/proxy-connect-timeout: "30"    nginx.ingress.kubernetes.io/proxy-read-timeout: "1800"    nginx.ingress.kubernetes.io/proxy-send-timeout: "1800"    nginx.ingress.kubernetes.io/proxy-body-size: "8m"    nginx.ingress.kubernetes.io/ssl-redirect: "true"    nginx.ingress.kubernetes.io/rewrite-target: "/$2"spec:  tls:    - hosts:      - 'logging.internal.gridsum.com'      secretName: tls-cert  rules:    - host: 'logging.internal.gridsum.com'      http:        paths:          - path: /es(/|$)(.*)            backend:              serviceName: elasticsearch              servicePort: 9200


在此 Ingress 定义中,由(.*)捕获的所有字符都将分配给占位符$2,然后将其用作重写目标注解中的参数。这样的话:https://logging.internal.gridsum.com/es 将会重定向到后端 elasticsearch 站点,并且忽略了 es 这个 path


595a67f7f893e0beb27472dfcc036203.png


Ingress-nginx 到 webapp 的日志追踪


熟悉我的朋友知道, 我写了《一套标准的ASP.NET Core容器化应用日志收集分析方案》,这里面主要是 BackEnd App 的日志,从我上面的结构图看,


Ingress-nginx----> Nginx FrontEnd App--->BackEnd App 需要一个串联的追踪 Id, 便于观察运维网络和业务应用。


幸好 Ingress-nginx, Nginx 强大的配置能力帮助我们做了很多事情:


客户端请求到达 Ingress-Nginx Controllerr,Ingress-Nginx Controller 会自动添加一个X-Request-ID的请求 Header (随机值)---- 这个配置是默认的


请求达到 Nginx FrontEnd App, Nginx 有默认配置proxy_pass_request_headers on;, 自动将请求头都传递到上游的 Backend App


这样跨越整个结构图的 request_id 思路已经清楚了,最后一步只需要我们在 Backend App 中提取请求中携带的X-Request-ID, 并作为日志的关键输出字段。


☺️ 这就涉及到怎么自定义日志的LayoutRender


下面为Asp.NETCore NLog 自定义名为x_request_id的 Render,该 Render 从请求的 X-Request-ID 标头中提取值。


① 定义 NLog Render


/// <summary>    /// Represent a unique identifier to represent a request from the request HTTP header X-Request-Id.    /// </summary>    [LayoutRenderer("x_request_id")]    public class XRequestIdLayoutRender : HttpContextLayoutRendererBase    {        protected override void Append(StringBuilder builder, LogEventInfo logEvent)        {            var identityName = HttpContextAccessor.HttpContext?.Request?.Headers?["X-Request-Id"].FirstOrDefault();            builder.Append(identityName);        }    }    /// <summary>    /// Represent a http context layout renderer to access the current http context.    /// </summary>    public abstract class HttpContextLayoutRendererBase : LayoutRenderer    {        private IHttpContextAccessor _httpContextAccessor;        /// <summary>        /// Gets the <see cref="IHttpContextAccessor"/>.        /// </summary>        protected IHttpContextAccessor HttpContextAccessor { get { return _httpContextAccessor ?? (_httpContextAccessor = ServiceLocator.ServiceProvider.GetService<IHttpContextAccessor>()); } }    }    internal sealed class ServiceLocator    {        public static IServiceProvider ServiceProvider { get; set; }    }


② 从请求中获取 X-Request-Id 依赖 IHttpContextAccessor 组件


这里使用依赖查找的方式获取该组件,故请在Startup ConfigureService 中生成服务


public void ConfigureServices(IServiceCollection services) {     // ......     ServiceLocator.ServiceProvider = services.BuildServiceProvider(); }


③ 最后在 Program 中注册这个NLog Render:


public static void Main(string[] args){     LayoutRenderer.Register<XRequestIdLayoutRender>("x_request_id");     CreateHostBuilder(args).Build().Run();}


这样从 Ingress-Nginx 产生的request_id,将会流转到 Backend App, 并在日志分析中起到巨大作用,也便于划清运维/开发的故障责任。


https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#generate-request-id


http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass_request_headers


总结


1.了解了Ingress在应用层工作,根据Host和Path暴露k8s服务。


2.本文梳理了Ingress和常见的Ingress-nginx的关系。


3.对于应用了Ingress的应用,梳理了从Ingress-nginx到WebApp的日志追踪id, 便于排查网络/业务故障。

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。 &nbsp; &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
缓存 JavaScript 安全
深度解析Nginx正向代理的原理与实现
深度解析Nginx正向代理的原理与实现
423 8
|
5月前
|
存储 应用服务中间件 nginx
在使用Nginx之后,如何在web应用中获取用户IP以及相关原理
但总的来说,通过理解网络通信的基础知识,了解http协议以及nginx的工作方式,我们已经能在大多数情况下准确地获取用户的真实IP地址了,在调试问题或者记录日志时会起到很大的帮助。
264 37
|
负载均衡 网络协议 关系型数据库
一口把LVS、Nginx及HAProxy工作原理讲清楚了。(附图)
一口把LVS、Nginx及HAProxy工作原理讲清楚了。(附图)
235 0
|
12月前
|
中间件 应用服务中间件 nginx
Nginx+uWSGI+Django原理
Nginx+uWSGI+Django原理
|
负载均衡 网络协议 Unix
Nginx负载均衡与故障转移实践
Nginx通过ngx_http_upstream_module模块实现负载均衡与故障转移,适用于多服务器环境。利用`upstream`与`server`指令定义后端服务器组,通过`proxy_pass`将请求代理至这些服务器,实现请求分发。Nginx还提供了多种负载均衡策略,如轮询、权重分配、IP哈希等,并支持自定义故障转移逻辑,确保系统稳定性和高可用性。示例配置展示了如何定义负载均衡设备及状态,并应用到具体server配置中。
|
负载均衡 应用服务中间件 网络安全
Django后端架构开发:Nginx服务优化实践
Django后端架构开发:Nginx服务优化实践
224 2
|
负载均衡 应用服务中间件 API
深入理解 Nginx 与 Kong 的配置与实践
在微服务架构中,Nginx 用于配置负载均衡,如示例所示,定义上游`pay-service`包含不同权重的服务节点。Kong API 网关则通过service和route进行服务管理和路由,与Nginx的upstream和location类似。通过Kong的命令行接口,可以创建upstream、target、service和route,实现对后端服务的负载均衡和请求管理。Nginx和Kong协同工作,提供高效、灵活的API管理和流量控制。
498 1
深入理解 Nginx 与 Kong 的配置与实践
|
12月前
|
Java 应用服务中间件 API
nginx线程池原理
nginx线程池原理
113 0
|
域名解析 缓存 负载均衡
深度解析Nginx正向代理的原理与实现
Nginx虽然主要被用作反向代理,但也可以通过一些特殊配置用作正向代理。虽然不是它的主流用途,但它仍能以其高性能和高稳定性为用户提供代理服务。不过,出于安全性和匿名性的考虑,在使用它作为正向代理时须谨慎配置,并根据实际需求做出调整。
344 0
|
安全 网络协议 应用服务中间件
一文读懂HTTPS⭐揭秘加密传输背后的原理与Nginx配置攻略
一文读懂HTTPS⭐揭秘加密传输背后的原理与Nginx配置攻略