使用Log-Pilot + logstash+Elasticsearch + Kibana 收集 kubernetes 日志

╰半橙微兮° 2022-01-06 01:59 476阅读 0赞

开发者在面对 Kubernetes 分布式集群下的日志需求时,常常会感到头疼,既有容器自身特性的原因,也有现有日志采集工具的桎梏,主要包括:

容器本身特性:

采集目标多:容器本身的特性导致采集目标多,需要采集容器内日志、容器 stdout。对于容器内部的文件日志采集,现在并没有一个很好的工具能够去动态发现采集。针对每种数据源都有对应的采集软件,但缺乏一站式的工具。

弹性伸缩难*:Kubernetes 是分布式的集群,服务、环境的弹性伸缩对于日志采集带来了很大的困难,无法像传统虚拟机环境下那样,事先配置好日志的采集路径等信息,采集的动态性以及数据完整性是非常大的挑战。

现有日志工具的一些缺陷

缺乏动态配置的能力。目前的采集工具都需要事先手动配置好日志采集方式和路径等信息,因为它无法能够自动感知到容器的生命周期变化或者动态漂移,所以它无法动态地去配置。

日志采集重复或丢失的问题。因为现在的一些采集工具基本上是通过 tail 的方式来进行日志采集的,那么这里就可能存在两个方面的问题:一个是可能导致日志丢失,比如采集工具在重启的过程中,而应用依然在写日志,那么就有可能导致这个窗口期的日志丢失;而对于这种情况一般保守的做法就是,默认往前多采集 1M 日志或 2M 的日志,那么这就又会可能引起日志采集重复的问题。

未明确标记日志源。因为一个应用可能有很多个容器,输出的应用日志也是一样的,那么当我们将所有应用日志收集到统一日志存储后端时,在搜索日志的时候,我们就无法明确这条日志具体是哪一个节点上的哪一个应用容器产生的。
本文档将介绍一种 Docker 日志收集工具 Log-Pilot,结合 Elasticsearch 和 Kibana、logstash 等工具,形成一套适用于 Kubernetes 环境下的一站式日志解决方案。

Log-Pilot 介绍

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

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

目前 log-pilot 在 Github 完全开源,项目地址是 https://github.com/AliyunContainerService/log-pilot 。您可以深入了解更多实现原理。

针对容器日志的声明式配置

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

在 Kubernetes 下,Log-Pilot 可以依据环境变量 aliyun_logs_$name = $path 动态地生成日志采集配置文件,其中包含两个变量:

$name 是我们自定义的一个字符串,它在不同的场景下指代不同的含义,在本场景中,将日志采集到 ElasticSearch 的时候,这个 $name 表示的是 Index。
另一个是 KaTeX parse error: Expected group after ‘_‘ at position 420: …,通过 aliyun_logs_̲name_format= 标签就可以告诉 Log-Pilot 在采集日志的时候,同时以什么样的格式来解析日志记录,支持的格式包括:none、json、csv、nginx、apache2 和 regxp。

Log-Pilot 同时支持自定义 tag,我们可以在环境变量里配置 aliyun_logs_$name_tags=“K1=V1,K2=V2”,那么在采集日志的时候也会将 K1=V1 和 K2=V2 采集到容器的日志输出中。自定义 tag 可帮助您给日志产生的环境打上 tag,方便进行日志统计、日志路由和日志过滤。

实战部分

架构:log-polit —> logstash —> es —> kibana

准备工作

1.k8s 集群 搭建。(略)
2.logstash 环境搭建。(略)
3.es集群(略)
4.kibana 展示端(略)
已上准备工作不是本篇文章的重点,不做论述。

