帶你玩轉kubernetes-k8s(第63篇-Kubernetes之集羣統一日誌管理)

在Kubernetes集羣環境中,一個完整的應用或服務都會涉及爲數衆多的組件運行,各組件所在的Node及實例數量都是可變的。日誌子系統如果不做集中化管理,則會給系統的運維支撐造成很大的困難,因此有必要在集羣層面對日誌進行統一收集和檢索等工作。

在容器中輸出到控制檯的日誌,都會以*-json.log的命名方式保存在/var/lib/docker/containers/目錄下,這就爲日誌採集和後續處理奠定了基礎。

Kubernetes推薦採用Fluentd+Elasticsearch+Kibana完成對系統和容器日誌的採集、查詢和展現工作。

部署統一的日誌管理系統,需要以下兩個前提條件。

       ◎ API Server正確配置了CA證書。

       ◎ DNS服務啓動、運行。

系統部署架構

該系統的邏輯架構如下圖:

在各Node上都運行了一個Fluentd容器,採集本節點/var/log和/var/lib/docker/containers兩個目錄下的日誌進程,將其彙總到Elasticsearch集羣,最終通過Kibana完成和用戶的交互工作。

這裏有一個特殊的需求:Fluentd必須在每個Node上運行,爲了滿足這一需求,我們通過下面幾種方式部署Fluentd。

◎ 直接在Node主機上部署Fluentd。
◎ 利用kubelet的--config參數,爲每個Node都加載Fluentd Pod。
◎ 利用DaemonSet讓Fluentd Pod在每個Node上運行。

創建Elasticsearch RC和Service

Elasticsearch的RC和Service定義如下:

---
apiVersion: v1
kind: ReplicationController
metadata:
  name: elasticsearch-logging-v1
  namespace: kube-system
  labels:
    k8s-app: elasticsearch-logging
    version: v1
    kubernetes.io/cluster-service: "true"
spec:
  replicas: 2
  selector:
    k8s-app: elasticsearch-logging
    version: v1
  template:
    metadata:
      labels:
        k8s-app: elasticsearch-logging
        version: v1
        kubernetes.io/cluster-service: "true"
    spec:
      containers:
      - image: gcr.io/google_containers/elasticsearch:1.8
        name: elasticsearch-logging
        resources:
          # keep request = limit to keep this container in guaranteed class
          limits:
            cpu: 100m
          requests:
            cpu: 100m
        ports:
        - containerPort: 9200
          name: db
          protocol: TCP
        - containerPort: 9300
          name: transport
          protocol: TCP
        volumeMounts:
        - name: es-persistent-storage
          mountPath: /data
      volumes:
      - name: es-persistent-storage
    	emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: elasticsearch-logging
  namespace: kube-system
  labels:
    k8s-app: elasticsearch-logging
    kubernetes.io/cluster-service: "true"
    kubernetes.io/name: "Elasticsearch"
spec:
  ports:
  - port: 9200
    protocol: TCP
    targetPort: db
  selector:
    k8s-app: elasticsearch-logging

執行kubectl create -f elastic-search.yml命令完成創建。
       在命令成功執行後,首先驗證Pod的運行情況。通過kubectl get pods--namespaces=kube-system獲取運行中的Pod。

接下來通過Elasticsearch頁面驗證其功能。

首先,執行# kubectl cluster-info命令獲取Elasticsearch服務的地址。

然後,使用# kubectl proxy命令對API Server進行代理,在成功執行後輸出如下內容:

這樣就可以在瀏覽器上訪問URL地址https://20.0.40.51:12567/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy,來驗證Elasticsearch的運行情況了,返回的內容是一個JSON文檔。

在每個Node上啓動Fluentd

Fluentd的DaemonSet定義如下:

apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: fluentd-cloud-logging
  namespace: kube-system
  labels:
    k8s-app: fluentd-cloud-logging
spec:
  template:
    metadata:
      namespace: kube-system
      labels:
        k8s-app: fluentd-cloud-logging
    spec:
      containers:
      - name: fluentd-cloud-logging
        image: gcr.io/google_containers/fluentd-elasticsearch:1.17
        resources:
          limits:
            cpu: 100m
            memory: 200Mi
        env:
        - name: FLUENTD_ARGS
          value: -q
        volumeMounts:
        - name: varlog
          mountPath: /var/log
          readOnly: false
        - name: containers
          mountPath: /var/lib/docker/containers
          readOnly: false
      volumes:
      - name: containers
        hostPath:
          path: /var/lib/docker/containers
      - name: varlog
        hostPath:
          path: /var/log

