基于AWS EKS的K8S实践 - 日志方案解决

2023-08-23 10:14:13 浏览数 (2)

Hi~朋友,关注置顶防止错过消息

基于AWS EKS的K8S实践系列文章是基于企业级的实战文章,一些设置信息需要根据公司自身要求进行设置,如果大家有问题讨论或咨询可以加我微信(公众号后台回复 程序员修炼笔记 可获取联系方式)。

当前日志的解决方案

  1. 传统 EFK
  2. 云供应商提供的日志平台(比如阿里的 SLS 、 CloudWatch)

云供应商的平台一般都可以通过 SDK 的方式进行投递解决,所以其实无关乎我们的应用部署方式,只要按照云供应商的所需配置进行配置即可。

今天我们主要说一下如果是自建的 ES 的日志的收集方案的解决。

Kubernetes的日志收集的集中方案

  1. 在每个节点上运行一个收集的agent,该agent负责采集节点上的所有日志,这种通常就是DaemonSet
  2. Sidecar容器:为每个Pod运行一个日志代理容器,该Agent容器只负责当前Pod内的业务日志的收集
  3. 直接将应用程序的日志推送到采集后端

关于第一种方案这种方案虽然可以降低资源的消耗(无需为每个 Pod 配置一个 Sidecar 容器),但是他的灵活程度比较低,因为在我们实际的使用场景中,每个日志推送到es 的 index 名称往往不同,并且日志保存周期也可能不同,而 Sidecar 可以根据每个 Pod 进行定制化相对灵活,当然最灵活的方式还是第三种,这种方式无关乎你的底层服务架构,都是基于 HTTP 或者 RPC 进行的数据的直接推送。

Sidecar 容器的解决方案

  1. 准备我们filebeat的配置文件,这里我们通过 ConfigMap准备,如下:
代码语言:javascript复制
kind: ConfigMap
 
apiVersion: v1
 
metadata:
 
  name: xxx-internal-filebeat-config
 
namespace: application-test
 
data:
 
  filebeat.yml: |
 
    filebeat.inputs:
 
- type: filestream
 
      paths:
 
- "/docker/log/*.log"
 
      parsers:
 
- multiline:
 
            type: pattern
 
            pattern: '^d{4}-d{2}-d{2}sd{2}:d{2}:d{2}.d{3}'
 
            negate: true
 
            match: after
 
      fields:
 
        project: xxx-internal
 
        env: test
 
      pipeline: ys-application-log-pipeline
 
    output.elasticsearch:
 
      hosts: ["test.es.xxx.com:9200"]
 
      indices:
 
- index: "%{[fields.project]}-%{[fields.env]}-%{ yyyy.MM.dd}"
 
  • paths: 收集的 log 日志文件的路径
  • multiline:确保将多行日志(如堆栈异常)作为一个完整文档发送
  • multiline.pattern:用来指定要匹配的正则表达式模式,根据你配置其他多行选项的方式,与指定正则表达式匹配的行将被视为上一行的延续或新多行事件的开始
  • multiline.negate:定义是否为否定模式,也就是和上面定义的模式相反,默认为false
  • multiline.match: 指定Filebeat如何将匹配的行组合到事件中,设置在之后(after)或之前(before)

我上面的配置的含义就是代表了我的日志开头是个时间戳,在logback中的配置是%d{yyyy-MM-dd HH:mm:ss.SSS},如果不以yyyy-MM-dd HH:mm:ss.SSS开始的连续行将会被追加到匹配的前一行。

  • fields:指定添加一些其他属性,这里我增加了project和 env
  • pipeline:用于指定Ingest pipeline,这里会在日志投递到 es 之前对日志进行清洗过滤转换,Ingest pipeline会在 ES 的 Ingest Node 上进行处理