log-pilot 以pod 的形式部署在k8s上
  1. cat log-pilot-DaemonSet.yaml
  2. apiVersion: extensions/v1beta1
  3. kind: DaemonSet
  4. metadata:
  5. name: log-pilot
  6. labels:
  7. app: log-pilot
  8. # 设置期望部署的namespace
  9. namespace: kube-system
  10. spec:
  11. updateStrategy:
  12. type: RollingUpdate
  13. template:
  14. metadata:
  15. labels:
  16. app: log-pilot
  17. annotations:
  18. scheduler.alpha.kubernetes.io/critical-pod: ''
  19. spec:
  20. # 是否允许部署到Master节点上
  21. tolerations:
  22. - key: node-role.kubernetes.io/master
  23. effect: NoSchedule
  24. containers:
  25. - name: log-pilot
  26. # 版本请参考https://github.com/AliyunContainerService/log-pilot/releases
  27. image: registry.cn-hangzhou.aliyuncs.com/acs/log-pilot:0.9.6-filebeat
  28. resources:
  29. limits:
  30. memory: 500Mi
  31. requests:
  32. cpu: 200m
  33. memory: 200Mi
  34. env:
  35. - name: "NODE_NAME"
  36. valueFrom:
  37. fieldRef:
  38. fieldPath: spec.nodeName
  39. - name: "LOGGING_OUTPUT"
  40. value: "logstash"
  41. # 请确保集群到ES网络可达
  42. - name: "LOGSTASH_HOST"
  43. value: "192.168.6.48"
  44. - name: "LOGSTASH_PORT"
  45. value: "5044"
  46. - name: "LOGSTASH_LOADBALANCE"
  47. value: "true"
  48. volumeMounts:
  49. - name: sock
  50. mountPath: /var/run/docker.sock
  51. - name: root
  52. mountPath: /host
  53. readOnly: true
  54. - name: varlib
  55. mountPath: /var/lib/filebeat
  56. - name: varlog
  57. mountPath: /var/log/filebeat
  58. - name: localtime
  59. mountPath: /etc/localtime
  60. readOnly: true
  61. livenessProbe:
  62. failureThreshold: 3
  63. exec:
  64. command:
  65. - /pilot/healthz
  66. initialDelaySeconds: 10
  67. periodSeconds: 10
  68. successThreshold: 1
  69. timeoutSeconds: 2
  70. securityContext:
  71. capabilities:
  72. add:
  73. - SYS_ADMIN
  74. terminationGracePeriodSeconds: 30
  75. volumes:
  76. - name: sock
  77. hostPath:
  78. path: /var/run/docker.sock
  79. - name: root
  80. hostPath:
  81. path: /
  82. - name: varlib
  83. hostPath:
  84. path: /var/lib/filebeat
  85. type: DirectoryOrCreate
  86. - name: varlog
  87. hostPath:
  88. path: /var/log/filebeat
  89. type: DirectoryOrCreate
  90. - name: localtime
  91. hostPath:
  92. path: /etc/localtime

其中
LOGGING_OUTPUT 是使用logstash接收log-pilot接收到的日志
LOGSTASH_HOST logstash服务的ip地址
LOGSTASH_PORT logstash服务的端口
LOGSTASH_LOADBALANCE 是否为logstash开启负载均衡模式

  1. $ kubectl create -f log-pilot-DaemonSet.yaml
  2. $ kubectl get pod --namespace=kube-system |grep log-pilot
  3. log-pilot-9kkvs 1/1 Running 0 56m
  4. log-pilot-nspdv 1/1 Running 0 56m
  5. log-pilot-sszk7 1/1 Running 0 56m

进到容器里面可以看到的进程

  1. $ kubectl exec -it log-pilot-nspdv sh -n kube-system
  2. /pilot # ps -ef
  3. PID USER TIME COMMAND
  4. 1 root 0:03 /pilot/pilot -template /pilot/filebeat.tpl -base /host -log-level debug
  5. 19 root 0:50 /usr/bin/filebeat -c /etc/filebeat/filebeat.yml
  6. 3535 root 0:00 sh
  7. 3551 root 0:00 ps -ef
  8. ## 自动生成的filebeat yaml文件
  9. /pilot # cat /etc/filebeat/filebeat.yml
  10. path.config: /etc/filebeat
  11. path.logs: /var/log/filebeat
  12. path.data: /var/lib/filebeat/data
  13. filebeat.registry_file: /var/lib/filebeat/registry
  14. filebeat.shutdown_timeout: 0
  15. logging.level: info
  16. logging.metrics.enabled: false
  17. logging.files.rotateeverybytes: 104857600
  18. logging.files.keepfiles: 10
  19. logging.files.permissions: 0600
  20. setup.template.name: "filebeat"
  21. setup.template.pattern: "filebeat-*"
  22. filebeat.config:
  23. prospectors:
  24. enabled: true
  25. path: ${path.config}/prospectors.d/*.yml
  26. reload.enabled: true
  27. reload.period: 10s
  28. output.logstash:
  29. hosts: ["192.168.6.48:5044"]
  30. index: filebeat-%{+yyyy.MM.dd}
  31. loadbalance: true

收集日志端准备好了,开始收集业务日志了。

收集业务日志

应用是用springboot 写的 这里启动一个java应用。yaml文件如下:

  1. $ cat deploy.yaml
  2. apiVersion: extensions/v1beta1
  3. kind: Deployment
  4. metadata:
  5. name: prexx-xx-account-web-profile-a
  6. spec:
  7. replicas: 1
  8. template:
  9. metadata:
  10. labels:
  11. app: prexx-xx-account-web-profile-a
  12. profile: profile-a
  13. spec:
  14. volumes:
  15. - name: "cephfs-fuse"
  16. hostPath:
  17. path: "/data/WEBLOG"
  18. - name: "preproductnfs"
  19. hostPath:
  20. path: "/home/nfs"
  21. containers:
  22. - name: prexx-xx-account-web-profile-a
  23. image: harbor.reg/pre_xx/prexx-xx-account-web:32
  24. imagePullPolicy: IfNotPresent
  25. volumeMounts:
  26. - name: cephfs-fuse
  27. mountPath: /data/WEBLOG
  28. - name: preproductnfs
  29. mountPath: /home/nfs
  30. resources:
  31. limits:
  32. memory: 2000Mi
  33. requests:
  34. memory: 1500Mi
  35. ports:
  36. - containerPort: 8080
  37. env:
  38. - name: app_name
  39. value: prexx-xx-account-web
  40. - name: aliyun_logs_catalina
  41. value: "stdout"
  42. - name: aliyun_logs_catalina_tags
  43. value: "logtype=prexx-xx-account-web,env=prexx"
  44. - name: aliyun_logs_logstash-htjf
  45. value: "/data/WEBLOG/prexx-xx-account-web/*/*.log"
  46. - name: aliyun_logs_logstash-htjf_tags
  47. value: "logtype=prexx-xx-account-web,env=prexx"
  48. livenessProbe:
  49. failureThreshold: 3
  50. exec:
  51. command:
  52. - /healthz
  53. initialDelaySeconds: 10
  54. periodSeconds: 10
  55. successThreshold: 1
  56. timeoutSeconds: 2

