点赞
评论
收藏
分享
举报
Ingress Controller 的工作原理(上)
发表于2022-10-12 11:05

浏览 2.8k

原文作者:陶辉
原文链接:课程实录 | Ingress Controller 的工作原理(上)
转载来源:NGINX 开源社区


编者按——本文为系列课程《 K8S Ingress Controller 技术细节探讨》的第一节《 Ingress Controller 的工作原理》的课程实录。由于文章较长,将分为上下两篇发布

在本节课程中,陶辉老师介绍了 NGINX 集群是怎么工作的,并对比 NGINX 官方和 Kubernetes 官方的两个 Ingress Controller 在运行时各自的特点以及性能上的差别。

课程内容包括 Kubernetes 的网络流量场景,以及 NGINX 集群该如何管理,如何解决分布式集群中常见的高可用、容灾、扩容等问题。

课程背景简介

为什么大家一直比较重视 Kubernetes ?近五年来随着 DevOps 逐渐落地,微服务的服务种类变多,服务的托管都希望变为自动化的方式,DevOps 也在往这个方向发展,因此 NGINX 现在更希望用集群化、自动化托管去管理 NGINX 配置文件。

采用这种方式,我们可能只需要在一个抽象的 web 界面上进行配置,甚至在各种配置文件中(比如 Kubernetes 的 yaml 配置文件)定义并声明配置即可。至于集群怎样管理,则无需人工操作,因此很多运维岗位都消失了。

如果我们想把几百台、几千台 NGINX 负载均衡自动化地管理起来,那么 Kubernetes 的 Ingress Controller 会有非常大的参考价值。

现在有很多商业化的产品,其实就是在开源版本的 NGINX 上面做了一些插件的开发,最后通过 WAF、service mesh 等进行包装,最终给到用户。但是我们作为程序员和技术人员,更应知道的是怎样实现它,如何参考。

由于 Ingress Controller 是七层负载均衡,这是 NGINX 最擅长的,所以我们主要分享 Ingress Controller 的两种实现,第一种是 Kubernetes 官方的,第二种是 NGINX 官方的,这两种都基于 Go 语言实现。

本期课程主要分享 Ingress Controller 的工作原理,介绍 NGINX 集群是怎么工作的,并对比 NGINX 官方和 Kubernetes 官方的两个 Ingress Controller 在运行时各自的特点,以及性能上的差别。

课程内容分为两条线:第一条线,主要分享 Kubernetes 的网络流量场景——因为 Ingress Controller 的工作场景就是处理南北向的流量,尤其是整个集群的出口入口流量;第二条线,讲解 NGINX 集群该如何管理,如何解决分布式集群中常见的高可用、容灾、扩容等问题。

此外,“ NGINX 集群如何管理”这条线会再分为两条线——一方面是 NGINX 本身怎样实现高可用,另一方面是 Ingress Controller 在 Kubernetes 的 pod 和 service 不停变换的情况下,怎样提供高可用服务。

Kubernetes 托管容器服务

我们的底层基础设施经历了从物理机到虚拟机、公有云的演变。有了 docker 以后, docker 公司开发了 swarm 以实现集群化,但做得很糟糕,因此才有了 Kubernetes 的出现。

为什么说 swarm 很糟糕呢?因为集群化最核心的问题不是简单的镜像管理或容器运行,这些功能使用 Linux 的 cgroup 就能很简单地实现,真正实现 DevOps 的难点在于编排。

“编排”是指我们预先定义一种运行方式,比如有多少个七层负载均衡,后面部署了几个四层负载均衡,在下面部署了多少个 pod ,希望它们以什么样的方式运行,如果挂上存储以后,又该怎么样去挂载,怎样处理容灾和备份等等。我们将编排以定义的方式告诉系统,由编排系统自动地进行调度。

“编排”才是关键,但是 swarm 无法实现。后来,谷歌用 Go 语言开发了 Kubernetes 并对外开源。它最核心的能力在于托管——定义好之后,如果需要新的 IP ,它会产生一个虚拟 IP 并分配一个新的 pod ,按照我们 yaml 中预先定义的格式把它部署起来。

Ingress Controller 中的流量