通過kubectl create命令創建Fluentd容器:

查看創建的結果:

結果顯示Fluentd DaemonSet正常運行,還啓動了3個Pod,與集羣中的Node數量一致。

接下來使用# kubectl logs fluentd-cloud-logging-7tw9z命令查看Pod的日誌,在Elasticsearch正常工作的情況下,我們會看到類似下面這樣的日誌內容:

# kubectl logs fluentd-cloud-logging-7tw9z

    Connection opened to Elasticsearch cluster => 
{:host => "elasticsearch-logging", :port=>9200, :scheme=>"http"}

運行Kibana

至此已經運行了Elasticsearch和Fluentd,數據的採集和匯聚已經完成,接下來使用Kibana展示和操作數據。

Kibana的RC和Service定義如下:

---
apiVersion: v1
kind: ReplicationController
metadata:
  name: kibana-logging-v1
  namespace: kube-system
  labels:
    k8s-app: kibana-logging
    version: v1
    kubernetes.io/cluster-service: "true"
spec:
  replicas: 1
  selector:
    k8s-app: kibana-logging
    version: v1
  template:
    metadata:
      labels:
        k8s-app: kibana-logging
        version: v1
        kubernetes.io/cluster-service: "true"
    spec:
      containers:
      - name: kibana-logging
        image: gcr.io/google_containers/kibana:1.3
        resources:
          # keep request = limit to keep this container in guaranteed class
          limits:
            cpu: 100m
          requests:
            cpu: 100m
        env:
          - name: "ELASTICSEARCH_URL"
            value: "http://elasticsearch-logging:9200"
        ports:
        - containerPort: 5601
          name: ui
          protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  name: kibana-logging
  namespace: kube-system
  labels:
    k8s-app: kibana-logging
    kubernetes.io/cluster-service: "true"
    kubernetes.io/name: "Kibana"
spec:
  ports:
  - port: 5601
    protocol: TCP
    targetPort: ui
  selector:
    k8s-app: kibana-logging

通過kubectl create -f kibana-rc-svc.yml命令創建Kibana的RC和Service。

查看Kibana的運行情況。

結果表明運行均已成功。通過kubectl cluster-info命令獲取Kibana服務的URL地址。

同樣通過kubectl proxy命令啓動代理,在出現“Starting to serve on 127.0.0.1:8001”字樣之後,用瀏覽器訪問URL地址http://ip:port/api/v1/proxy/namespaces/kube-system/services/kibana-logging即可訪問Kibana頁面。

第1次進入頁面時需要進行一些設置,選擇所需選項後單擊create按鈕。

然後單擊discover按鈕,就可以正常查詢日誌了。

在搜索欄輸入“error”關鍵字,可以搜索出包含該關鍵字的日誌記錄。

同時,通過左邊菜單中Fields相關的內容對查詢的內容進行限定。

至此,Kubernetes集羣範圍內的統一日誌收集和查詢系統就搭建完成了。

Kubernetes的審計機制

Kubernetes爲了加強對集羣操作的安全監管,從1.4版本開始引入審計機制,主要體現爲審計日誌(Audit Log)。審計日誌按照時間順序記錄了與安全相關的各種事件,這些事件有助於系統管理員快速、集中瞭解以下問題:

◎ 發生了什麼事情?
◎ 作用於什麼對象?
◎ 在什麼時間發生?
◎ 誰(從哪兒)觸發的?
◎ 在哪兒觀察到的?
◎ 活動的後繼處理行爲是怎樣的?

下面是兩條Pod操作的審計日誌示例。

第一條:

第二條:

API Server把客戶端的請求(Request)的處理流程視爲一個“鏈條”,這個鏈條上的每個“節點”就是一個狀態(Stage),從開始到結束的所有Request Stage如下。