其中
aliyun_logs_logstash-htjf 指向收集日志的路径
aliyun_logs_logstash-htjf_tags 为收集的日志添加tag

启动应用

  1. $ kunerctl create -f deploy.yaml
  2. $ kubectl get pod prexx-xx-account-web-profile-a-5bf9c8947f-gbhpg
  3. NAME READY STATUS RESTARTS AGE
  4. prexx-xx-account-web-profile-a-5bf9c8947f-gbhpg 1/1 Running 0 1m

配置logstash 文件

根据日志打印格式 (和开发要求日志的打印格式尽量一致,方便收集)定义日志过滤模版。
debugger 地址:https://grokdebug.herokuapp.com/ 需要梯子

在这里插入图片描述
日志过滤匹配的模版为

  1. %{TIMESTAMP_ISO8601:timestamp}\s+\[%{THREADID_1:threadId}\]\s+%{LOGLEVEL:level}\s+%{JAVACLASS:JAVACLASS}\s+\-\s+%{JAVAMESSAGE:javameassage}

创建logstash文件 接收log-pilot 传过来的日志

  1. cat xx_spring_boot.conf
  2. input {
  3. beats {
  4. port => "5044"
  5. codec=> multiline {
  6. pattern => "^%{YEAR}.*"
  7. negate => true
  8. what => "previous"
  9. }
  10. }
  11. }
  12. filter {
  13. grok {
  14. patterns_dir => [ "/etc/logstash/patterns.d" ]
  15. match => [ "message", "%{TIMESTAMP_ISO8601:timestamp}\s+\[%{THREADID:threadId}\]\s+\[%{THREADNAME:traceId}\]\s+%{LOGLEVEL:level}\s+%{JAVACLASS:javaclass}\s+\-\s+%{JAVAMESSAGE:javameassage}","message", "%{TIMESTAMP_ISO8601:timestamp}\s+\[%{THREADID_1:threadId}\]\s+%{LOGLEVEL:level}\s+%{JAVACLASS:javaclass}\s+\-\s+%{JAVAMESSAGE:javameassage}"]
  16. remove_field => [ "message","beat","timestamp","topic","hostname","name"]
  17. }
  18. date {
  19. match => ["time", "dd/MMM/yyyy:HH:mm:ss Z"]
  20. locale => "cn"
  21. }
  22. }
  23. output {
  24. elasticsearch {
  25. hosts => ["192.168.6.17:9200","192.168.6.18:9200","192.168.6.19:9200"]
  26. index => "logstash-htjf-filebeat-%{+YYYY-MM}"
  27. user => elastic
  28. password => xx
  29. }
  30. stdout { codec => rubydebug }
  31. }

启动logstash

  1. /usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/xx_spring_boot.conf --path.data=/var/log/xx_spring_boot.log & > /dev/null

通过kibana 展示收集的日志

在这里插入图片描述
通过全局环境变量传进来的tag 也展示出来了。

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,476人围观)

还没有评论,来说两句吧...

相关阅读