在介绍 Ingress Controller 的作用之前,先解释一下流量。

很简单,外部的 traffic 流量通过时,可以理解为是通过 NGINX,首先基于域名(即 nginx.conf 文件中的 server_name ,也可称作虚拟主机域名 /virtual server/ 主机/虚拟主机等)做第一次匹配,之后再匹配 URL 或 location 。这就是 NGINX 中最核心的两级匹配。

如果大家熟悉 NGINX 的话,知道 NGINX 每一个请求有 11 个处理阶段,其中有一个叫 find_config ,这个阶段就是匹配 location 。

至于匹配域名,在接收到 host 头部的时候就已经在匹配了。而且 NGINX 的性能是非常高的,匹配域名走的是哈希表,匹配 URL 走的是一棵多叉树。

流量匹配完以后 NGINX 就把流量传输给后端的 service ,流量通过 service 后会再走一层(通过 service 上的负载均衡机制),到达 pod ——这就是完整的场景。

如果有人不太了解 Kubernetes :Service 和 pod 都是 Kubernetes 中的核心概念,我们可以把 pod 看作物理机或主机,它有自己的 IP ,而一个 service 可能对应着好几个 pod 。

那么现在 NGINX 要做什么呢?把流量管理起来。也就是有了 NGINX 以后, service 可能就变成了纯粹的逻辑概念了,真实的流量直接从 NGINX 到达 pod 。

Service 与 Endpoint

当然, Kubernetes 是很复杂的, service 有时并不是这样的。比如下图,就是一个标准的 service 。

Service 有很多种标签选择方式,这里只选择了一种,叫作 selector 的标签。如上图左侧,就是 yaml 格式(一种定义的格式),第一行 kind 定义了一个 service 类型;第二行是 API 版本,因为工程化的东西总得要有版本,向前兼容;metadata 下的 name ,定义了 service 的名称——这是给 ingress ( Kubernetes 里叫 Ingress controller )用的,核心就在于控制 Ingress ;Service 的名称(此例中叫 my-service )对应了三个 pod ,怎么对应的呢?用了一个选择器叫 MyApp ,走的是 TCP 协议。

Pod 的数量并没有关系,只要定义了 pod ,且它的选择器叫 app : MyAPP,那么就通通由 Service : my-service 进行类似于 VRP 的一种负载均衡服务。

这个负载均衡服务是怎么实现的?当它有一个虚拟 IP 的时候,其实是通过 iptables 完成的。Linux 上有一个配置叫 net.ipv4.ip_forward ,当它置为 1 的时候,就具备了转发报文的能力,在转发报文的时候有一个 iptables 规则。比如访问虚拟 IP 的时候,其中 50% 的流量给一个 pod ,50% 的流量给另一个 pod ,就是通过 iptables 来完成的。

Pod 其实就是 endpoint 。Ingress controller 主要监控五类数据,其中 endpoint 就是其中第一类, service 是第二类。service 跟 endpoint 的对应关系是:一个 service 可以绑定很多个 endpoint 。

Ingress 和抽象

有了 service 之后, endpoint 就已经被 service 抽象出来了。Ingress 又是什么?

如上, kind : Ingress 用于定义类型,表示这就是一个 Ingress ,也就是 NGINX 要抽象的。大家可以思考一下,如果让你去实现一个 NGINX 集群管理,肯定要把 NGINX 很多东西抽象出来,你会抽象什么?

我们先看 Kubernetes 主要抽象了些什么:第一个是域名(即 host ),跟 NGINX 中的 server_name 是一样的;下面有个 pathType ,则跟 location 一样。

location 有好多种配置,比如正则表达式配置、前缀匹配配置、完全匹配、跳过正则匹配等等,但是 Ingress 或者说 Kubernetes 所抽象的,是相对很有限的,因为 Kubernetes 并没有认为 NGINX 是唯一的选择,还可以放 LVS 或者其他的一些负载均衡——而其他的没有 NGINX 这么强大,所以只是把最小能力抽象出来了。