Ingest Node相比 LogStash 的缺点主要是他的输出只能到 ES(不能再输出到 Kafka 队列),没有缓冲机制,不像 LogStash 有缓冲机制在一定程度上可以防止数据的丢失,其次是他支持的 Processor 相对较少,没有 LogStash 种类丰富,但在我们的使用场景下,日志量没有明显的波峰,而且我们的日志写到 es的情况下我这里就直接利用Ingest pipeline进行处理,这样也会少一个 LogStash 组件的维护,这里牵涉到一个技术选型的核心思想:在你的人力和基础系统不够扎实的前提下,一定要将你的技术架构简单化,组件越少越好,以最低成本的最合适的方式满足你的当下需求,整的花里胡哨没用只是皮毛而且也会增加运维人员开发人员的负担,系统先跑起来,其次稳下来,最后投入一定的人力开发基础系统(包含 DevOps 、监控),这些支持系统虽然不能为公司带来明面上的收益,但是他是提高研发效率,保障系统跑的快跑的好提高问题排查效率的关键。

  • output.elasticsearch.indices:指定我们投递到 es的 index 名称

ys-application-log-pipeline用做什么?

es 的里面的时间默认是 filebeat 投递日志的时间,不是日志里面的时间,我们的有些应用对这个时间比较敏感,必须是日志里面的时间,因此ys-application-log-pipeline主要做的就是将日志里面的时间取出来,单独再存储到一个field 中,方便进行排序查询。

代码语言:javascript复制
PUT _ingest/pipeline/ys-application-log-pipeline
 
{
 
"processors": [
 
{
 
"grok": {
 
"field": "message",
 
"patterns": [
 
"%{MY_DATETIME:log_time}"
 
],
 
"pattern_definitions": {
 
"MY_DATE": "%{YEAR}[/-]%{MONTHNUM}[/-]%{MONTHDAY}",
 
"MY_TIME": "[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9]",
 
"MY_DATETIME": "%{MY_DATE} %{MY_TIME}"
 
}
 
}
 
},
 
{
 
"date": {
 
"field": "log_time",
 
"formats": [
 
"yyyy-MM-dd HH:mm:ss.SSS"
 
],
 
"target_field": "log_time",
 
"output_format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
 
}
 
},
 
{
 
"script": {
 
"lang": "painless",
 
"source": "String datetime = ctx.log_time;nZonedDateTime zdt = ZonedDateTime.parse(datetime);nzdt = zdt.minusHours(7);nctx.log_time = zdt;"
 
}
 
},
 
{
 
"date": {
 
"field": "log_time",
 
"formats": [
 
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
 
],
 
"target_field": "log_time",
 
"output_format": "yyyy-MM-dd HH:mm:ss.SSS"
 
}
 
}
 
]
 
}
 

Deployments配置

代码语言:javascript复制
apiVersion: apps/v1
 
kind: Deployment
 
metadata:
 
namespace: application-test
 
  name: xxx-internal
 
  labels:
 
    app: xxx-internal
 
spec:
 
...
 
template:
 
    metadata:
 
      labels:
 
        app: xxx-internal
 
    spec:
 
      restartPolicy: Always
 
      containers:
 
- name: xxx-internal
 
          image: DEPLOY_IMAGE
 
          imagePullPolicy: Always
 
....
 
          volumeMounts:
 
- mountPath: /docker/log
 
              name: application-log
 
- name: filebeat
 
          image: docker.elastic.co/beats/filebeat:8.6.1
 
          imagePullPolicy: Always
 
          volumeMounts:
 
- name: application-log
 
              mountPath: /docker/log
 
- name: filebeat-config
 
              mountPath: /usr/share/filebeat/filebeat.yml
 
              subPath: filebeat.yml
 
      volumes:
 
- name: application-log
 
          emptyDir: {}
 
- name: filebeat-config
 
          configMap:
 
            name: xxx-internal-filebeat-config
 
            items:
 
- key: filebeat.yml
 
                path: filebeat.yml

可以看到在我们的 Pod 中我们除了本身的业务应用容器,我们还启动了一个fielbeat 容器专门用来收集我们的业务日志,具体的关于 Volume 的挂载后续我这边有时间单独写,这里就不专门写了,熟悉 Kubernetes 的同学肯定不会陌生,经过上述配置我们的业务日志就会被投递到我们的 es 中。

0 人点赞