(建議收藏)以nginx-ingress爲基礎的超高效持久化方案!

容器內的日誌輸出有多重方式:容器內文件、stdout、stderr等等,咱們在解決nginx-ingress-controller的日誌持久化過程當中,以k8s的編排和組織能力,嘗試非侵入地解決各類問題,包括目錄權限與掛載的問題、nginx配置問題、日誌輪轉的問題。但願這些解決方法,能夠爲讀者容器化應用的日誌落盤提供思路。nginx

從需求提及

輕舟微服務平臺大量地依賴nginx-ingress-controller進行流量管理和負載均衡,所以該組件的日誌維護很是重要。docker

輕舟k8s團隊設計了一個較爲無侵入的方案,經過這個方案能夠將nginx-ingress-controller的日誌輸出,不管是accesslog仍是klog庫輸出的日誌,都能進行重定向落盤和輪轉、清理。 咱們發現這個日誌持久化方案基本能夠應對絕大多數的容器應用的日誌持久化需求。bash

nginx-ingress-controller的日誌

nginx-ingress-controller的日誌包括三個部分:markdown

  • controller日誌:輸出到stdout,經過啓動參數中的–log_dir可已配置輸出到文件,重定向到文件後會自動輪轉,但不會自動清理負載均衡

  • accesslog:輸出到stdout,經過nginx-ingress-controller的配置文件——configmap:
    nginx-configuration中的字段能夠配置輸出到哪一個文件。輸出到文件後不會自動輪轉或清理運維

  • errorlog:輸出到stderr,配置方式與accesslog相似。ide

給controller日誌落盤

  1. 給nginx-ingress-controller掛一個hostpath:
    /data/log/nginx_ingress_controller/
    映射到容器裏的/var/log/nginx_ingress_controller/ ,
  2. 給nginx-ingress-controller配置log-dir和logtostderr參數,將日誌重定向到/var/log/nginx_ingress_controller/中。

controller的日誌須要作定時清理。因爲controller的日誌是經過klog(k8s.io/klog)輸出的,會進行日誌滾動,因此咱們經過腳本定時清理必定時間以前的日誌文件便可。微服務

給nginx日誌落盤

  1. 修改configmap:
    nginx-configuration。配置accesslog和errorlog的輸出路徑,替換默認的stdout和stderr。輸出路徑咱們能夠與controller一致,便於查找。spa

  2. accesslog和errorlog都只有一個日誌文件,咱們可使用logrotate進行日誌輪轉,將輸出到宿主機上的日誌進行輪轉和清理。配置如:設計

    $ cat /etc/logrotate.d/nginx.log /data/log/nginx_ingress_controller/access.log { su root list rotate 7 daily maxsize 50M copytruncate missingok create 0644 www-data root } 12345678910

  3. 官方提供的模板中,nginx-ingress-controller默認都是以33這個用戶登陸啓動容器的,所以掛載hostpath路徑時存在權限問題。咱們須要手動在機器上執行chown
    -R 33:33 /data/log/nginx_ingress_controller.

自動化ops

nginx日誌落盤中,第二、3兩點均須要人工運維,有什麼解決辦法嗎?

initContainer

問題的關鍵是:有什麼辦法能夠在nginx-ingress-controller容器啓動以前加一個hook,將宿主機的指定目錄執行chown呢?

能夠用initContainer。initcontainer必須在containers中的容器運行前運行完畢併成功退出。利用這一k8s特性,咱們開發一個docker image:hub.c.163.com/combk8s/adddirperm:1.0.0 ,裏面只執行以下腳本:

#!/bin/bash
logdir=$LOG_DIR
userID=$USER_ID
echo "try to set dir: $logdir 's group as $userID"
chown  -R  $userID:$userID $logdir
12345
複製代碼

腳本讀取一些環境變量, 確認須要修改哪一個目錄,改爲怎樣的user group。

將腳本打包成dockerimage, 放在nginx-ingress-controller的deploy yaml中,做爲initcontainers。 注意要對該initcontainer配置環境變量和volumeMount.

sidecar

再說第二點,咱們注意到nginx-ingress-controller的基礎鏡像中並不包含logrotate,因此咱們初步的思路是在宿主機上運行並配置logrotate。 但機器上安裝和運行logrotate有須要批量運維的腳本,而且有些環境的機器可能不容許咱們安裝這些東西。 因此仍是應該思考一個容器化的方案。

咱們因而設計了一個sidecar,使用咱們本身構建好的鏡像:hub.c.163.com/combk8s/logrotate:v1.1 。這個鏡像啓動的容器中,會每一個6小時執行一次logrotate,定時時間能夠經過環境變量CRON_EXPR注入,例如CRON_EXPR= */3 * * * * 表示每隔三分鐘執行一次。

咱們將針對nginx accesslog和errorlog的日誌的輪轉策略保存到configmap中,並以volume的方式mount到這個sidecar容器中, 同時,這個sidecar容器也要mount nginx-ingress-controller的日誌目錄。

概括

咱們總結一下這些問題的解決辦法:

  • 鏡像user 權限致使的目錄掛載問題:經過initcontainer在業務容器啓動前先進行chown,調整目錄用戶組
  • 對於業務的stdout、stderr日誌,須要直接調整業務的配置,進行日誌落地,不然這類日誌只能經過docker保存的容器輸出文件來查看,可讀性較差
  • 對於須要進行輪轉的日誌,咱們能夠經過一個sidecar容器進行定時輪轉。

其餘方案的思考

鏡像覆蓋

有的人建議將initcontainer去掉,改成基於原有的nginx-ingress-controller鏡像加一層layer,將配置路徑權限的腳本放在該層執行。 我的認爲這種方法既不美觀,也不方便。惟一的好處僅在於deploy yaml仍然簡潔(但少不了volumeMount之類的配置)。

不過仍是看我的使用感覺吧~

做者:黃揚

看到這裏的小夥伴,若是你喜歡這篇文章的話,別忘了轉發、收藏、留言互動!

若是對文章有任何問題,歡迎在留言區和我交流~

最近我新整理了一些Java資料,包含面經分享、模擬試題、和視頻乾貨,若是你須要的話,歡迎私信我!

相關文章
相關標籤/搜索