◎ RequestReceived:在Audit Handler收到請求後生成的狀態。
◎ ResponseStarted:響應的Header已經發送但Body還沒有發送的狀態,僅對長期運行的請求(Long-running Requests)有效,例如Watch。
◎ ResponseComplete:Body已經發送完成。
◎ Panic:嚴重錯誤(Panic)發生時的狀態。
Kubernets從1.7版本開始引入高級審計特性(AdvancedAuditing),可以自定義審計策略(選擇記錄哪些事件)和審計存儲後端(日誌和Webhook)等,開啓方法爲增加kube-apiserver的啓動參數--feature-gates=AdvancedAuditing=true。注意:在開啓AdvancedAuditing後,日誌的格式有一些修改,例如新增了上述Stage信息;從Kubernets 1.8版本開始,該參數默認爲true。
kube-apiserver在收到一個請求後(如創建Pod的請求),會根據Audit Policy(審計策略)對此請求做出相應的處理。
我們可以將Audit Policy視作一組規則,這組規則定義了有哪些事件及數據需要記錄(審計)。當一個事件被處理時,規則列表會依次嘗試匹配該事件,第1個匹配的規則會決定審計日誌的級別(Audit Level),目前定義的幾種級別如下(按級別從低到高排列)。
◎ None:不生成審計日誌。
◎ Metadata:只記錄Request請求的元數據如requesting user、timestamp、resource、verb等,但不記錄請求及響應的具體內容。
◎ Request:記錄Request請求的元數據及請求的具體內容。
◎ RequestResponse:記錄事件的元數據,以及請求與應答的具體內容。

None以上的級別會生成相應的審計日誌並將審計日誌輸出到後端,當前的後端實現如下。

(1)Log backend:以本地日誌文件記錄保存,爲JSON日誌格式,我們需要對API Server的啓動命令設置下列參數。

◎ --audit-log-path:指定日誌文件的保存路徑。
◎ --audit-log-maxage:設定審計日誌文件保留的最大天數。
◎ --audit-log-maxbackup:設定審計日誌文件最多保留多少個。
◎ --audit-log-maxsize:設定審計日誌文件的單個大小,單位爲MB,默認爲100MB。

審計日誌文件以audit-log-maxsize設置的大小爲單位,在寫滿後,kube-apiserver將以時間戳重命名原文件,然後繼續寫入audit-log-path指定的審計日誌文件;audit-log-maxbackup和audit-log-maxage參數則用於kube-apiserver自動刪除舊的審計日誌文件。

(2)Webhook backend:回調外部接口進行通知,審計日誌以JSON格式發送(POST方式)給Webhook Server,支持batch和blocking這兩種通知模式,相關配置參數如下。
◎ --audit-webhook-config-file:指定Webhook backend的配置文件。

◎ --audit-webhook-mode:確定採用哪種模式回調通知。
◎ --audit-webhook-initial-backoff:指定回調失敗後第1次重試的等待時間,後繼重試等待時間則呈指數級遞增。

Webhook backend的配置文件採用了kubeconfig格式,主要內容包括遠程審計服務的地址和相關鑑權參數,配置示例如下:

# clusters refers to the remote service.
clusters:
  - name: name-of-remote-audit-service
    cluster:
      certificate-authority: /path/to/ca.pem  # CA for verifying the remote service.
      server: https://audit.example.com/audit # URL of remote service to query. Must use 'https'.

# users refers to the API server's webhook configuration.
users:
  - name: name-of-api-server
    user:
      client-certificate: /path/to/cert.pem # cert for the webhook plugin to use
      client-key: /path/to/key.pem          # key matching the cert

# kubeconfig files require a context. Provide one for the API server.
current-context: webhook
contexts:
- context:
    cluster: name-of-remote-audit-service
    user: name-of-api-sever
  name: webhook

--audit-webhook-mode則包括以下選項。
◎ batch:批量模式,緩存事件並以異步批量方式通知,是默認的工作模式。
◎ blocking:阻塞模式,事件按順序逐個處理,這種模式會阻塞API Server的響應,可能導致性能問題。
◎ blocking-strict:與阻塞模式類似,不同的是當一個Request在RequestReceived階段發生審計失敗時,整個Request請求會被認爲失敗。

(3)Batching Dynamic backend:一種動態配置的Webhook backend,是通過AuditSink API 動態配置的,在Kubernetes 1.13版本中引入。
       需要注意的是,開啓審計功能會增加API Server的內存消耗量,因爲此時需要額外的內存來存儲每個請求的審計上下文數據,而增加的內存量與審計功能的配置有關,比如更詳細的審計日誌所需的內存更多。我們可以通過kube-apiserver中的--audit-policy-file參數指定一個Audit Policy文件名來開啓API Server的審計功能。

通常審計日誌可以以本地日誌文件方式保存,然後使用Fluentd作爲Agent採集該日誌並存儲到Elasticsearch,用Kibana等UI界面對日誌進行展示和查詢。

 

小結: 今天的內容到此結束

           謝謝大家的瀏覽。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章