摘要: 本文主要描述了阿里雲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會帶來較明顯的請求訪問問題:

  1. 造成一定的QPS抖動和訪問失敗情況
  2. 對於長連接服務會被頻繁斷掉
  3. 造成大量的處於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

原文鏈接

更多技術乾貨敬請關注云棲社區知乎機構號:阿里云云棲社區 - 知乎

本文為雲棲社區原創內容,未經允許不得轉載。


推薦閱讀:
相關文章