kubernetes(二十二)addons-EFK日志处理

时间:2020-04-11
本文章向大家介绍kubernetes(二十二)addons-EFK日志处理,主要包括kubernetes(二十二)addons-EFK日志处理使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

前言

kubernetes官方默认给我们提供了很多addons,其中就包括了日志处理套件EFK,包括 Elasticsearch, Fluentd 和 Kibana三个组件。其中Elasticsearch是搜索引擎,负责存储日志并对外提供日志的查询功能;Fluentd是一个日志收集组件,负责收集集群中的日志、并发送给Elasticsearch;Kibana是一个图形化展示组件,负责从Elasticsearch中查询日志,并以适当的形式展示出来

部署EFK

  1. 下载对应的启动文件

    $ cd /opt/k8s/work/efk
    $ for file in es-service.yaml es-statefulset.yaml fluentd-es-configmap.yaml fluentd-es-ds.yaml kibana-deployment.yaml kibana-service.yaml;
    do
    wget  https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/fluentd-elasticsearch/$file
    done
    
    
    • Elasticsearch 以statefulset形式启动。对应的镜像中不包含Es的安全插件 X-Pack。因为es要求vm.max_map_count的值不能小于262144,所以对应的启动文件es-statefulset.yaml中有一个init container,在es容器启动前设置vm.max_map_count。如果系统中这个值已经设置过,可以把这个init container相关的配置去掉,通过以下命令可以查看vm.max_map_count的值

      $ more /proc/sys/vm/max_map_count
      
      
    • Storage es-statefulset.yaml启动文件中es的存储配置的是EmptyDir,所以在es重启时存储的数据会丢失,因此直接下载的文件只使用于测试,如果想在生产环境使用,要替换成永久存性的存储卷。

    • Fluentd 以DaemonSet形式启动,会在所有节点上启动一个pod,依据fluentd-es-configmap.yaml中的配置会读取kubelet、container的日志,发送给es。

    • 此addon中启动文件,不要直接在生产环境中使用,如果想在生产环境中使用,推荐用 Helm来安装这些组件,对应的helm地址如下

      Elasticsearch

      Fluentd-elasticsearch

      Kibana

  2. 修改启动文件中对应的镜像地址

    启动文件中默认的镜像Registry是quay.io,国内无法直接下载,此处用微软的Registry代替

    $ sed -i -e 's_quay.io_quay.azk8s.cn_' es-statefulset.yaml
    $ sed -i -e 's_quay.io_quay.azk8s.cn_' fluentd-es-ds.yaml 
    
    
  3. 启动EFK

    $ kubectl apply -f .
    
    

以上通过Kubernetes提供的EFK进行日志收集的部署就完成了。不过由于我在自己测试环境执行时由于资源限制,ES无法同时启动两个,而Kubernetes提供的这个ES镜像,至少需要两个组建成集群才能正常使用,所以,只能采用ES官方的镜像自己搭建EFK环境。

单节点ElasticSearch部署EFK

