负载均衡
负载均衡(Load Balancer,简称 LB)是指把客户端访问的流量通过负载均衡器,然后根据指定的一些负载均衡策略进行转发,最终可以均匀的分摊到后端上游服务器上,然后上游服务器进行响应后再返回数据给客户端。负载均衡的最常见应用是充当反向代理,通过负载均衡,可以大大的提高服务的响应速度、提高并发请求、提高稳定性(防止单点故障)。
负载均衡的基本实现方案,从业界来看,一般分为软件和硬件两大类,软件负载均衡又可以分层如4层、7层负载均衡,如下:
硬件负载均衡
如 F5,性能好,但是贵。一般的互联网公司都没有采集硬件负载均衡软件负载均衡
4 层:典型的如 LVS
7 层:典型的如 Nginx、HAProxy
目前这两个都可以实现 4 层,但是更多的还是使用 Nginx 的 7 层功能。
容器化
在物理机时代,还没有容器化之前,典型的负载均衡的建设方案就是搭建一套 Nginx 集群,提供 7 层的代理;搭建一套 LVS 集群,提供 4 层代理方案。并且同时,一般 7 层之上,都有一个 4 层代理,流量的基本流向就是 client -> LVS(4 层) -> Nginx(7层) -> server
。
在物理机这个时代,运维人员对 Nginx 的 upstream 的配置,基本都是手动添加修改各个 server,然后推送配置上线应用。传统的物理机时代的维护方式,是基于后端 server 的 IP 基本是固定的,比如,你上线一个 WebServer 的服务,要部署到哪些机器上,这个是事先确定好的了,IP 会固定不变,不管你怎么升级,服务都还是固定在这些机器上,因此这个时代这样的维护方式,并没有太多问题,大家以往也都维护的挺和谐。
在容器化时代,基于 Kubernetes 的容器化平台下,LB 的建设有哪些差异呢?主要分为两大块:
后端服务的 IP,会由于集群的调度,IP 是可变的,每当你部署、升级等操作的时候,IP 都会改变,那么这个时候,我们显然不能够再继续采用原有写死 IP 的方式来进行 7 层代理的维护了。由于服务 IP 的不确定性,我们必须要改变姿势,不能由人为填充 Nginx 的 upstream 的 server ip 的方式,只能通过动态的获取和变更,这个就需要 LB 能够主动发现后端服务并且动态更新
Kubernetes 的容器化平台下,集群内部的网络是虚拟的,虚拟网络的 IP 在集群外部是无法访问的,因此还需要解决好容器集群内外的网络互通问题。
K8s 负载均衡
Kubernetes 本身有内置一个集群内部的负载均衡方案,叫 kube-proxy,但是这个只能内部访问,并且功能稍显不足;而实际上,我们的容器平台,必须要提供集群外部访问的功能,因为你的用户(客户端)都是在集群外部。
Kubernetes 负载均衡相关的方案,包括:
集群内部负载均衡【内置】
Pod IP 在集群内部都是互通的,因此集群内部无需考虑网络互通问题
每个 Node 节点上的 kube-proxy,就是集群内置的内部负载均衡的解决方案;但是只限于集群内部,并且功能有限集群外部负载均衡【额外添加】
社区提供的 nginx-ingress-controller 方案可以满足需求
云厂商的 Cloud provider 也可以满足需求
参考 nginx-ingress-controller 的模式,自建 LB 方案
Nginx-Controller
简单来说,Nginx-Controller 就是来动态发现 Pod,然后渲染为 nginx 的 upstream;Nginx-Controller 就是一个 Nginx 再加上一个 Controller(发现 Pod 并渲染为 upstream)。
因此,一般的架构方案就是;client -> CDN -> LVS -> Nginx-Ingress-Controller -> Pod
下面来说下nginx-ingress的原理
初始化
// NewNGINXController creates a new NGINX Ingress controller.
func NewNGINXController(config *Configuration, mc metric.Collector) *NGINXController {
eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartLogging(klog.Infof)