应用日志收集

前言

在进行日志收集的过程中,我们首先想到的是使用Logstash,因为它是ELK stack中的重要成员,但是在测试过程中发现,Logstash是基于JDK的,在没有产生日志的情况单纯启动Logstash就大概要消耗500M内存,在每个Pod中都启动一个日志收集组件的情况下,使用logstash有点浪费系统资源,经人推荐我们选择使用Filebeat替代,经测试单独启动Filebeat容器大约会消耗12M内存,比起logstash相当轻量级。

方案选择

Kubernetes官方提供了EFK的日志收集解决方案,但是这种方案并不适合所有的业务场景,它本身就有一些局限性,例如:

  • 所有日志都必须是out前台输出,真实业务场景中无法保证所有日志都在前台输出
  • 只能有一个日志输出文件,而真实业务场景中往往有多个日志输出文件
  • Fluentd并不是常用的日志收集工具,我们更习惯用logstash,现使用filebeat替代
  • 我们已经有自己的ELK集群且有专人维护,没有必要再在kubernetes上做一个日志收集服务

基于以上几个原因,我们决定使用自己的ELK集群。

Kubernetes集群中的日志收集解决方案

编号 方案 优点 缺点
1 每个app的镜像中都集成日志收集组件 部署方便,kubernetes的yaml文件无须特别配置,可以为每个app自定义日志收集配置 强耦合,不方便应用和日志收集组件升级和维护且会导致镜像过大
2 单独创建一个日志收集组件跟app的容器一起运行在同一个pod中 低耦合,扩展性强,方便维护和升级 需要对kubernetes的yaml文件进行单独配置,略显繁琐
3 将所有的Pod的日志都挂载到宿主机上,每台主机上单独起一个日志收集Pod 完全解耦,性能最高,管理起来最方便 需要统一日志收集规则,目录和输出方式

综合以上优缺点,我们选择使用方案二。

该方案在扩展性、个性化、部署和后期维护方面都能做到均衡,因此选择该方案。

filebeat日志收集架构图

我们创建了自己的filebeat镜像。创建过程和使用方式见https://github.com/rootsongjc/docker-images

镜像地址:index.tenxcloud.com/jimmy/filebeat:5.4.0

测试

我们部署一个应用filebeat来收集日志的功能测试。

创建应用yaml文件filebeat-test.yaml

  1. apiVersion: extensions/v1beta1
  2. kind: Deployment
  3. metadata:
  4. name: filebeat-test
  5. namespace: default
  6. spec:
  7. replicas: 3
  8. template:
  9. metadata:
  10. labels:
  11. k8s-app: filebeat-test
  12. spec:
  13. containers:
  14. - image: sz-pg-oam-docker-hub-001.tendcloud.com/library/filebeat:5.4.0
  15. name: filebeat
  16. volumeMounts:
  17. - name: app-logs
  18. mountPath: /log
  19. - name: filebeat-config
  20. mountPath: /etc/filebeat/
  21. - image: sz-pg-oam-docker-hub-001.tendcloud.com/library/analytics-docker-test:Build_8
  22. name : app
  23. ports:
  24. - containerPort: 80
  25. volumeMounts:
  26. - name: app-logs
  27. mountPath: /usr/local/TalkingData/logs
  28. volumes:
  29. - name: app-logs
  30. emptyDir: {}
  31. - name: filebeat-config
  32. configMap:
  33. name: filebeat-config
  34. ---
  35. apiVersion: v1
  36. kind: Service
  37. metadata:
  38. name: filebeat-test
  39. labels:
  40. app: filebeat-test
  41. spec:
  42. ports:
  43. - port: 80
  44. protocol: TCP
  45. name: http
  46. selector:
  47. run: filebeat-test
  48. ---
  49. apiVersion: v1
  50. kind: ConfigMap
  51. metadata:
  52. name: filebeat-config
  53. data:
  54. filebeat.yml: |
  55. filebeat.prospectors:
  56. - input_type: log
  57. paths:
  58. - "/log/*"
  59. - "/log/usermange/common/*"
  60. output.elasticsearch:
  61. hosts: ["172.23.5.255:9200"]
  62. username: "elastic"
  63. password: "changeme"
  64. index: "filebeat-docker-test"

说明

该文件中包含了配置文件filebeat的配置文件的ConfigMap,因此不需要再定义环境变量。

当然你也可以不同ConfigMap,通过传统的传递环境变量的方式来配置filebeat。

例如对filebeat的容器进行如下配置:

  1. containers:
  2. - image: sz-pg-oam-docker-hub-001.tendcloud.com/library/filebeat:5.4.0
  3. name: filebeat
  4. volumeMounts:
  5. - name: app-logs
  6. mountPath: /log
  7. env:
  8. - name: PATHS
  9. value: "/log/*"
  10. - name: ES_SERVER
  11. value: 172.23.5.255:9200
  12. - name: INDEX
  13. value: logstash-docker
  14. - name: INPUT_TYPE
  15. value: log

目前使用这种方式会有个问题,及时PATHS只能传递单个目录,如果想传递多个目录需要修改filebeat镜像的docker-entrypoint.sh脚本,对该环境变量进行解析增加filebeat.yml文件中的PATHS列表。

推荐使用ConfigMap,这样filebeat的配置就能够更灵活。

注意事项

  • 将app的/usr/local/TalkingData/logs目录挂载到filebeat的/log目录下。
  • 该文件可以在manifests/test/filebeat-test.yaml找到。
  • 我使用了自己的私有镜像仓库,测试时请换成自己的应用镜像。
  • Filebeat的环境变量的值配置请参考https://github.com/rootsongjc/docker-images

创建应用

部署Deployment

  1. kubectl create -f filebeat-test.yaml

查看http://172.23.5.255:9200/_cat/indices将可以看到列表有这样的indices:

  1. green open filebeat-docker-test 7xPEwEbUQRirk8oDX36gAA 5 1 2151 0 1.6mb 841.8kb

访问Kibana的web页面,查看filebeat-2017.05.17的索引,可以看到filebeat收集到了app日志。

Kibana页面

点开没个日志条目,可以看到以下详细字段:

filebeat收集的日志详细信息

  • _index值即我们在YAML文件的configMap中配置的index值
  • beat.hostnamebeat.name即pod的名称
  • source表示filebeat容器中的日志目录

我们可以通过人为得使index = service name,这样就可以方便的收集和查看每个service的日志。