通过阿里云K8S Ingress Controller实现路由配置的动态更新

7次阅读

共计 3974 个字符,预计需要花费 10 分钟才能阅读完成。

摘要:本文主要描述了阿里云 Kubernetes 集群 Ingress Controller 如何通过动态更新的方式来极大地缓解转发平面 Nginx 频繁 Reload 带来的影响。
简介
在 Kubernetes 集群中,Ingress 作为集群内服务对外暴露的访问接入点,其几乎承载着集群内服务访问的所有流量。我们知道,Nginx Ingress Controller 是 Kubernetes 社区很重要的一个子项目,其内部主要依托于高性能的负载均衡软件 Nginx,将 Kubernetes Ingress 资源对象实时地自动化转换为 Nginx 配置规则来对外提供期望的授权访问入口。
现实问题
当随着 Kubernetes 集群中部署的微服务越来越多,对外暴露的路由规则越来越复杂,服务后端 Endpoint 变化的越来越频繁,那么对应地都会引起 Nginx Ingress Controller 组件内 Nginx 配置文件的变化越来越频繁;而我们知道,任何一行 Nginx 配置的变化,都需要 Reload Nginx 才能生效,这在变化频率较低的场景下索性还能接受,但在高频率变化的场景下就会引起 Nginx 的频繁 Reload。
而 Nginx 频繁 Reload 带来的问题,这已是一个老生常谈的话题了,其问题本质主要还是源于 Nginx 本身最初的架构设计模型:

一般在 Linux 服务器中,我们会配置使用 Nginx 的 EPOLL 多进程模式;当我们修改了 Nginx 配置文件后,需要通过
nginx -s reload
命令来重新热加载新的 Nginx 配置规则;
当 Nginx Master 进程接收到 reload signal 后,其会从指定路径重新加载新的 Nginx 配置文件内容,并校验配置规则的有效性,若检验为有效的配置文件,则会依据新的配置文件中的 worker_processes 值 fork 出指定数量的新的 Nginx Worker 进程,此时新 fork 出来的子进程完全继承了父进程的内存数据 ngx_cycle(其包含了新的解析后的 Nginx 配置规则),同时将配置中的每一个 Listen Socket FD 注册到内核的 EPOLL 事件监听中,此时这些新的 Nginx Worker 进程可以接收处理来自客户端的请求;
同时 Nginx Master 进程会发送 QUIT signal 通知老的 Nginx Worker 进程平滑退出,当老的 Nginx Worker 进程接收到 QTUI 信号后,将其之前注册到 EPOLL 中的监听 Event 移除,至此不再接收处理新的客户端请求,并依据老配置文件中设置的 worker_shutdown_timeout 值来设置定时器,然后继续处理完已接收的客户端请求;若在 worker_shutdown_timeout 之前处理完已有的客户端请求,则自动退出,若未处理完,则被强制 Kill 退出,此时就会导致该客户端请求响应异常。
因此,对于在高频率变化的场景下,Nginx 频繁 Reload 会带来较明显的请求访问问题:

造成一定的 QPS 抖动和访问失败情况
对于长连接服务会被频繁断掉
造成大量的处于 shutting down 的 Nginx Worker 进程,进而引起内存膨胀

动态更新
为缓解 Nginx 频繁 Reload 带来的影响,我们需要通过动态更新的方式来加载 Nginx 配置规则,即在不 Fork 新 Nginx Worker 进程的情况下来实时更新已加载到内存中的 Nginx 配置规则。
首先我们看下 Nginx 的配置文件样式,主要包含下面几部分配置章节:
# 1\. main configuration
daemon off;
worker_processes 4;

events {
# 2\. event configuration
multi_accept on;
worker_connections 1024;
use epoll;
}