那么实际的流量是怎么匹配呢?根据我们的规则,如上图,如果发现 http 请求头部是 http://foo.bar.com,就传到 service1 ,如果是 http://bar.foo.com ,则传到 service2 。其实 service1 在 NGINX 中是根本看不到的,因为我们通常会有一个 upstream ,其中有 server pod1 和 server pod2 的 IP ,而一个 service 就对应一个 upstream 。

Ingress controller 在架构上的实现

接下来介绍 Ingress controller 在架构层面上是怎样实现的。

首先 NGINX 自身需要很多个维度来保证高可用( HA )。其中第一个就是以上这些配置随着机器宕机的时候,会不会丢掉?第二是 NGINX 挂掉以后能不能自动拉起?所在的这台机器挂掉了,能不能起新的机器(只要池子够多)?这都是我们要解决的问题。

先看第一个问题——数据会不会丢?这些数据究竟在哪里呢?

首先要搞清楚 NGINX 部在哪里,NGINX 作为 pod 部署在 worker node 上。也许有多个 NGINX 部署在不同的 worker node 上,那么如果这些 NGINX 的配置不一致了怎么办呢?我们需要把配置文件 nginx.conf 以及共享内存中的数据放到一个数据库中,这样才不会丢。这个数据库就是 ETCD ,这是一个 key-value 数据库——其实 Kubernetes 中的所有的数据都放在 ETCD 中。

NGINX 的数据如何放到 ETCD 中的呢?通过 APIServer ,也就是 gRPC 协议。APIServer 会通过 ETCD 本身提供的 gRPC 写入数据库中。值得一提的是,ETCD 数据库也是用 Go 语言写的。

ETCD 数据库

大家也许听说过 paxos 算法,也就是两段式提交。通常来说,分布式数据库不能写主备,主备就会有单点问题。因此我们要抛弃主备这种概念,或者说,有一个主节点挂掉也完全无所谓,只要挂掉的节点数小于 n/2 ( n 代表总节点数),就不影响服务。

比如,有三个节点,挂掉一台,还有两台,就还能正常提供服务,包括读服务和写服务,所有的能力没有丧失——这就是 paxos 的解决方案。paxos 以及 ETCD ,实际上是用 raft 的协议来实现的,以保证可靠性。

ETCD 里面存了五类数据,是 NGINX Ingress Controller 非常关心的数据。

第一个是 ingress (即上文讲过的 yaml 配置),然后是 endpoint 和 service ,一个是在 service 的 yaml ,一个是我们定义的 pod ,这些 pod 和 service 是通过选择器关联起来的,通过两类 yaml 把数据都存到 ETCD 里面。

以上这三类就是刚才讲的流量,外部的 HTTP 请求进来,先通过 ingress 中的 host 做域名判断,再通过 URL 做二次匹配,然后进入 upstream ,NGINX 中的 proxy_pass 开始选择 upstream 。选择 upstream 的时候,根据 endpoint 和 service 唯一地确认究竟该路由给哪一批 server 。

此外, ETCD 或者说 NGINX Ingress Controller 还非常在意两个东西,即 secret 和 ConfigMap 。

Secret 是什么?我们在配 ingress 、配 host 域名的时候,有可能外部流量是走 TLS 的——实现 HTTP 到 HTTPS 来保证它的安全。为了保证安全,最核心的一点就是检验身份、身份鉴别。在实现安全传输,包括使用非正则加密时,其实是通过 DH 秘钥交换协议,都不需要 secret 参与,但是在某一个条件下是一定需要 secret 参与的,就是身份验证,因为我们需要有人背书,其中背书使用的是 PKI 公钥体系,需要把公私钥保存到 NGINX 上。

公私钥是非常重要的,一旦被别人拿走以后就可以伪造了。假设你是一个银行或金融机构,绝不会把证书随随便便放到 ETCD 里,需要加密一下。

因此 Kubernetes 给我们提供了一种数据,叫 secret ,也就是加密以后再存到 ETCD 里面。即使拿走了 ETCD 数据库,也解密不了。所以,secret 就是为了保证 TLS 的公钥证书和 PKI 体系的公私钥证书(主要是私钥)的安全。

最后一个是 ConfigMap 。NGINX 提供了很强的能力,但是像 ingress 只能提供一点点能力,那剩余的很多数据存哪里呢?就存到 ConfigMap 里。ConfigMap 就是 Kubernetes 为大家提供的一个 key-value 存储的数据类型,它可以存文件、字符串等等,我们可以把很多东西放到 ConfigMap 上。

