Kubernetes部署ELK並使用Filebeat收集容器日誌

本文的試驗環境爲CentOS 7.3,Kubernetes集羣爲1.11.2,安裝步驟參見kubeadm安裝kubernetes V1.11.1 集羣

1. 環境準備

Elasticsearch運行時要求vm.max_map_count內核參數必須大於262144,因此開始之前需要確保這個參數正常調整過。

$ sysctl -w vm.max_map_count=262144

也可以在ES的的編排文件中增加一個initContainer來修改內核參數,但這要求kublet啓動的時候必須添加了--allow-privileged參數,但是一般生產中不會給加這個參數,因此最好在系統供給的時候要求這個參數修改完成。

ES的配置方式

  • 使用Cluster Update Setting API動態修改配置
  • 使用配置文件的方式,配置文件默認在 config 文件夾下,具體位置取決於安裝方式。
    • elasticsearch.yml 配置Elasticsearch
    • jvm.options 配置ES JVM參數
    • log4j.properties 配置ES logging參數
  • 使用Prompt方式在啓動時輸入

最常使用的配置方式爲使用配置文件,ES的配置文件爲yaml格式,格式要求和Kubernetes的編排文件一樣。配置文件中可以引用環境變量,例如node.name: ${HOSTNAME}

ES的節點

ES的節點Node可以分爲幾種角色:

  • Master-eligible node,是指有資格被選爲Master節點的Node,可以統稱爲Master節點。設置node.master: true
  • Data node,存儲數據的節點,設置方式爲node.data: true
  • Ingest node,進行數據處理的節點,設置方式爲node.ingest: true
  • Trible node,爲了做集羣整合用的。

對於單節點的Node,默認是master-eligible和data,對於多節點的集羣,就要仔細規劃每個節點的角色。

2. 單實例方式部署ELK

單實例部署ELK的方法非常簡單,可以參考我Github上的elk-single.yaml文件,整體就是創建一個ES的部署,創建一個Kibana的部署,創建一個ES的Headless服務,創建一個Kiana的NodePort服務,本地通過節點的NodePort訪問Kibana。

[root@devops-101 ~]# curl -L -O https://raw.githubusercontent.com/cocowool/k8s-go/master/elk/elk-single.yaml
[root@devops-101 ~]# kubectl apply -f elk-single.yaml 
deployment.apps/kb-single created
service/kb-single-svc unchanged
deployment.apps/es-single created
service/es-single-nodeport unchanged
service/es-single unchanged
[root@devops-101 ~]# kubectl get all
NAME                             READY     STATUS    RESTARTS   AGE
pod/es-single-5b8b696ff8-9mqrz   1/1       Running   0          26s
pod/kb-single-69d6d9c744-sxzw9   1/1       Running   0          26s

NAME                         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                         AGE
service/es-single            ClusterIP   None             <none>        9200/TCP,9300/TCP               19m
service/es-single-nodeport   NodePort    172.17.197.237   <none>        9200:31200/TCP,9300:31300/TCP   13h
service/kb-single-svc        NodePort    172.17.27.11     <none>        5601:32601/TCP                  19m
service/kubernetes           ClusterIP   172.17.0.1       <none>        443/TCP                         14d

NAME                        DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/es-single   1         1         1            1           26s
deployment.apps/kb-single   1         1         1            1           26s

NAME                                   DESIRED   CURRENT   READY     AGE
replicaset.apps/es-single-5b8b696ff8   1         1         1         26s
replicaset.apps/kb-single-69d6d9c744   1         1         1         26s

可以看看效果如下:

3. 集羣部署ELK

3.1 不區分集羣中的節點角色

[root@devops-101 ~]# curl -L -O https://raw.githubusercontent.com/cocowool/k8s-go/master/elk/elk-cluster.yaml
[root@devops-101 ~]# kubectl apply -f elk-cluster.yaml 
deployment.apps/kb-single created
service/kb-single-svc created
statefulset.apps/es-cluster created
service/es-cluster-nodeport created
service/es-cluster created

效果如下

3.2 區分集羣中節點角色

如果需要區分節點的角色,就需要建立兩個StatefulSet部署,一個是Master集羣,一個是Data集羣。Data集羣的存儲我這裏爲了簡單使用了emptyDir,可以使用localStorage或者hostPath,關於存儲的介紹,可以參考Kubernetes存儲系統介紹。這樣就可以避免Data節點在本機重啓時發生數據丟失而重建索引,但是如果發生遷移的話,如果想保留數據,只能採用共享存儲的方案了。具體的編排文件在這裏elk-cluster-with-role

