一、背景
目前我們的生產環境一層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的改造。