likes
comments
collection
share

【k8s系列十四】nginx-ingress原理

作者站长头像
站长
· 阅读数 11

一. 现存的问题

现在所有的app再上线之前都必须进行加密,这里的加密不是说对应用加密,而是对请求加密,比如https加密请求。如果我们使用的是clusterIp类型, clusterIp是四层协议,那么就不能再svc层加密,这时必须在每一个app上进行加密。 也就是每台服务器都要配置https加密协议

【k8s系列十四】nginx-ingress原理

这样的问题是,每次上线一个app,都要对app进行加密。很多重复操作。

那么,我们能不能换一种方案,就实现一次加密呢?比如将ClusterIp替换为nginx,这样就采用七层协议(四层协议只能用来进行数据传输,七层协议才可以用来做加密)。

【k8s系列十四】nginx-ingress原理 这样用户在请求到nginx的时候,采用的是https加密协议, 而nginx在请求到pod的时候, 采用的是http协议, 这样我们只需要在nginx进行加密就可以了. 这样的配置更简单, 后端服务的压力也会更小.

我们要是在物理机上像上面那样实现是可以的, 那么, 要是在k8s中, 应该如何实现呢?

【k8s系列十四】nginx-ingress原理

第一步:创建一个myapp-deployment, 创建n个pod. 在创建一个clusterIp类型的svc, 关联到myapp. 设置好对内端口. 第二步:创建一个nginx-deployment,创建n个nginx的pod, 在创建一个NodePort类型的svc, 对内关联nginx的pod, 对外暴露一个端口. 第三步: 我们在nginx上进行https加密, 这样用户在请求的时候,需要通过https:对外暴露的端口请求到nginx的svc,进而请求到nginx. 然后nginx在转发请求到myapp的svc, 这时使用的是http请求.

这样就实现了k8s集群版本的应用加密.

问题来了. 我的根本目标是想要给myapp加密, 但就为了给myapp加密, 我们配置了myapp的svc, nginx, nginx的svc, 以及nortPort对外暴露端口等等一系列动作. 假如后期还有一套app需要部署且实现加密,我们还需要配置一套这样的方案, 实在是太费劲了. 有没有一种简单的方案, 假如我创建某种类型的资源, 它就自动实现了创建这一系列的动作.

这就是ingress.

小结

svc可以实现负载均衡,但是svc也有一个缺点,svc底层是一个4层协议,这样svc就不能实现7层的负载调度,所以,后期官方给我们增加了一个叫ingress的接口。基于ingress,我们就可以实现七层代理。只能能够实现七层代理的组件, 我们都可以把它封装为ingress。我们常用的七层调度是服务器是nginx,因此我们可以吧nginx封装为nginx-ingress。

二. nginx-ingress原理

ingress 的作用是什么呢? 我们只要创建了ingress对象, 他就会自动把相应的配置添加到七层代理服务器里(比如:nginx). 也就是https配置的那一套被自动实现了, 但原理还是上面的逻辑.

【k8s系列十四】nginx-ingress原理

也就是ingerss将上述创建过程都自动化了. 虽然自动化了,但是也会有一些问题. 比如: ingress配置文件写好了, 启动的时候会自动写入到七层代理服务器nginx中, 我们知道nginx配置修改,必须重启服务, 重启服务就会导致服务的不稳定. 就重启nginx这件事, ingress就没有那么好用了. 这是一个问题. 解决这个问题有两个办法. 方法一: 替换nginx. 把nginx替换为一个更修改配置不需要重启服务立刻就生效的七层代理服务器. 比如:traffic服务器. 修改了配置以后, 可以不用重启服务, 立刻生效. 但traffic是一个新的服务器, 目前为止 traffic服务还不太稳定, 其性能只能达到nginx的80%. 方法二: 改造nginx. 由于traffic还不稳定, 性能还不太高, 所以,现在各大公司依然趋于使用nginx-ingress, 也就是改造后的nginx. 因此,我们就可以看到改造后的这张图, 这张图就是nginx-ingress的原理

【k8s系列十四】nginx-ingress原理

在改后的nginx-ingress中, 多了两个协程. 什么是协程呢?可以理解为是轻量级的进程.

  • 第一个协程Store(协程), 它会去监听k8s的apiserver. 当有任何和ingress有关的事件发生的时候, Store协程会获取并判断这个协程的紧急重要程度.如果是特别紧急而且很重要的信息, 则发送给SyncQueue协程. 如果不是特别紧急的信息, 则将其写入到一个更新时间updateChannel中.
  • updateChannel就相当于一个一级缓存. 不重要的信息会不断的写入到updateChannel中, 直到写满了,再将其交给nginxController主程.
  • nginxController主程会将数据发送到同步队列中, 同步队列是syncQueue. 这相当于是nginx的一个二级缓存
  • syncQueue写满了以后, 注意这里必须是写满了以后, 会定期将队列中的数据交给SyncQueue协程处理.
  • 协程处理信息后, 判断nginx是否需要reload. 如果是就重写配置文件, 然后重启nginx. 如果不需要, 就把信息以post请求的方式向乱lua server发送更新请求.

整个上面这个过程, 其实就是给nginx增加了2层缓存, 目的就是为了减少ngxin重启的次数.