[root@devops-101 ~]# curl -L -O https://raw.githubusercontent.com/cocowool/k8s-go/master/elk/elk-cluster-with-role.yaml 
[root@devops-101 ~]# kubectl apply -f elk-cluster-with-role.yaml 
deployment.apps/kb-single created
service/kb-single-svc created
statefulset.apps/es-cluster created
statefulset.apps/es-cluster-data created
service/es-cluster-nodeport created
service/es-cluster created
[root@devops-101 ~]# kubectl get all
NAME                             READY     STATUS              RESTARTS   AGE
pod/es-cluster-0                 1/1       Running             0          13s
pod/es-cluster-1                 0/1       ContainerCreating   0          2s
pod/es-cluster-data-0            1/1       Running             0          13s
pod/es-cluster-data-1            0/1       ContainerCreating   0          2s
pod/kb-single-5848f5f967-w8hwq   1/1       Running             0          14s

NAME                          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                         AGE
service/es-cluster            ClusterIP   None             <none>        9200/TCP,9300/TCP               13s
service/es-cluster-nodeport   NodePort    172.17.207.135   <none>        9200:31200/TCP,9300:31300/TCP   13s
service/kb-single-svc         NodePort    172.17.8.137     <none>        5601:32601/TCP                  14s
service/kubernetes            ClusterIP   172.17.0.1       <none>        443/TCP                         16d

NAME                        DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/kb-single   1         1         1            1           14s

NAME                                   DESIRED   CURRENT   READY     AGE
replicaset.apps/kb-single-5848f5f967   1         1         1         14s

NAME                               DESIRED   CURRENT   AGE
statefulset.apps/es-cluster        3         2         14s
statefulset.apps/es-cluster-data   2         2         13s

效果如下

4. 使用Filebeat監控收集容器日誌

使用Logstash,可以監測具有一定命名規律的日誌文件,但是對於容器日誌,很多文件名都是沒有規律的,這種情況比較適合使用Filebeat來對日誌目錄進行監測,發現有更新的日誌後上送到Logstash處理或者直接送入到ES中。

每個Node節點上的容器應用日誌,默認都會在/var/log/containers目錄下創建軟鏈接,這裏我遇到了兩個小問題,第一個就是當時掛載hostPath的時候沒有掛載軟鏈接的目的文件夾,導致在容器中能看到軟鏈接,但是找不到對應的文件;第二個問題是宿主機上這些日誌權限都是root,而Pod默認用filebeat用戶啓動的應用,因此要單獨設置下。

效果如下

具體的編排文件可以參考我的Github主頁,提供了Deployment方式的編排和DaemonSet方式的編排。

對於具體日誌的格式,因爲時間問題沒有做進一步的解析,這裏如果有朋友做過,可以分享出來。

主要的編排文件內容摘抄如下。

kind: List
apiVersion: v1
items:
- apiVersion: v1
  kind: ConfigMap
  metadata:
    name: filebeat-config
    labels:
      k8s-app: filebeat
      kubernetes.io/cluster-service: "true"
      app: filebeat-config
  data:
    filebeat.yml: |
      processors:
        - add_cloud_metadata:
      filebeat.modules:
      - module: system
      filebeat.inputs:
      - type: log
        paths:
          - /var/log/containers/*.log
        symlinks: true
        # json.message_key: log
        # json.keys_under_root: true
      output.elasticsearch:
        hosts: ['es-single:9200']
      logging.level: info        
- apiVersion: extensions/v1beta1
  kind: DaemonSet 
  metadata:
    name: filebeat
    labels:
      k8s-app: filebeat
      kubernetes.io/cluster-service: "true"
  spec:
    template:
      metadata:
        name: filebeat
        labels:
          app: filebeat
          k8s-app: filebeat
          kubernetes.io/cluster-service: "true"
      spec:
        containers:
        - image: docker.elastic.co/beats/filebeat:6.4.0
          name: filebeat
          args: [
            "-c", "/home/filebeat-config/filebeat.yml",
            "-e",
          ]
          securityContext:
            runAsUser: 0
          volumeMounts:
          - name: filebeat-storage
            mountPath: /var/log/containers
          - name: varlogpods
            mountPath: /var/log/pods
          - name: varlibdockercontainers
            mountPath: /var/lib/docker/containers
          - name: "filebeat-volume"
            mountPath: "/home/filebeat-config"
        nodeSelector:
          role: front
        volumes:
          - name: filebeat-storage
            hostPath:
              path: /var/log/containers
          - name: varlogpods
            hostPath:
              path: /var/log/pods
          - name: varlibdockercontainers
            hostPath:
              path: /var/lib/docker/containers
          - name: filebeat-volume
            configMap:
              name: filebeat-config

參考資料:

  1. Elasticsearch cluster on top of Kubernetes made easy
  2. Install Elasticseaerch with Docker
  3. Docker Elasticsearch
  4. Running Kibana on Docker
  5. Configuring Elasticsearch
  6. Elasticsearch Node
  7. Loggin Using Elasticsearch and kibana
  8. Configuring Logstash for Docker
  9. Running Filebeat on Docker
  10. Filebeat中文指南
  11. Add experimental symlink support
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章