部署Elasticsearch

  1. 编辑启动文件

    1. es配置文件

      $ cat >docker.es.co-configmap.yaml<<EOF
      kind: ConfigMap
      apiVersion: v1
      metadata:
        name: es-config-v7.6.1
        namespace: kube-system
        labels:
          addonmanager.kubernetes.io/mode: Reconcile
      data:
        elasticsearch.yml: |-
          cluster.name: kubernetes-logging
          node.name: elasticsearch-logging-0
          path.data: /data
          discovery.type: single-node
          network.host: 0.0.0.0
      EOF
      
      
      • discovery.type: single-node,代表对应的es是单节点集群
      • network.host: 0.0.0.0 任意IP都可以访问
    2. es启动文件

      $ cat >docker.es.co-statefulset.yml<<EOF
      # Elasticsearch deployment itself
      apiVersion: apps/v1
      kind: StatefulSet
      metadata:
        name: elasticsearch-logging
        namespace: kube-system
        labels:
          k8s-app: elasticsearch-logging
          version: v7.4.2
          addonmanager.kubernetes.io/mode: Reconcile
      spec:
        serviceName: elasticsearch-logging
        replicas: 1
        selector:
          matchLabels:
            k8s-app: elasticsearch-logging
            version: v7.4.2
        template:
          metadata:
            labels:
              k8s-app: elasticsearch-logging
              version: v7.4.2
          spec:
            #serviceAccountName: elasticsearch-logging
            containers:
            - image: elasticsearch:7.6.1
              name: elasticsearch-logging
              #imagePullPolicy: Always
              resources:
                # need more cpu upon initialization, therefore burstable class
                limits:
                  cpu: 1000m
                  memory: 4Gi
                requests:
                  cpu: 100m
                  memory: 1Gi
              ports:
              - containerPort: 9200
                name: db
                protocol: TCP
              - containerPort: 9300
                name: transport
                protocol: TCP
                #livenessProbe:
                #tcpSocket:
                #  port: transport
                #initialDelaySeconds: 5
                #timeoutSeconds: 10
                # readinessProbe:
                #tcpSocket:
                #  port: transport
                #initialDelaySeconds: 5
                #timeoutSeconds: 10
              volumeMounts:
              - name: elasticsearch-logging
                mountPath: /data
              - name: config-volume
                mountPath: /usr/share/elasticsearch/config/elasticsearch.yml
                subPath: elasticsearch.yml
              env:
              - name: "NAMESPACE"
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.namespace
            volumes:
            - name: elasticsearch-logging
              emptyDir: {}
            - name: config-volume
              configMap:
                name: es-config-v7.6.1
           
      EOF
       
      

      相比较kubernetes给我们提供的启动文件,此处主要做了两点改变

      • 删除了权限相关部分,不需要进行服务发现组件集群了。
      • 镜像文件换成了elasticsearch:7.6.1,是es官方发布在docker hub上的镜像
    3. es service文件

      $ cat >es-service.yaml<<EOF
      apiVersion: v1
      kind: Service
      metadata:
        name: elasticsearch-logging
        namespace: kube-system
        labels:
          k8s-app: elasticsearch-logging
          kubernetes.io/cluster-service: "true"
          addonmanager.kubernetes.io/mode: Reconcile
          kubernetes.io/name: "Elasticsearch"
      spec:
        ports:
        - port: 9200
          protocol: TCP
          targetPort: db
        selector:
          k8s-app: elasticsearch-logging
      
      EOF
      
  2. 启动服务

    $ kubectl create -f docker.es.co-configmap.yaml
    $ kubectl create -f docker.es.co-statefulset.yml
    $ kubectl create -f es-service.yaml
    
    

部署fluentd服务

