• Kubernetes高效收集生产日志


    • 容器本身特性:
      • 采集目标多:容器本身的特性导致采集目标多,需要采集容器内日志、容器 stdout。对于容器内部的文件日志采集,现在并没有一个很好的工具能够去动态发现采集。针对每种数据源都有对应的采集软件,但缺乏一站式的工具。
      • 弹性伸缩难:kubernetes 是分布式的集群,服务、环境的弹性伸缩对于日志采集带来了很大的困难,无法像传统虚拟机环境下那样,事先配置好日志的采集路径等信息,采集的动态性以及数据完整性是非常大的挑战。
    • 现有日志工具的一些缺陷:
      • 缺乏动态配置的能力。目前的采集工具都需要事先手动配置好日志采集方式和路径等信息,因为它无法能够自动感知到容器的生命周期变化或者动态漂移,所以它无法动态地去配置。
      • 日志采集重复或丢失的问题。因为现在的一些采集工具基本上是通过 tail 的方式来进行日志采集的,那么这里就可能存在两个方面的问题:一个是可能导致日志丢失,比如采集工具在重启的过程中,而应用依然在写日志,那么就有可能导致这个窗口期的日志丢失;而对于这种情况一般保守的做法就是,默认往前多采集 1M 日志或 2M 的日志,那么这就又会可能引起日志采集重复的问题。
      • 未明确标记日志源。因为一个应用可能有很多个容器,输出的应用日志也是一样的,那么当我们将所有应用日志收集到统一日志存储后端时,在搜索日志的时候,我们就无法明确这条日志具体是哪一个节点上的哪一个应用容器产生的。

    本文档将介绍一种 Docker 日志收集工具 log-pilot,结合 Elasticsearch 和 kibana 等工具,形成一套适用于 kubernetes 环境下的一站式日志解决方案。

    GitHub - AliyunContainerService/log-pilot: Collect logs for docker containersCollect logs for docker containers. Contribute to AliyunContainerService/log-pilot development by creating an account on GitHub.https://github.com/AliyunContainerService/log-pilot容器日志采集利器Log-Pilot-阿里云开发者社区容器时代越来越多的传统应用将会逐渐容器化,而日志又是应用的一个关键环节,那么在应用容器化过程中,如何方便快捷高效地来自动发现和采集应用的日志,如何与日志存储系统协同来高效存储和搜索应用日志,本文将主要跟大家分享下如何通过Log-Pilot来采集容器的标准输出日志和容器内文件日志。icon-default.png?t=M276https://developer.aliyun.com/article/674327

    Log-Pilot 支持容器事件管理,它能够动态地监听容器的事件变化,然后依据容器的标签来进行解析,生成日志采集配置文件,然后交由采集插件来进行日志采集。

    相关特点和优势,可以点击上方的链接学习。

    方案

    从日志的采集方式上,在我看来方案大致主要分为两种:

    **(1)POD 里面安装logging agent**

    每个pod里面都要安装一个agent,无论是以放在本container还是以sidecar的方式部署,很明显会占用很多资源,基本不推荐

    **(2)在节点上安装logging agent(推荐)**

    其实容器stdout,stderr的日志最终也是落在宿主机上,而容器内的路径可以通过配置volumeMount 在宿主机上配置映射即可,所以这种方式还是最可行的

    当然应用还可以自己通过代码直接上报给日志服务,但是这种方式不够通用,还增加了业务代码的复杂性

    log-Pilot是一个智能容器日志采集工具,它不仅能够高效便捷地将容器日志采集输出到多种存储日志后端,同时还能够动态地发现和采集容器内部的日志文件,更多咨询可以移步这里

    log-Pilot目前支持两种工具对日志进行收集,Fluentd Plugin 和 Filebeat Plugin


    Log-Pilot支持容器事件管理,它能够动态地监听容器的事件变化,然后依据容器的标签来进行解析,生成日志采集配置文件,然后交由采集插件来进行日志采集

    以下的的安装配置,是基于上一篇的EFK的配置,只是修改收集端(有必要,可以了解上一篇的文章)

    Kubernetes安装EFK日志收集_南宫乘风-Linux运维-虚拟化容器-Python编程 ownit.top-CSDN博客

    准备

    参考官方部署文档的基础上使用本项目manifests/efk/部署,以下为几点主要的修改:

    • 增加 log-Pilot 部署代码(解决 不支持 es7.0 版本以上的痛点)
    • 修改官方docker镜像,方便国内下载加速
    • 修改 es-statefulset.yaml 支持日志存储持久化等
    • 增加自动清理日志

    创建 Elasticsearch 集群

    apiVersion: v1
    kind: Namespace
    metadata:
      name: logging

    1、 es-service.yaml

    kind: Service
    apiVersion: v1
    metadata:
      name: elasticsearch
      namespace: logging
      labels:
        app: elasticsearch
    spec:
      selector:
        app: elasticsearch
      clusterIP: None
      ports:
        - port: 9200
          name: rest
        - port: 9300
          name: inter-node

    定义了一个名为 elasticsearch 的 Service,指定标签 app=elasticsearch,当我们将 Elasticsearch StatefulSet 与此服务关联时,服务将返回带有标签 app=elasticsearch的 Elasticsearch Pods 的 DNS A 记录,然后设置 clusterIP=None,将该服务设置成无头服务。最后,我们分别定义端口9200、9300,分别用于与 REST API 交互,以及用于节点间通信。 

    [root@master01 efk]# kubectl apply -f es-service.yaml
    service/elasticsearch-logging created
    [root@master01 efk]# kubectl get svc -n kube-system 
    NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
    elasticsearch-logging   ClusterIP   None            <none>        9200/TCP                     15s

    es-statefulset.yaml

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: es
      namespace: logging
    spec:
      serviceName: elasticsearch
      replicas: 3
      selector:
        matchLabels:
          app: elasticsearch
      template:
        metadata:
          labels: 
            app: elasticsearch
        spec:
          nodeSelector:  #记得给节点把标签,不然会找到不符合的节点
            es: log
          initContainers:
          - name: increase-vm-max-map
            image: busybox
            command: ["sysctl", "-w", "vm.max_map_count=262144"]
            securityContext:
              privileged: true
          - name: increase-fd-ulimit
            image: busybox
            command: ["sh", "-c", "ulimit -n 65536"]
            securityContext:
              privileged: true
          containers:
          - name: elasticsearch
            image: docker.elastic.co/elasticsearch/elasticsearch:7.6.2
            ports:
            - name: rest
              containerPort: 9200
            - name: inter
              containerPort: 9300
            resources:
              limits:
                cpu: 1000m
              requests:
                cpu: 1000m
            volumeMounts:
            - name: data
              mountPath: /usr/share/elasticsearch/data
            env:
            - name: cluster.name
              value: k8s-logs
            - name: node.name
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: cluster.initial_master_nodes
              value: "es-0,es-1,es-2"
            - name: discovery.zen.minimum_master_nodes
              value: "2"
            - name: discovery.seed_hosts
              value: "elasticsearch"
            - name: ES_JAVA_OPTS
              value: "-Xms512m -Xmx512m"
            - name: network.host
              value: "0.0.0.0"
      volumeClaimTemplates:
      - metadata:
          name: data
          labels:
            app: elasticsearch
        spec:
          accessModes: [ "ReadWriteOnce" ]
          storageClassName: nfsdata
          resources:
            requests:
              storage: 5Gi 

     Pods 部署完成后,我们可以通过请求一个 REST API 来检查 Elasticsearch 集群是否正常运行。使用下面的命令将本地端口9200 转发到 Elasticsearch 节点(如es-0)对应的端口:

    [root@master01 new]# kubectl port-forward es-0 9200:9200 --namespace=logging
    Forwarding from 127.0.0.1:9200 -> 9200
    Forwarding from [::1]:9200 -> 9200
    curl http://localhost:9200/_cluster/state?pretty

     看到上面的信息就表明我们名为 k8s-logs 的 Elasticsearch 集群成功创建了3个节点:es-0,es-1,和es-2,当前主节点是 es-0

    创建 Kibana 服务

    Elasticsearch 集群启动成功了,接下来我们可以来部署 Kibana 服务,新建一个名为 kibana.yaml 的文件,对应的文件内容如下:

    kibana.yaml 

    apiVersion: v1
    kind: Service
    metadata:
      name: kibana
      namespace: logging
      labels:
        app: kibana
    spec:
      ports:
      - port: 5601
      type: NodePort
      selector:
        app: kibana
     
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: kibana
      namespace: logging
      labels:
        app: kibana
    spec:
      selector:
        matchLabels:
          app: kibana
      template:
        metadata:
          labels:
            app: kibana
        spec:
          nodeSelector:
            es: log
          containers:
          - name: kibana
            image: docker.elastic.co/kibana/kibana:7.6.2
            resources:
              limits:
                cpu: 1000m
              requests:
                cpu: 1000m
            env:
            - name: ELASTICSEARCH_HOSTS
              value: http://elasticsearch:9200
            ports:
            - containerPort: 5601

    上面我们定义了两个资源对象,一个 Service 和 Deployment,为了测试方便,我们将 Service 设置为了 NodePort 类型,Kibana Pod 中配置都比较简单,唯一需要注意的是我们使用 ELASTICSEARCH_HOSTS 这个环境变量来设置Elasticsearch 集群的端点和端口,直接使用 Kubernetes DNS 即可,此端点对应服务名称为 elasticsearch,由于是一个 headless service,所以该域将解析为3个 Elasticsearch Pod 的 IP 地址列表。 配置完成后,直接使用 kubectl 工具创建:

    kubectl create -f kibana.yaml
    service/kibana created
    deployment.apps/kibana created

    创建完成后,可以查看 Kibana Pod 的运行状态

    [root@master01 new]#  kubectl get pods --namespace=logging
    NAME                      READY   STATUS    RESTARTS   AGE
    es-0                      1/1     Running   0          13m
    es-1                      1/1     Running   0          9m48s
    es-2                      1/1     Running   0          7m46s
    kibana-8476dc9bbf-6mm6k   1/1     Running   0          3m2s

    如果 Pod 已经是 Running 状态了,证明应用已经部署成功了,然后可以通过 NodePort 来访问 Kibana 这个服务,在浏览器中打开http://<任意节点IP>:31838即可,

    出现 这个代表成功

    部署 log-Pilot

    Log-pilot是一个智能容器日志采集工具,它不仅能够高效便捷地将容器日志采集输出到多种存储日志后端,同时还能够动态地发现和采集容器内部的日志文件。

    针对前面提出的日志采集难题,Log-pilot通过声明式配置实现强大的容器事件管理,可同时获取容器标准输出和内部文件日志,解决了动态伸缩问题,此外,Log-pilot具有自动发现机制、CheckPoint及句柄保持的机制、自动日志数据打标、有效应对动态配置、日志重复和丢失以及日志源标记等问题。

    本质

    通过变量和模版文件生产日志收集配置文件,对日志进行采集。
    容器内文件日志路径需要配置emptyDir

    log-pilot.yaml

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: log-pilot
      labels:
        app: log-pilot
      # 设置期望部署的namespace。
      namespace: logging
    spec:
      selector:
        matchLabels:
          app: log-pilot
      updateStrategy:
        type: RollingUpdate
      template:
        metadata:
          labels:
            app: log-pilot
          annotations:
            scheduler.alpha.kubernetes.io/critical-pod: ''
        spec:
          # 是否允许部署到Master节点上tolerations。
          tolerations:
          - key: node-role.kubernetes.io/master
            effect: NoSchedule
          containers:
          - name: log-pilot
            # 版本请参考https://github.com/AliyunContainerService/log-pilot/releases。
            image: heleicool/log-pilot:7.x-filebeat
            resources:
              limits:
                memory: 500Mi
              requests:
                cpu: 200m
                memory: 200Mi
            env:
              - name: "NODE_NAME"
                valueFrom:
                  fieldRef:
                    fieldPath: spec.nodeName
              - name: "LOGGING_OUTPUT"
                value: "elasticsearch"
              # 请确保集群到ES网络可达。
              - name: "ELASTICSEARCH_HOSTS"
                value: "elasticsearch:9200"
              # 配置ES访问权限。
             # - name: "ELASTICSEARCH_USER"
            #    value: "{es_username}"
             # - name: "ELASTICSEARCH_PASSWORD"
             #   value: "{es_password}"
            volumeMounts:
            - name: sock
              mountPath: /var/run/docker.sock
            - name: root
              mountPath: /host
              readOnly: true
            - name: varlib
              mountPath: /var/lib/filebeat
            - name: varlog
              mountPath: /var/log/filebeat
            - name: localtime
              mountPath: /etc/localtime
              readOnly: true
            livenessProbe:
              failureThreshold: 3
              exec:
                command:
                - /pilot/healthz
              initialDelaySeconds: 10
              periodSeconds: 10
              successThreshold: 1
              timeoutSeconds: 2
            securityContext:
              capabilities:
                add:
                - SYS_ADMIN
          terminationGracePeriodSeconds: 30
          volumes:
          - name: sock
            hostPath:
              path: /var/run/docker.sock
          - name: root
            hostPath:
              path: /
          - name: varlib
            hostPath:
              path: /var/lib/filebeat
              type: DirectoryOrCreate
          - name: varlog
            hostPath:
              path: /var/log/filebeat
              type: DirectoryOrCreate
          - name: localtime
            hostPath:
              path: /etc/localtime
    

    默认阿里云仓库只支持7.x以下版本es的数据写入,使用如下插件可以实现。
    git地址:https://github.com/40kuai/log-pilot/tree/filebeat7.x
    dockerhub:heleicool/log-pilot:7.x-filebeat

    服务日志采集

    创建一个标准的 Nginx 服务, 主要是 env 添加了两种,上面我们介绍过

    一 是 基于 docker stdout 输出日志 (aliyun_logs_catalina)

    二 是 基于 程序指定输出到指定的目录中 (aliyun_logs_access)

    ( elasticsearch )环境变量中的 name表示Index,这里name 表示 Index,这里 name表示Index,这里name 即是 catalina 和 access, 这里用于 Kibana 查询日志

     nginx.yaml

    apiVersion: apps/v1
    kind: Deployment 
    metadata: 
      name: nginx-dm
    spec: 
      replicas: 3
      selector:
        matchLabels:
          name: nginx
      template: 
        metadata: 
          labels: 
            name: nginx 
        spec: 
          tolerations:
            - key: "node-role.kubernetes.io/master"
              effect: "NoSchedule"
          containers: 
            - name: nginx 
              image: nginx:alpine 
              imagePullPolicy: IfNotPresent
              env:
               - name: aliyun_logs_nginx-log
                 value: "stdout"
               - name: aliyun_logs_access
                 value: "/var/log/nginx/*.log"
              ports:
                - containerPort: 80
                  name: http
    ---
    apiVersion: v1 
    kind: Service
    metadata: 
      name: nginx-svc 
    spec: 
      ports: 
        - port: 80
          name: http
          targetPort: 80
          protocol: TCP 
      selector: 
        name: nginx
    

     

    pod.yaml

    [root@master01 new]# cat pod2.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: counter
      namespace: logging  #可以添加空间名称,也会收集到的
    spec:
      containers:
      - name: count
        image: busybox
        args: [/bin/sh, -c,
                'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
        env:
        # 1、stdout为约定关键字,表示采集标准输出日志。
        # 2、配置标准输出日志采集到ES的catalina索引下。
        - name: aliyun_logs_catalina
          value: "stdout"
        # 1、配置采集容器内文件日志,支持通配符。
        # 2、配置该日志采集到ES的access索引下。
    

    tomcat.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: tomcat
    spec:
      containers:
      - name: tomcat
        image: "tomcat:7.0"
        env:
        # 1、stdout为约定关键字,表示采集标准输出日志。
        # 2、配置标准输出日志采集到ES的catalina索引下。
        - name: aliyun_logs_catalina
          value: "stdout"
        # 1、配置采集容器内文件日志,支持通配符。
        # 2、配置该日志采集到ES的access索引下。
        - name: aliyun_logs_access
          value: "/usr/local/tomcat/logs/catalina.*.log"
        # 容器内文件日志路径需要配置emptyDir。
        volumeMounts:
          - name: tomcat-log
            mountPath: /usr/local/tomcat/logs
      volumes:
        - name: tomcat-log
          emptyDir: {}
    

     k8s 部署 log-pilot 收集容器标准输出日志和指定路径应用日志 - lixinliang - 博客园

  • 相关阅读:
    Ansible中文权威指南学习
    gitlab
    Python-Day01-task
    Python-Day01
    CentOs6.7 python2.6升级到2.7.11
    网站访问慢排查方法及解决方案
    LAMP环境下zabbix安装配置
    监控知识点概述
    Java抽象类、接口和内部类
    Java 访问控制
  • 原文地址:https://www.cnblogs.com/heian99/p/15998574.html
Copyright © 2020-2023  润新知