Ingress-nginx工作原理和实践

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
日志服务 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, 便于排查网络/业务故障。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
7月前
|
缓存 JavaScript 安全
深度解析Nginx正向代理的原理与实现
深度解析Nginx正向代理的原理与实现
246 8
|
4月前
|
负载均衡 网络协议 关系型数据库
一口把LVS、Nginx及HAProxy工作原理讲清楚了。(附图)
一口把LVS、Nginx及HAProxy工作原理讲清楚了。(附图)
|
2月前
|
中间件 应用服务中间件 nginx
Nginx+uWSGI+Django原理
Nginx+uWSGI+Django原理
|
3月前
|
负载均衡 网络协议 Unix
Nginx负载均衡与故障转移实践
Nginx通过ngx_http_upstream_module模块实现负载均衡与故障转移,适用于多服务器环境。利用`upstream`与`server`指令定义后端服务器组,通过`proxy_pass`将请求代理至这些服务器,实现请求分发。Nginx还提供了多种负载均衡策略,如轮询、权重分配、IP哈希等,并支持自定义故障转移逻辑,确保系统稳定性和高可用性。示例配置展示了如何定义负载均衡设备及状态,并应用到具体server配置中。
|
2月前
|
Java 应用服务中间件 API
nginx线程池原理
nginx线程池原理
43 0
|
4月前
|
负载均衡 应用服务中间件 网络安全
Django后端架构开发:Nginx服务优化实践
Django后端架构开发:Nginx服务优化实践
73 2
|
5月前
|
负载均衡 应用服务中间件 API
深入理解 Nginx 与 Kong 的配置与实践
在微服务架构中,Nginx 用于配置负载均衡,如示例所示,定义上游`pay-service`包含不同权重的服务节点。Kong API 网关则通过service和route进行服务管理和路由,与Nginx的upstream和location类似。通过Kong的命令行接口,可以创建upstream、target、service和route,实现对后端服务的负载均衡和请求管理。Nginx和Kong协同工作,提供高效、灵活的API管理和流量控制。
170 1
深入理解 Nginx 与 Kong 的配置与实践
|
4月前
|
域名解析 缓存 负载均衡
深度解析Nginx正向代理的原理与实现
Nginx虽然主要被用作反向代理,但也可以通过一些特殊配置用作正向代理。虽然不是它的主流用途,但它仍能以其高性能和高稳定性为用户提供代理服务。不过,出于安全性和匿名性的考虑,在使用它作为正向代理时须谨慎配置,并根据实际需求做出调整。
153 0
|
7月前
|
安全 网络协议 应用服务中间件
一文读懂HTTPS⭐揭秘加密传输背后的原理与Nginx配置攻略
一文读懂HTTPS⭐揭秘加密传输背后的原理与Nginx配置攻略
|
7月前
|
应用服务中间件 nginx
Nginx的referer参数的用法和原理
总结:referer参数可以用于Nginx配置,以限制或允许特定来源网站的访问,提高安全性或控制流量。它通过valid_referers指令来定义合法的Referer来源,并根据配置对请求进行处理。但需要注意,Referer字段内容可以被伪造,因此不应作为唯一的安全措施。
936 0