http {
# 3\. http main configuration
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

upstream {
# 4\. upstream configuration
server 0.0.0.1;
}

server {
# 5\. server configuration
server_name _ ;
listen 80 default_server;

location / {
# 6\. location configuration
proxy_pass http://upstream_balancer;
}
}
而在 Kubernetes 集群中,一个 Ingress 资源对象主要被解析映射到 Nginx 的 HTTP Main Block、Server Block、Upstream Block 和 Location Block 等章节的配置规则上,因此我们可以将这几部分频繁变化的配置内容以 Shared Memory 的方式统一维持在内存中,同时在 Ingress Controller 内部暴露出管控端口,通过 API 的方式来实时管理 Nginx 路由规则配置:

当 K8S Ingress Controller 监控到集群内 Ingress 及相关联的资源发生变化时,均可通过 Internal API 将最新的 Nginx 配置规则推送到统一的共享内存配置中,而不用再通过 Reload Nginx 的方式来使新配置生效,至此当 Nginx 处理任何新接收的客户端请求时,都可以基于最新的共享内存中的配置进行规则匹配和路由转发;
配置说明
1、目前阿里云容器服务 Kubernetes 集群中最新版本的 Nginx Ingress Controller 组件默认已开启 Upstream 的动态更新,同时支持应用服务的灰度发布和蓝绿发布功能,具体配置说明可参考这里;
我们可以通过如下命令来查看当前共享内存中的 Nginx Upstream 的配置列表:
kubectl -n kube-system exec -it <NGINX-INGRESS-CONOTROLLER-POD-NAME> — curl http://127.0.0.1:18080/configuration/backends
2、同时也支持 HTTPS 证书的动态更新,可通过修改 nginx-ingress-controller deployment 的如下参数配置来开启 Nginx Ingress Controller 的证书动态更新:
– args:
– /nginx-ingress-controller
– –configmap=$(POD_NAMESPACE)/nginx-configuration
– –tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
– –udp-services-configmap=$(POD_NAMESPACE)/udp-services
– –annotations-prefix=nginx.ingress.kubernetes.io
– –publish-service=$(POD_NAMESPACE)/nginx-ingress-lb
– –enable-dynamic-certificates=true ### 添加该配置
– –v=2
当开启 HTTPS 证书的动态更新后,Ingress 的 TLS 证书都统一维护在 Nginx 的共享内存中,我们可通过如下命令来查看当前共享内存中配置的证书列表:
kubectl -n kube-system exec -it <NGINX-INGRESS-CONOTROLLER-POD-NAME> — curl http://127.0.0.1:18080/configuration/certs
3、进一步地我们也支持 Nginx Server 和 Location 配置的动态更新,可通过修改 nginx-ingress-controller deployment 的如下参数配置来开启 Nginx Ingress Controller 的 Server 和 Location 的动态更新:
– args:
– /nginx-ingress-controller
– –configmap=$(POD_NAMESPACE)/nginx-configuration
– –tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
– –udp-services-configmap=$(POD_NAMESPACE)/udp-services
– –annotations-prefix=nginx.ingress.kubernetes.io
– –publish-service=$(POD_NAMESPACE)/nginx-ingress-lb
– –enable-dynamic-certificates=true ### 添加该配置
– –enable-dynamic-servers=true ### 添加该配置,同时也要 enable-dynamic-certificates
– –v=2
同样地,当我们开启了 Nginx Ingress Controller 的 Server 动态更新后,所有 Nginx Server 和 Location 的配置都统一维护在共享内存中,我们同样可以通过如下命令来查看当前共享内存中的 Server 配置列表:
kubectl -n kube-system exec -it <NGINX-INGRESS-CONOTROLLER-POD-NAME> — curl http://127.0.0.1:18080/configuration/servers
注意说明:当开启 Server 的动态更新特性后,部分 Ingress Annotation 配置暂不支持,正在逐步优化支持中,相应地您可直接通过 ConfigMap 方式来进行配置;

本文作者:chenqz 阅读原文
本文为云栖社区原创内容,未经允许不得转载。

正文完
 0