原文链接:https://kubernetes.github.io/ingress-nginx/how-it-works/
本文的目的是解释 Nginx Ingress 控制器的工作原理,特别是 Nginx 模型的构建方式以及我们为何需要这个模型。
1. NGINX 配置
ingress-nginx 的目标是构造配置文件(nginx.conf),主要用途是在配置文件有任何变更后都需要重新加载 NGINX。不过需要特别注意的是,在只有 upstream 配置变更的时候我们不需要重新加载 Nginx(即当你部署的应用 Endpoints 变更时)。我们使用 lua-nginx-module(https://github.com/openresty/lua-nginx-module) 达到这个目的。请通过 下面的内容 来了解有关操作方法的更多信息。
2. NGINX 模型
通常,一个 Kubernetes 控制器采用 synchronization loop pattern(https://coreos.com/kubernetes/docs/latest/replication-controller.html#the-reconciliation-loop-in-detail) 来检查控制器中所需的状态是否已更新或者需要变更。为了达到这个目的,我们需要使用集群中放入不同对象来构建模型,特别是 Ingresses、Services、Endpoints、Secrets 以及 Configmaps 来生成反映集群状态时间点的配置文件。
为了从集群获取这些对象,我们使用 Kubernetes Informers(https://godoc.org/k8s.io/client-go/informers#NewFilteredSharedInformerFactory),特别是 FilteredSharedInformer。当一个新的对象添加、修改或者删除的时候,informers 允许通过 回调(https://godoc.org/k8s.io/client-go/tools/cache#ResourceEventHandlerFuncs) 针对单个变更进行响应。不过没有办法知道一个特定的变更是否会影响最终的配置文件,所以在每次变更时,我们都必须基于集群的状态重新构建一个新模型,并将其和当前的模型进行比较。如果新模型等于当前模型,那么我们就可以避免生成新的 NGINX 配置并触发重新加载,否则,我们就通过 Endpoints 来检查不同,然后使用 HTTP POST 请求一个新的 Endpoints 列表发送给运行在 Nginx 中的 Lua 程序并且避免重新生成一个新的 NGINX 配置以及触发重新加载。如果运行的模型和当前的差异不仅仅是 Endpoints,我们则基于新的模型创建一个新的 NGINX 配置文件,替代当前的模型并触发一次重新加载。
该模型的用途之一是当状态没有变化的时候避免不必要的重新加载,并检测定义中的冲突。
生成 NGINX 配置最终是从一个 Go template 生成的,使用新模型作为这个模板所需要的变量输入。
3. 构建 NGINX 模型
建立模型是一项成本比较高的操作,所以必须使用同步循环。通过使用 work queue(https://github.com/kubernetes/ingress-nginx/blob/master/internal/task/queue.go#L38),可以不丢失变更并通过 sync.Mutex 移除来强制执行一次同步循环,此外还可以在同步循环的开始和结束之间创建一个时间窗口,从而允许我们摒弃不必要的更新。重要的是要理解,集群中的任何变更都会生成事件,然后 informer 会发送给控制器,这也是使用 work queue 的原因之一。
建立模型的操作方式:
4. 重新加载
下面描述了一些需要重新加载的场景:
5. 避免重新加载
在某些情况下,有可能需要避免重新加载,尤其是在 endpoints 发送变化的时候,如 Pod 启动或者被替换时。完全移除重新加载这超过了 Ingress 控制器的范围。这将需要大量的工作,并且有时没有任何意义。仅当 NGINX 变更了读取新配置的方式时,才进行变更,基本上,新的更改不会替代工作进程。
5.1 避免 Endpoints 变更时重新加载
在每个 endpoint 对象变更时,控制器从所有能看到的服务上获取 endpoints 并生成相应的后端对象。然后将这些对象发送给运行在 Nginx 内部的 Lua 处理程序。Lua 程序将这些后端存储在共享内存区域。然后对于在 balancer_by_lua 上下文运行的每个请求,Lua 代码检测 endpoints 选择对应 upstream 并应用已经配置的负载均衡算法,Nginx 负责其余的工作。这样,我们避免在 endpoint 变更时重新加载 Nginx。注意,这也包括仅影响 Nginx upstream 配置的 annoations 变更。
在频繁部署应用的较大集群中,这个特性可以避免大量的 Nginx 重新加载,否则会影响响应延迟,负责均衡质量(每一次重新加载 Nginx 都会重置负载均衡状态)等等。
5.2 避免因错误的配置而中断
因为 ingress-nginx 使用 synchronization loop pattern,它对所有匹配到的对象应用配置。如果某些 Ingress 对象配置损坏,如 nginx.ingress.kubernetes.io/configuration-snippet 这个 annotation 语法错误,生成的配置变得无效,将不会重新加载,并不再考虑其它 Ingress。
为了防止这种情况发生,nginx ingress 控制器选择暴露一个 validating admission webhook server(https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#validatingadmissionwebhook) 以确保传入的 ingress 对象可用性。这个 webhook 把传入的 ingress 对象追加到 ingresses 列表上,生成配置并调用 nginx 以确保配置没有语法错误。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有