一、背景
目前我們的生產環境一層Nginx已經容器化部署,但是監控並不完善,我們期望其具有Ingress-Nginx-Controller組件上報監控的數據。這樣可以建立請求全鏈路的監控大盤。有利於監控查看關鍵鏈路的狀態信息,並快速定位問題。因此需要研究Ingress-Nginx-Controller組件的監控機制原理,看是否可以移植到一層nginx上實現metrics監控數據的采集。
二、分析
首先,目前常用的Ingress-Nginx-Controller有兩個。一個是K8S官方開源的Ingress-Nginx-Controller,另一個是nginx官方開源的Ingress-Nginx-Controller。我們使用的是K8S官方的版本。
這兩個Controller大致的區別如下:
1)K8S官方的Controller也是采用Go語言開發的,集成了Lua實現的OpenResty;而Nginx官方的Ccontroller是集成了Nginx;
2)兩者對Nginx的配置不同,並且使用的nginx.conf配置模板也是不一樣的,Nginx官方的采用兩個模板文件以include的方式配置upstream;K8S官方版本采用Lua動態配置upstream,所以不需要reload。
所以,在pod頻繁變更的場景下,采用K8S官方版本不需要reload,影響會更小。
接下來,我們來看K8S官方的Ingress-Nginx-Controller是如何實現Metrics監控數據采集上報的。
根據Ingress-Nginx-Controlleroller內部架構圖:
可以知道,Ingress-Nginx-Controller的內部組成部分和通訊機制。這里我們針對Nginx Metrics部分展開分析。於是,我們分析一下Ingress-Nginx-Controller的源碼,找到其Metrics的入口。
在ingress-nginx/cmd/nginx/main.go文件中,我們找到了Metrics的入口,如下:
可以看到,當我們訪問/metrics路徑去獲取監控數據時,程序會返回metrics.NewCollector()中采集的數據。繼續分析metrics.NewCollector的邏輯。在ingress-nginx/internal/ingress/metrics/main.go文件中,我們可以看到:
這就是metrics真實數據來源的采集入口,我們可以看到一共包含了四部分的數據:NGINXStatus,NGINXProcess,SocketCollector和IngressController。下面,我們看下這四部分數據具體是什么?
1)NGINXStatus
其中nginx.StatusPath就是/nginx_status
由此可知,NGINXStatus的數據就是通過/nginx_status有nginx的status模板采集的數據。
2)NGINXProcess
而NGINXProcess的數據則是通過process_exporter的方式在/proc中采集nginx相關的數據。
3)SocketCollector
而NGINXSocket部分的數據則是監聽/tmp/prometheus-nginx.socket這個socket文件來收集的數據。那么這個文件的數據來源是哪里呢?我們grep一下這個文件,發現nginx的lua腳本中有一個monitor.lua文件,就是這個文件采集到nginx的數據后寫進去的。
由此可知,NGINXSocket的數據是通過monitor.lua采集的。
4)IngressController
而NGINXController部分的數據則controller對nginx操作狀態信息的統計,然后直接上報的。
經過以上的分析,我們知道。ingress-nginx-controller的metrics監控包含了四部分數據:NGINXStatus,NGINXProcess,SocketCollector和IngressController。
其中NGINXStatus和SocketCollector都是在nginx中實現,通過nginx自身的status模板和monitor.lua實現,並通過http或者socket的方式暴露。NGINXProcess和IngressController則是有ingress-controller本身實現。
三、一層Nginx實現類似ingress-nginx-controller的metrics監控
由上面的分析我們可以知道,要使得普通的nginx實例具備Ingress-Nginx-Controller的metrics監控能力,需要將NGINXStatus,NGINXProcess,SocketCollector和IngressController四部分的數據采集能力移植到nginx實例上。
1)NGINXStatus不需要移植,nginx開啟status模塊,以/nginx_status暴露即可; 2)SocketCollector移植簡單,將monitor.lua腳本拷貝到nginx中,簡單配置跑起來即可;該部分是SocketCollector監聽在/tmp/prometheus-nginx.socket文件,由monitor.lua采集數據后寫入。 3)NGINXProcess和IngressController移植較復雜,需要深入分析其源碼,從ingress-nginx-controller中剝離出來后單獨運行。其中IngressController部分的數據丟棄。
最后,通過抽離移植NGINXStatus,NGINXProcess,SocketCollector三部分監控內容。(代碼見:https://github.com/wsjhk/nginx-custom-metrics.git)部署到一層nginx中需要做如下變更:
1)抽離出來的代碼編譯為ngxcustom-metrics二進制可執行文件,打包到nginx的鏡像中,隨容器啟動一起啟動。
2)nginx的配置中需要添加Lua相關代碼的部署,具體配置參考源碼。
3)Prometheus配置采集一層nginx的metrics監控信息。驗證監控數據。
(一層Nginx的容器化實現參考:https://mp.weixin.qq.com/s/q_kTlflDMg6MGyNOq6sVjQ)
3.1)deployment中添加annotation:
3.2)添加job_name采集:
- job_name: 'slb-nginx-pods' honor_labels: false kubernetes_sd_configs: - role: pod namespaces: names: - slb-nginx tls_config: insecure_skip_verify: true relabel_configs: - target_label: dc replacement: huadong1 - target_label: cloud replacement: aliyun - source_labels: [__meta_kubernetes_namespace] action: replace target_label: namespace - source_labels: [__meta_kubernetes_pod_name] action: replace target_label: pod - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] action: keep regex: true - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] action: replace target_label: __metrics_path__ regex: (.+) - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_ngx_mr_port] action: replace regex: ([^:]+)(?::\d+)?;(\d+) replacement: $1:$2 target_label: __address__ - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme] action: replace target_label: __scheme__ regex: (.+)
采集到的數據樣例如下:
至此,完成了Nginx監控Metrics的改造。