Ingress Controller ,或者说 NGINX ,必须要监控以上这五类数据。而这五类数据本身也能保证安全性,因为它存在 ETCD 里面,根本就不会丢,或者说只要小于 n/2 的机器挂了都没关系,也不会丢。

(未完待续)


更多资源

想要更及时全面地获取 NGINX 相关的技术干货、互动问答、系列课程、活动资源?
请前往 NGINX 开源社区:

官网:https://www.nginx.org.cn/
微信公众号:https://mp.weixin.qq.com/s/XVE5yvDbmJtpV2alsIFwJg
微信群:https://www.nginx.org.cn/static/pc/images/homePage/QR-code.png?v=1621313354
B 站:https://space.bilibili.com/628384319


已修改于2023-03-08 19:54
本作品系原创
创作不易,留下一份鼓励
NGINX官方账号

暂无个人介绍

关注



写下您的评论
发表评论
全部评论(0)

按点赞数排序

按时间排序

关于作者
NGINX官方账号
这家伙很懒还未留下介绍~
228
文章
21
问答
198
粉丝
相关文章
介绍nginx网页配置工具QQ技术交流群1:1106758598QQ技术交流群2:560797506邮箱: cym1102@qq.com官网地址: http://www.nginxwebui.cn码云: https://gitee.com/cym1102/nginxWebUIgithub: https://github.com/cym1102/nginxWebUI功能特点nginxWebUI也可管理多个nginx服务器集群,随时一键切换到对应服务器上进行nginx配置,也可以一键将某台服务器配置同步到其他服务器,方便集群管理.部署此项目后,配置nginx再也不用上网各种搜索配置代码,再也不用手动申请和配置ssl证书,只需要在本项目中进行增删改查就可方便的配置和启动nginx。技术说明本项目是基于springBoot的web系统,数据库使用sqlite,因此服务器上不需要安装任何数据库项目启动时会释放一个.sqlite.db到系统用户文件夹中,注意进行备份本系统通过Let'sencrypt申请证书,使用acme.sh脚本
点赞 6
浏览 6.1k
  前三周学习了陶辉老师的“NGINX基础培训系列课程”,感觉受益良多,在这里想把一些知识点记录一下,和大家分享一下知识点,也方便日后的随手查看,温故知新。  首先,我们了解到了Nginx的版本,Nginx发布版本分为主线版本和稳定版本,区分两个版本也非常简单,主线版本版本号为单数,比如1.19,稳定版本为双数,比如1.18,今天我要说的是稳定版本,这个版本会尽量少的减少Nginx的bug问题,适用于生产环境,这里我不建议使用Nginx和其他软件一样在生产环境中落后一个或多个大版本使用,之前生产环境做过漏扫,发现我们编译自带的Nginx版本为:nginx/1.13.3(查询命令为nginx-V),结果出现了多个漏洞,四个高危和一个中危漏洞:        通过升级Nginx到稳定版最新版本后修复!  其次,是Nginx发行版本的选择,目前比较流行的有:nginx、nginxplus、Tengine、openresty、ope
点赞 1
浏览 3.2k
感谢您参加“NGINX从入门到精通进阶系列培训”!以下为培训的问答、课件和录像,希望您能通过此培训学有所得,祝学习进步!>问与答:- 基础篇+高级篇 - 应用篇+实战篇(New)>课件(PPT):基础篇:-NGINX概要、安装、配置:https://interact.f5.com/rs/653-SMC-783/images/CNFEB22-NginxCoreCourse-Setup.pdf-NGINX日志、运维:https://interact.f5.com/rs/653-SMC-783/images/cnfeb22-nginxcorecourse-maintenance.pdf高级篇:-NGINX变量、API:https://interact.f5.com/rs/653-SMC-783/images/CNFEB22-NginxCoreCourse-API.pdf-NGINXSSL、NJS:https://interact.f5.com/rs/653-SMC-783/images/CNFEB22-NginxCoreCourse-SSL.pdf
点赞 10
浏览 4.8k