fluentd启动文件和kubernetes给我们提供的没有什么变化,我本地启动时唯一修改的地方是docker日志的目录。在默认情况下,docker日志采用json-file这个日志driver,存储在docker工作目录下的containers目录中,默认的工作目录是/var/lib/docker,所以默认的docker 日志目录是/var/lib/docker/containers,我自己的环境在安装docker时将工作目录修改成了/data/k8s/docker/data,所以需要修改启动中的挂载目录

  1. 编辑启动文件

    1. DaemonSet文件

      $ cat>fluentd-es-ds.yaml<<EOF
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: fluentd-es
        namespace: kube-system
        labels:
          k8s-app: fluentd-es
          addonmanager.kubernetes.io/mode: Reconcile
      ---
      kind: ClusterRole
      apiVersion: rbac.authorization.k8s.io/v1
      metadata:
        name: fluentd-es
        labels:
          k8s-app: fluentd-es
          addonmanager.kubernetes.io/mode: Reconcile
      rules:
      - apiGroups:
        - ""
        resources:
        - "namespaces"
        - "pods"
        verbs:
        - "get"
        - "watch"
        - "list"
      ---
      kind: ClusterRoleBinding
      apiVersion: rbac.authorization.k8s.io/v1
      metadata:
        name: fluentd-es
        labels:
          k8s-app: fluentd-es
          addonmanager.kubernetes.io/mode: Reconcile
      subjects:
      - kind: ServiceAccount
        name: fluentd-es
        namespace: kube-system
        apiGroup: ""
      roleRef:
        kind: ClusterRole
        name: fluentd-es
        apiGroup: ""
      ---
      apiVersion: apps/v1
      kind: DaemonSet
      metadata:
        name: fluentd-es-v3.0.0
        namespace: kube-system
        labels:
          k8s-app: fluentd-es
          version: v3.0.0
          addonmanager.kubernetes.io/mode: Reconcile
      spec:
        selector:
          matchLabels:
            k8s-app: fluentd-es
            version: v3.0.0
        template:
          metadata:
            labels:
              k8s-app: fluentd-es
              version: v3.0.0
            # This annotation ensures that fluentd does not get evicted if the node
            # supports critical pod annotation based priority scheme.
            # Note that this does not guarantee admission on the nodes (#40573).
            annotations:
              seccomp.security.alpha.kubernetes.io/pod: 'docker/default'
          spec:
            priorityClassName: system-node-critical
            serviceAccountName: fluentd-es
            containers:
            - name: fluentd-es
              image: quay.azk8s.cn/fluentd_elasticsearch/fluentd:v3.0.0
              env:
              - name: FLUENTD_ARGS
                value: --no-supervisor -q
              resources:
                limits:
                  memory: 500Mi
                requests:
                  cpu: 100m
                  memory: 200Mi
              volumeMounts:
              - name: varlog
                mountPath: /var/log
              - name: varlibdockercontainers
                mountPath: /data/k8s/docker/data/containers
                readOnly: true
              - name: config-volume
                mountPath: /etc/fluent/config.d
              ports:
              - containerPort: 24231
                name: prometheus
                protocol: TCP
                #livenessProbe:
                #tcpSocket:
                #  port: prometheus
                #initialDelaySeconds: 5
                #timeoutSeconds: 10
                #readinessProbe:
                #tcpSocket:
                #  port: prometheus
                #initialDelaySeconds: 5
                #timeoutSeconds: 10
            terminationGracePeriodSeconds: 30
            volumes:
            - name: varlog
              hostPath:
                path: /var/log
            - name: varlibdockercontainers
              hostPath:
                path: /data/k8s/docker/data/containers
            - name: config-volume
              configMap:
                name: fluentd-es-config-v0.2.0
      EOF
      
      
      • 将对应的varlibdockercontainers挂载的hostPath修改成了/data/k8s/docker/data/containers,并且挂载到fluentd容器内的路径也要是/data/k8s/docker/data/containers,要保持一致
    2. 配置文件,因为配置文件和kubernetes给我们提供的没有做变更,此处不全部贴出,具体内容参考fluentd-es-configmap.yaml,此处只给出source部分的内容,来讲解下前一步为什么我们挂载到fluentd容器内的日志目录要和宿主机保持一致

    ...
    <source>
      @id fluentd-containers.log
      @type tail
      path /var/log/containers/*.log
      pos_file /var/log/es-containers.log.pos
      tag raw.kubernetes.*
      read_from_head true
      <parse>
        @type multi_format
        <pattern>
          format json
          time_key time
          time_format %Y-%m-%dT%H:%M:%S.%NZ
        </pattern>
        <pattern>
          format /^(?<time>.+) (?<stream>stdout|stderr) [^ ]* (?<log>.*)$/
          time_format %Y-%m-%dT%H:%M:%S.%N%:z
        </pattern>
      </parse>
    </source>
    ...
    
    

    这个source部分的配置中,fluentd并不是从我们挂载的容器中的docker日志目录直接拿数据的,而是从/var/log/containers目录下拉取日志数据的(/var/log/是我们将宿主机的/var/log目录挂载进去的),这个是因为,Kubernetes 的kubelet组件在/var/log/目录下创建了一个软链接,并且将pod名称,和container名称也放到这个软连接名称中了,例如

     /var/log/containers/fluentd-es-v3.0.0-hvbw7_kube-system_fluentd-es-ef645a4009163b41d596b68d32dbcc921f032549fa168b630d10d0ea2f98eacb.log -> /var/log/pods/kube-system_fluentd-es-v3.0.0-hvbw7_c5269d8e-8543-470a-8599-8ae3a7242a46/fluentd-es/0.log
     
    
     /var/log/pods/kube-system_fluentd-es-v3.0.0-hvbw7_c5269d8e-8543-470a-8599-8ae3a7242a46/fluentd-es/0.log -> /data/k8s/docker/data/containers/ef645a4009163b41d596b68d32dbcc921f032549fa168b630d10d0ea2f98eacb/ef645a4009163b41d596b68d32dbcc921f032549fa168b630d10d0ea2f98eacb-json.log
     
    

    kubelet通过这样的链接,读取/var/log/containers下的日志,实际上就会读取到容器内的日志,因为链接的路径信息已经固定,所以在容器内的路径一定要和宿主机中保持一致。

    这样做的好处也比较好理解,因为日志文件名称中包含了pod名称,命名空间等kubernetes的信息,在flutented中通过插件很容易就可将这些信息解析出来,便于使用者在kibana中对特定应用的日志进行检索过滤。

  2. 启动fluentd

    $ kubectl create -f fluentd-es-configmap.yaml
    $ kubectl create -f fluentd-es-ds.yaml  
    
    

部署kibana

  1. 编辑启动文件

    1. deployment文件

      cat >cat kibana-deployment.yaml<<EOF
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: kibana-logging
        namespace: kube-system
        labels:
          k8s-app: kibana-logging
          addonmanager.kubernetes.io/mode: Reconcile
      spec:
        replicas: 1
        selector:
          matchLabels:
            k8s-app: kibana-logging
        template:
          metadata:
            labels:
              k8s-app: kibana-logging
            annotations:
              seccomp.security.alpha.kubernetes.io/pod: 'docker/default'
          spec:
            containers:
            - name: kibana-logging
              image: elastic/kibana:7.2.0
              resources:
                # need more cpu upon initialization, therefore burstable class
                limits:
                  cpu: 1000m
                requests:
                  cpu: 100m
              env:
                - name: ELASTICSEARCH_HOSTS
                  value: http://elasticsearch-logging:9200
                - name: SERVER_NAME
                  value: kibana-logging
                - name: SERVER_BASEPATH
                  value: /api/v1/namespaces/kube-system/services/kibana-logging/proxy
                - name: SERVER_REWRITEBASEPATH
                  value: "false"
              ports:
              - containerPort: 5601
                name: ui
                protocol: TCP
      
      EOF
      
      
    2. service文件

      cat >kibana-service.yaml<<EOF
      apiVersion: v1
      kind: Service
      metadata:
        name: kibana-logging
        namespace: kube-system
        labels:
          k8s-app: kibana-logging
          kubernetes.io/cluster-service: "true"
          addonmanager.kubernetes.io/mode: Reconcile
          kubernetes.io/name: "Kibana"
      spec:
        ports:
        - port: 5601
          protocol: TCP
          targetPort: ui
        selector:
          k8s-app: kibana-logging
      EOF
      
      
  2. 启动kibana

    $ kubectl create -f kibana-deployment.yaml
    $ kubectl create -f kibana-service.yaml
    
    

启动kubecrl proxy访问kibana

$ kubectl proxy --accept-hosts='^*$' --address=192.168.0.107

通过界面访问,在浏览器中输入 http://192.168.0.107:8001/api/v1/namespaces/kube-system/services/kibana-logging/proxy/访问kibana。

初次访问需要先配置index pattern

稍等片刻,之后在Discover界面就可以查看相应的日志

可以看到,除了容器中的日志,还额外追加了许多kubernetes的信息。

原文地址:https://www.cnblogs.com/gaofeng-henu/p/12678901.html