主要内容

  • 1 ELK概念

  • 2 K8S需要收集哪些日志

  • 3 ELK Stack日志方案

  • 4 容器中的日志怎么收集

  • 5 K8S平台中应用日志收集

准备环境

一套正常运行的k8s集群,kubeadm安装部署或者二进制部署即可

ip地址 角色 备注
192.168.73.136 nfs
192.168.73.138 k8s-master
192.168.73.139 k8s-node01
192.168.73.140 k8s-node02

1 ELK 概念

ELK是Elasticsearch、Logstash、Kibana三大开源框架首字母大写简称。市面上也被成为Elastic Stack。其中Elasticsearch是一个基于Lucene、分布式、通过Restful方式进行交互的近实时搜索平台框架。像类似百度、谷歌这种大数据全文搜索引擎的场景都可以使用Elasticsearch作为底层支持框架,可见Elasticsearch提供的搜索能力确实强大,市面上很多时候我们简称Elasticsearch为es。Logstash是ELK的中央数据流引擎,用于从不同目标(文件/数据存储/MQ)收集的不同格式数据,经过过滤后支持输出到不同目的地(文件/MQ/redis/elasticsearch/kafka等)。Kibana可以将elasticsearch的数据通过友好的页面展示出来,提供实时分析的功能。

通过上面对ELK简单的介绍,我们知道了ELK字面意义包含的每个开源框架的功能。市面上很多开发只要提到ELK能够一致说出它是一个日志分析架构技术栈总称,但实际上ELK不仅仅适用于日志分析,它还可以支持其它任何数据分析和收集的场景,日志分析和收集只是更具有代表性。并非唯一性。我们本教程主要也是围绕通过ELK如何搭建一个生产级的日志分析平台来讲解ELK的使用。

官方网站:https://www.elastic.co/cn/products/

2 日志管理平台

在过往的单体应用时代,我们所有组件都部署到一台服务器中,那时日志管理平台的需求可能并没有那么强烈,我们只需要登录到一台服务器通过shell命令就可以很方便的查看系统日志,并快速定位问题。随着互联网的发展,互联网已经全面渗入到生活的各个领域,使用互联网的用户量也越来越多,单体应用已不能够支持庞大的用户的并发量,尤其像中国这种人口大国。那么将单体应用进行拆分,通过水平扩展来支持庞大用户的使用迫在眉睫,微服务概念就是在类似这样的阶段诞生,在微服务盛行的互联网技术时代,单个应用被拆分为多个应用,每个应用集群部署进行负载均衡,那么如果某项业务发生系统错误,开发或运维人员还是以过往单体应用方式登录一台一台登录服务器查看日志来定位问题,这种解决线上问题的效率可想而知。日志管理平台的建设就显得极其重要。通过Logstash去收集每台服务器日志文件,然后按定义的正则模板过滤后传输到Kafka或redis,然后由另一个Logstash从KafKa或redis读取日志存储到elasticsearch中创建索引,最后通过Kibana展示给开发者或运维人员进行分析。这样大大提升了运维线上问题的效率。除此之外,还可以将收集的日志进行大数据分析,得到更有价值的数据给到高层进行决策。

3 K8S需要收集哪些日志

这里只是以主要收集日志为例:

  • K8S系统的组件日志
  • K8S Cluster里面部署的应用程序日志

    -标准输出

    -日志文件

4 K8S中的ELK Stack日志采集方案

  • 方案一:Node上部署一个日志收集程序

    使用DaemonSet的方式去给每一个node上部署日志收集程序logging-agent

    然后使用这个agent对本node节点上的/var/log和/var/lib/docker/containers/两个目录下的日志进行采集

    或者把Pod中容器日志目录挂载到宿主机统一目录上,这样进行收集

  • 方案二:Pod中附加专用日志收集的容器

    每个运行应用程序的Pod中增加一个日志收集容器,使用emtyDir共享日志目录让日志收集程序读取到。

  • 方案三:应用程序直接推送日志

    这个方案需要开发在代码中修改直接把应用程序直接推送到远程的存储上,不再输入出控制台或者本地文件了,使用不太多,超出Kubernetes范围

方式 优点 缺点
方案一:Node上部署一个日志收集程序 每个Node仅需部署一个日志收集程序,资源消耗少,对应用无侵入 应用程序日志需要写到标准输出和标准错误输出,不支持多行日志
方案二:Pod中附加专用日志收集的容器 低耦合 每个Pod启动一个日志收集代理,增加资源消耗,并增加运维维护成本
方案三:应用程序直接推送日志 无需额外收集工具 浸入应用,增加应用复杂度

5 单节点方式部署ELK

单节点部署ELK的方法较简单,可以参考下面的yaml编排文件,整体就是创建一个es,然后创建kibana的可视化展示,创建一个es的service服务,然后通过ingress的方式对外暴露域名访问

首先,编写es的yaml,这里部署的是单机版,在k8s集群内中,通常当日志量每天超过20G以上的话,还是建议部署在k8s集群外部,支持分布式集群的架构,这里使用的是有状态部署的方式,并且使用动态存储进行持久化,需要提前创建好存储类,才能运行该yaml

  1. [root@k8s-master fek]# vim elasticsearch.yaml
  2. apiVersion: apps/v1
  3. kind: StatefulSet
  4. metadata:
  5. name: elasticsearch
  6. namespace: kube-system
  7. labels:
  8. k8s-app: elasticsearch
  9. spec:
  10. serviceName: elasticsearch
  11. selector:
  12. matchLabels:
  13. k8s-app: elasticsearch
  14. template:
  15. metadata:
  16. labels:
  17. k8s-app: elasticsearch
  18. spec:
  19. containers:
  20. - image: elasticsearch:7.3.1
  21. name: elasticsearch
  22. resources:
  23. limits:
  24. cpu: 1
  25. memory: 2Gi
  26. requests:
  27. cpu: 0.5
  28. memory: 500Mi
  29. env:
  30. - name: "discovery.type"
  31. value: "single-node"
  32. - name: ES_JAVA_OPTS
  33. value: "-Xms512m -Xmx2g"
  34. ports:
  35. - containerPort: 9200
  36. name: db
  37. protocol: TCP
  38. volumeMounts:
  39. - name: elasticsearch-data
  40. mountPath: /usr/share/elasticsearch/data
  41. volumeClaimTemplates:
  42. - metadata:
  43. name: elasticsearch-data
  44. spec:
  45. storageClassName: "managed-nfs-storage"
  46. accessModes: [ "ReadWriteOnce" ]
  47. resources:
  48. requests:
  49. storage: 20Gi
  50. ---
  51. apiVersion: v1
  52. kind: Service
  53. metadata:
  54. name: elasticsearch
  55. namespace: kube-system
  56. spec:
  57. clusterIP: None
  58. ports:
  59. - port: 9200
  60. protocol: TCP
  61. targetPort: db
  62. selector:
  63. k8s-app: elasticsearch

使用刚才编写好的yaml文件创建Elasticsearch,然后检查是否启动,如下所示能看到一个elasticsearch-0 的pod副本被创建,正常运行;如果不能正常启动可以使用kubectl describe查看详细描述,排查问题

  1. [root@k8s-master fek]# kubectl get pod -n kube-system
  2. NAME READY STATUS RESTARTS AGE
  3. coredns-5bd5f9dbd9-95flw 1/1 Running 0 17h
  4. elasticsearch-0 1/1 Running 1 16m
  5. php-demo-85849d58df-4bvld 2/2 Running 2 18h
  6. php-demo-85849d58df-7tbb2 2/2 Running 0 17h

然后,需要部署一个Kibana来对搜集到的日志进行可视化展示,使用Deployment的方式编写一个yaml,使用ingress对外进行暴露访问,直接引用了es

  1. [root@k8s-master fek]# vim kibana.yaml
  2. apiVersion: apps/v1
  3. kind: Deployment
  4. metadata:
  5. name: kibana
  6. namespace: kube-system
  7. labels:
  8. k8s-app: kibana
  9. spec:
  10. replicas: 1
  11. selector:
  12. matchLabels:
  13. k8s-app: kibana
  14. template:
  15. metadata:
  16. labels:
  17. k8s-app: kibana
  18. spec:
  19. containers:
  20. - name: kibana
  21. image: kibana:7.3.1
  22. resources:
  23. limits:
  24. cpu: 1
  25. memory: 500Mi
  26. requests:
  27. cpu: 0.5
  28. memory: 200Mi
  29. env:
  30. - name: ELASTICSEARCH_HOSTS
  31. value: http://elasticsearch:9200
  32. ports:
  33. - containerPort: 5601
  34. name: ui
  35. protocol: TCP
  36. ---
  37. apiVersion: v1
  38. kind: Service
  39. metadata:
  40. name: kibana
  41. namespace: kube-system
  42. spec:
  43. ports:
  44. - port: 5601
  45. protocol: TCP
  46. targetPort: ui
  47. selector:
  48. k8s-app: kibana
  49. ---
  50. apiVersion: extensions/v1beta1
  51. kind: Ingress
  52. metadata:
  53. name: kibana
  54. namespace: kube-system
  55. spec:
  56. rules:
  57. - host: kibana.ctnrs.com
  58. http:
  59. paths:
  60. - path: /
  61. backend:
  62. serviceName: kibana
  63. servicePort: 5601

使用刚才编写好的yaml创建kibana,可以看到最后生成了一个kibana-b7d98644-lshsz的pod,并且正常运行

  1. [root@k8s-master fek]# kubectl apply -f kibana.yaml
  2. deployment.apps/kibana created
  3. service/kibana created
  4. ingress.extensions/kibana created
  5. [root@k8s-master fek]# kubectl get pod -n kube-system
  6. NAME READY STATUS RESTARTS AGE
  7. coredns-5bd5f9dbd9-95flw 1/1 Running 0 17h
  8. elasticsearch-0 1/1 Running 1 16m
  9. kibana-b7d98644-48gtm 1/1 Running 1 17h
  10. php-demo-85849d58df-4bvld 2/2 Running 2 18h
  11. php-demo-85849d58df-7tbb2 2/2 Running 0 17h

最后,需要编写yaml在每个node上创建一个ingress-nginx控制器来对外提供访问

  1. [root@k8s-master demo2]# vim mandatory.yaml
  2. apiVersion: v1
  3. kind: Namespace
  4. metadata:
  5. name: ingress-nginx
  6. labels:
  7. app.kubernetes.io/name: ingress-nginx
  8. app.kubernetes.io/part-of: ingress-nginx
  9. ---
  10. kind: ConfigMap
  11. apiVersion: v1
  12. metadata:
  13. name: nginx-configuration
  14. namespace: ingress-nginx
  15. labels:
  16. app.kubernetes.io/name: ingress-nginx
  17. app.kubernetes.io/part-of: ingress-nginx
  18. ---
  19. kind: ConfigMap
  20. apiVersion: v1
  21. metadata:
  22. name: tcp-services
  23. namespace: ingress-nginx
  24. labels:
  25. app.kubernetes.io/name: ingress-nginx
  26. app.kubernetes.io/part-of: ingress-nginx
  27. ---
  28. kind: ConfigMap
  29. apiVersion: v1
  30. metadata:
  31. name: udp-services
  32. namespace: ingress-nginx
  33. labels:
  34. app.kubernetes.io/name: ingress-nginx
  35. app.kubernetes.io/part-of: ingress-nginx
  36. ---
  37. apiVersion: v1
  38. kind: ServiceAccount
  39. metadata:
  40. name: nginx-ingress-serviceaccount
  41. namespace: ingress-nginx
  42. labels:
  43. app.kubernetes.io/name: ingress-nginx
  44. app.kubernetes.io/part-of: ingress-nginx
  45. ---
  46. apiVersion: rbac.authorization.k8s.io/v1beta1
  47. kind: ClusterRole
  48. metadata:
  49. name: nginx-ingress-clusterrole
  50. labels:
  51. app.kubernetes.io/name: ingress-nginx
  52. app.kubernetes.io/part-of: ingress-nginx
  53. rules:
  54. - apiGroups:
  55. - ""
  56. resources:
  57. - configmaps
  58. - endpoints
  59. - nodes
  60. - pods
  61. - secrets
  62. verbs:
  63. - list
  64. - watch
  65. - apiGroups:
  66. - ""
  67. resources:
  68. - nodes
  69. verbs:
  70. - get
  71. - apiGroups:
  72. - ""
  73. resources:
  74. - services
  75. verbs:
  76. - get
  77. - list
  78. - watch
  79. - apiGroups:
  80. - ""
  81. resources:
  82. - events
  83. verbs:
  84. - create
  85. - patch
  86. - apiGroups:
  87. - "extensions"
  88. - "networking.k8s.io"
  89. resources:
  90. - ingresses
  91. verbs:
  92. - get
  93. - list
  94. - watch
  95. - apiGroups:
  96. - "extensions"
  97. - "networking.k8s.io"
  98. resources:
  99. - ingresses/status
  100. verbs:
  101. - update
  102. ---
  103. apiVersion: rbac.authorization.k8s.io/v1beta1
  104. kind: Role
  105. metadata:
  106. name: nginx-ingress-role
  107. namespace: ingress-nginx
  108. labels:
  109. app.kubernetes.io/name: ingress-nginx
  110. app.kubernetes.io/part-of: ingress-nginx
  111. rules:
  112. - apiGroups:
  113. - ""
  114. resources:
  115. - configmaps
  116. - pods
  117. - secrets
  118. - namespaces
  119. verbs:
  120. - get
  121. - apiGroups:
  122. - ""
  123. resources:
  124. - configmaps
  125. resourceNames:
  126. # Defaults to "<election-id>-<ingress-class>"
  127. # Here: "<ingress-controller-leader>-<nginx>"
  128. # This has to be adapted if you change either parameter
  129. # when launching the nginx-ingress-controller.
  130. - "ingress-controller-leader-nginx"
  131. verbs:
  132. - get
  133. - update
  134. - apiGroups:
  135. - ""
  136. resources:
  137. - configmaps
  138. verbs:
  139. - create
  140. - apiGroups:
  141. - ""
  142. resources:
  143. - endpoints
  144. verbs:
  145. - get
  146. ---
  147. apiVersion: rbac.authorization.k8s.io/v1beta1
  148. kind: RoleBinding
  149. metadata:
  150. name: nginx-ingress-role-nisa-binding
  151. namespace: ingress-nginx
  152. labels:
  153. app.kubernetes.io/name: ingress-nginx
  154. app.kubernetes.io/part-of: ingress-nginx
  155. roleRef:
  156. apiGroup: rbac.authorization.k8s.io
  157. kind: Role
  158. name: nginx-ingress-role
  159. subjects:
  160. - kind: ServiceAccount
  161. name: nginx-ingress-serviceaccount
  162. namespace: ingress-nginx
  163. ---
  164. apiVersion: rbac.authorization.k8s.io/v1beta1
  165. kind: ClusterRoleBinding
  166. metadata:
  167. name: nginx-ingress-clusterrole-nisa-binding
  168. labels:
  169. app.kubernetes.io/name: ingress-nginx
  170. app.kubernetes.io/part-of: ingress-nginx
  171. roleRef:
  172. apiGroup: rbac.authorization.k8s.io
  173. kind: ClusterRole
  174. name: nginx-ingress-clusterrole
  175. subjects:
  176. - kind: ServiceAccount
  177. name: nginx-ingress-serviceaccount
  178. namespace: ingress-nginx
  179. ---
  180. apiVersion: apps/v1
  181. kind: DaemonSet
  182. metadata:
  183. name: nginx-ingress-controller
  184. namespace: ingress-nginx
  185. labels:
  186. app.kubernetes.io/name: ingress-nginx
  187. app.kubernetes.io/part-of: ingress-nginx
  188. spec:
  189. selector:
  190. matchLabels:
  191. app.kubernetes.io/name: ingress-nginx
  192. app.kubernetes.io/part-of: ingress-nginx
  193. template:
  194. metadata:
  195. labels:
  196. app.kubernetes.io/name: ingress-nginx
  197. app.kubernetes.io/part-of: ingress-nginx
  198. annotations:
  199. prometheus.io/port: "10254"
  200. prometheus.io/scrape: "true"
  201. spec:
  202. serviceAccountName: nginx-ingress-serviceaccount
  203. hostNetwork: true
  204. containers:
  205. - name: nginx-ingress-controller
  206. image: lizhenliang/nginx-ingress-controller:0.20.0
  207. args:
  208. - /nginx-ingress-controller
  209. - --configmap=$(POD_NAMESPACE)/nginx-configuration
  210. - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
  211. - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
  212. - --publish-service=$(POD_NAMESPACE)/ingress-nginx
  213. - --annotations-prefix=nginx.ingress.kubernetes.io
  214. securityContext:
  215. allowPrivilegeEscalation: true
  216. capabilities:
  217. drop:
  218. - ALL
  219. add:
  220. - NET_BIND_SERVICE
  221. # www-data -> 33
  222. runAsUser: 33
  223. env:
  224. - name: POD_NAME
  225. valueFrom:
  226. fieldRef:
  227. fieldPath: metadata.name
  228. - name: POD_NAMESPACE
  229. valueFrom:
  230. fieldRef:
  231. fieldPath: metadata.namespace
  232. ports:
  233. - name: http
  234. containerPort: 80
  235. - name: https
  236. containerPort: 443
  237. livenessProbe:
  238. failureThreshold: 3
  239. httpGet:
  240. path: /healthz
  241. port: 10254
  242. scheme: HTTP
  243. initialDelaySeconds: 10
  244. periodSeconds: 10
  245. successThreshold: 1
  246. timeoutSeconds: 10
  247. readinessProbe:
  248. failureThreshold: 3
  249. httpGet:
  250. path: /healthz
  251. port: 10254
  252. scheme: HTTP
  253. periodSeconds: 10
  254. successThreshold: 1
  255. timeoutSeconds: 10
  256. ---

创建ingress控制器,可以看到使用的DaemonSet 的方式在每一个node都部署了ingress控制器,我们可以在本地host中绑定任意一个node ip,然后使用域名都可以访问

  1. [root@k8s-master demo2]# kubectl apply -f mandatory.yaml
  2. [root@k8s-master demo2]# kubectl get pod -n ingress-nginx
  3. NAME READY STATUS RESTARTS AGE
  4. nginx-ingress-controller-98769 1/1 Running 6 13h
  5. nginx-ingress-controller-n6wpq 1/1 Running 0 13h
  6. nginx-ingress-controller-tbfxq 1/1 Running 29 13h
  7. nginx-ingress-controller-trxnj 1/1 Running 6 13h

绑定本机hosts,访问域名验证

windows系统,hosts文件地址:C:\Windows\System32\drivers\etc,Mac系统sudo vi /private/etc/hosts 编辑hosts文件,在底部加入域名和ip,用于解析,这个ip地址为任意node节点ip地址

加入如下命令,然后保存

  1. 192.168.73.139 kibana.ctnrs.com

最后在浏览器中,输入kibana.ctnrs.com,就会进入kibana的web界面,已设置了不需要进行登陆,当前页面都是全英文模式,可以修改上网搜一下修改配置文件的位置,建议使用英文版本

5.1 方案一:Node上部署一个filebeat采集器采集k8s组件日志

es和kibana部署好了之后,我们如何采集pod日志呢,我们采用方案一的方式,首先在每一个node上中部署一个filebeat的采集器,采用的是7.3.1版本,因为filebeat是对k8s有支持,可以连接api给pod日志打标签,所以yaml中需要进行认证,最后在配置文件中对获取数据采集了之后输入到es中,已在yaml中配置好

  1. [root@k8s-master fek]# vim filebeat-kubernetes.yaml
  2. ---
  3. apiVersion: v1
  4. kind: ConfigMap
  5. metadata:
  6. name: filebeat-config
  7. namespace: kube-system
  8. labels:
  9. k8s-app: filebeat
  10. data:
  11. filebeat.yml: |-
  12. filebeat.config:
  13. inputs:
  14. # Mounted `filebeat-inputs` configmap:
  15. path: ${path.config}/inputs.d/*.yml
  16. # Reload inputs configs as they change:
  17. reload.enabled: false
  18. modules:
  19. path: ${path.config}/modules.d/*.yml
  20. # Reload module configs as they change:
  21. reload.enabled: false
  22. # To enable hints based autodiscover, remove `filebeat.config.inputs` configuration and uncomment this:
  23. #filebeat.autodiscover:
  24. # providers:
  25. # - type: kubernetes
  26. # hints.enabled: true
  27. output.elasticsearch:
  28. hosts: ['${ELASTICSEARCH_HOST:elasticsearch}:${ELASTICSEARCH_PORT:9200}']
  29. ---
  30. apiVersion: v1
  31. kind: ConfigMap
  32. metadata:
  33. name: filebeat-inputs
  34. namespace: kube-system
  35. labels:
  36. k8s-app: filebeat
  37. data:
  38. kubernetes.yml: |-
  39. - type: docker
  40. containers.ids:
  41. - "*"
  42. processors:
  43. - add_kubernetes_metadata:
  44. in_cluster: true
  45. ---
  46. apiVersion: extensions/v1beta1
  47. kind: DaemonSet
  48. metadata:
  49. name: filebeat
  50. namespace: kube-system
  51. labels:
  52. k8s-app: filebeat
  53. spec:
  54. template:
  55. metadata:
  56. labels:
  57. k8s-app: filebeat
  58. spec:
  59. serviceAccountName: filebeat
  60. terminationGracePeriodSeconds: 30
  61. containers:
  62. - name: filebeat
  63. image: elastic/filebeat:7.3.1
  64. args: [
  65. "-c", "/etc/filebeat.yml",
  66. "-e",
  67. ]
  68. env:
  69. - name: ELASTICSEARCH_HOST
  70. value: elasticsearch
  71. - name: ELASTICSEARCH_PORT
  72. value: "9200"
  73. securityContext:
  74. runAsUser: 0
  75. # If using Red Hat OpenShift uncomment this:
  76. #privileged: true
  77. resources:
  78. limits:
  79. memory: 200Mi
  80. requests:
  81. cpu: 100m
  82. memory: 100Mi
  83. volumeMounts:
  84. - name: config
  85. mountPath: /etc/filebeat.yml
  86. readOnly: true
  87. subPath: filebeat.yml
  88. - name: inputs
  89. mountPath: /usr/share/filebeat/inputs.d
  90. readOnly: true
  91. - name: data
  92. mountPath: /usr/share/filebeat/data
  93. - name: varlibdockercontainers
  94. mountPath: /var/lib/docker/containers
  95. readOnly: true
  96. volumes:
  97. - name: config
  98. configMap:
  99. defaultMode: 0600
  100. name: filebeat-config
  101. - name: varlibdockercontainers
  102. hostPath:
  103. path: /var/lib/docker/containers
  104. - name: inputs
  105. configMap:
  106. defaultMode: 0600
  107. name: filebeat-inputs
  108. # data folder stores a registry of read status for all files, so we don't send everything again on a Filebeat pod restart
  109. - name: data
  110. hostPath:
  111. path: /var/lib/filebeat-data
  112. type: DirectoryOrCreate
  113. ---
  114. apiVersion: rbac.authorization.k8s.io/v1beta1
  115. kind: ClusterRoleBinding
  116. metadata:
  117. name: filebeat
  118. subjects:
  119. - kind: ServiceAccount
  120. name: filebeat
  121. namespace: kube-system
  122. roleRef:
  123. kind: ClusterRole
  124. name: filebeat
  125. apiGroup: rbac.authorization.k8s.io
  126. ---
  127. apiVersion: rbac.authorization.k8s.io/v1beta1
  128. kind: ClusterRole
  129. metadata:
  130. name: filebeat
  131. labels:
  132. k8s-app: filebeat
  133. rules:
  134. - apiGroups: [""] # "" indicates the core API group
  135. resources:
  136. - namespaces
  137. - pods
  138. verbs:
  139. - get
  140. - watch
  141. - list
  142. ---
  143. apiVersion: v1
  144. kind: ServiceAccount
  145. metadata:
  146. name: filebeat
  147. namespace: kube-system
  148. labels:
  149. k8s-app: filebeat
  150. ---

使用编写好的yaml文件创建filebeat采集器,然后检查是否启动,如果不能正常启动可以使用kubectl describe查看详细描述,排查问题

  1. [root@k8s-master fek]# kubectl apply -f filebeat-kubernetes.yaml
  2. configmap/filebeat-config created
  3. configmap/filebeat-inputs created
  4. daemonset.extensions/filebeat created
  5. clusterrolebinding.rbac.authorization.k8s.io/filebeat created
  6. clusterrole.rbac.authorization.k8s.io/filebeat created
  7. serviceaccount/filebeat created
  8. [root@k8s-master fek]# ls
  9. elasticsearch.yaml filebeat-kubernetes.yaml kibana.yaml
  10. [root@k8s-master fek]# kubectl get pod -n kube-system
  11. NAME READY STATUS RESTARTS AGE
  12. alertmanager-5d75d5688f-fmlq6 2/2 Running 11 58d
  13. coredns-5bd5f9dbd9-rv7ft 1/1 Running 2 47d
  14. filebeat-2dlk8 1/1 ContainerCreating 0 27s
  15. filebeat-cqvmk 1/1 ContainerCreating 0 27s
  16. filebeat-s2xmm 1/1 ContainerCreating 0 28s
  17. filebeat-w28qc 1/1 ContainerCreating 0 27s
  18. grafana-0 1/1 Running 5 64d
  19. kube-state-metrics-7c76bdbf68-48b7w 2/2 Running 4 47d
  20. kubernetes-dashboard-7d77666777-d5ng4 1/1 Running 9 65d
  21. prometheus-0 2/2 Running 2 47d

需要对k8s组件的日志进行采集,因为我的环境是用的kubeadm进行部署的,因此我的组件日志都在/var/log/message里面,因此我们还需要部署一个采集k8s组件日志的pod副本,自定义了索引k8s-module-%{+yyyy.MM.dd},编写yaml如下:

  1. [root@k8s-master elk]# vim k8s-logs.yaml
  2. apiVersion: v1
  3. kind: ConfigMap
  4. metadata:
  5. name: k8s-logs-filebeat-config
  6. namespace: kube-system
  7. data:
  8. filebeat.yml: |
  9. filebeat.inputs:
  10. - type: log
  11. paths:
  12. - /var/log/messages
  13. fields:
  14. app: k8s
  15. type: module
  16. fields_under_root: true
  17. setup.ilm.enabled: false
  18. setup.template.name: "k8s-module"
  19. setup.template.pattern: "k8s-module-*"
  20. output.elasticsearch:
  21. hosts: ['elasticsearch.kube-system:9200']
  22. index: "k8s-module-%{+yyyy.MM.dd}"
  23. ---
  24. apiVersion: apps/v1
  25. kind: DaemonSet
  26. metadata:
  27. name: k8s-logs
  28. namespace: kube-system
  29. spec:
  30. selector:
  31. matchLabels:
  32. project: k8s
  33. app: filebeat
  34. template:
  35. metadata:
  36. labels:
  37. project: k8s
  38. app: filebeat
  39. spec:
  40. containers:
  41. - name: filebeat
  42. image: elastic/filebeat:7.3.1
  43. args: [
  44. "-c", "/etc/filebeat.yml",
  45. "-e",
  46. ]
  47. resources:
  48. requests:
  49. cpu: 100m
  50. memory: 100Mi
  51. limits:
  52. cpu: 500m
  53. memory: 500Mi
  54. securityContext:
  55. runAsUser: 0
  56. volumeMounts:
  57. - name: filebeat-config
  58. mountPath: /etc/filebeat.yml
  59. subPath: filebeat.yml
  60. - name: k8s-logs
  61. mountPath: /var/log/messages
  62. volumes:
  63. - name: k8s-logs
  64. hostPath:
  65. path: /var/log/messages
  66. - name: filebeat-config
  67. configMap:
  68. name: k8s-logs-filebeat-config

创建编写好的yaml,并且检查是否成功创建,能看到两个命名为k8s-log-xx的pod副本分别创建在两个nodes上

  1. [root@k8s-master elk]# kubectl apply -f k8s-logs.yaml
  2. [root@k8s-master elk]# kubectl get pod -n kube-system
  3. NAME READY STATUS RESTARTS AGE
  4. coredns-5bd5f9dbd9-8zdn5 1/1 Running 0 10h
  5. elasticsearch-0 1/1 Running 1 13h
  6. filebeat-2q5tz 1/1 Running 0 13h
  7. filebeat-k6m27 1/1 Running 2 13h
  8. k8s-logs-52xgk 1/1 Running 0 5h45m
  9. k8s-logs-jpkqp 1/1 Running 0 5h45m
  10. kibana-b7d98644-tllmm 1/1 Running 0 10h

5.1.1 在kibana的web界面进行配置日志可视化

首先打开kibana的web界面,点击左边菜单栏汇中的设置,然后点击在Kibana下面的索引按钮,然后点击左上角的然后根据如图所示分别创建一个filebeat-7.3.1-和k8s-module-的filebeat采集器的索引匹配

然后按照时间过滤,完成创建

索引匹配创建以后,点击左边最上面的菜单Discove,然后可以在左侧看到我们刚才创建的索引,然后就可以在下面添加要展示的标签,也可以对标签进行筛选,最终效果如图所示,可以看到采集到的日志的所有信息

在其中一个node上,输入echo hello logs >>/var/log/messages,然后在web上选择k8s-module-*的索引匹配,就可以在采集到的日志中看到刚才输入的hello logs,则证明采集成功,如图所示

5.2 方案二:Pod中附加专用日志收集的容器

我们也可以使用方案的方式,通过在pod中注入一个日志收集的容器来采集pod的日志,以一个php-demo的应用为例,使用emptyDir的方式把日志目录共享给采集器的容器收集,编写nginx-deployment.yaml ,直接在pod中加入filebeat的容器,并且自定义索引为nginx-access-%{+yyyy.MM.dd}

  1. [root@k8s-master fek]# vim nginx-deployment.yaml
  2. apiVersion: apps/v1beta1
  3. kind: Deployment
  4. metadata:
  5. name: php-demo
  6. namespace: kube-system
  7. spec:
  8. replicas: 2
  9. selector:
  10. matchLabels:
  11. project: www
  12. app: php-demo
  13. template:
  14. metadata:
  15. labels:
  16. project: www
  17. app: php-demo
  18. spec:
  19. imagePullSecrets:
  20. - name: registry-pull-secret
  21. containers:
  22. - name: nginx
  23. image: lizhenliang/nginx-php
  24. ports:
  25. - containerPort: 80
  26. name: web
  27. protocol: TCP
  28. resources:
  29. requests:
  30. cpu: 0.5
  31. memory: 256Mi
  32. limits:
  33. cpu: 1
  34. memory: 1Gi
  35. livenessProbe:
  36. httpGet:
  37. path: /status.html
  38. port: 80
  39. initialDelaySeconds: 20
  40. timeoutSeconds: 20
  41. readinessProbe:
  42. httpGet:
  43. path: /status.html
  44. port: 80
  45. initialDelaySeconds: 20
  46. timeoutSeconds: 20
  47. volumeMounts:
  48. - name: nginx-logs
  49. mountPath: /usr/local/nginx/logs
  50. - name: filebeat
  51. image: elastic/filebeat:7.3.1
  52. args: [
  53. "-c", "/etc/filebeat.yml",
  54. "-e",
  55. ]
  56. resources:
  57. limits:
  58. memory: 500Mi
  59. requests:
  60. cpu: 100m
  61. memory: 100Mi
  62. securityContext:
  63. runAsUser: 0
  64. volumeMounts:
  65. - name: filebeat-config
  66. mountPath: /etc/filebeat.yml
  67. subPath: filebeat.yml
  68. - name: nginx-logs
  69. mountPath: /usr/local/nginx/logs
  70. volumes:
  71. - name: nginx-logs
  72. emptyDir: {}
  73. - name: filebeat-config
  74. configMap:
  75. name: filebeat-nginx-config
  76. ---
  77. apiVersion: v1
  78. kind: ConfigMap
  79. metadata:
  80. name: filebeat-nginx-config
  81. namespace: kube-system
  82. data:
  83. filebeat.yml: |-
  84. filebeat.inputs:
  85. - type: log
  86. paths:
  87. - /usr/local/nginx/logs/access.log
  88. # tags: ["access"]
  89. fields:
  90. app: www
  91. type: nginx-access
  92. fields_under_root: true
  93. setup.ilm.enabled: false
  94. setup.template.name: "nginx-access"
  95. setup.template.pattern: "nginx-access-*"
  96. output.elasticsearch:
  97. hosts: ['elasticsearch.kube-system:9200']
  98. index: "nginx-access-%{+yyyy.MM.dd}"

创建刚才编写的nginx-deployment.yaml,创建成果之后会在kube-system命名空间下面pod/web-demo-58d89c9bc4-r5692的2个pod副本,还有一个对外暴露的service/web-demo

  1. [root@k8s-master elk]# kubectl apply -f nginx-deployment.yaml
  2. [root@k8s-master fek]# kubectl get pod -n kube-system
  3. NAME READY STATUS RESTARTS AGE
  4. coredns-5bd5f9dbd9-8zdn5 1/1 Running 0 20h
  5. elasticsearch-0 1/1 Running 1 23h
  6. filebeat-46nvd 1/1 Running 0 23m
  7. filebeat-sst8m 1/1 Running 0 23m
  8. k8s-logs-52xgk 1/1 Running 0 15h
  9. k8s-logs-jpkqp 1/1 Running 0 15h
  10. kibana-b7d98644-tllmm 1/1 Running 0 20h
  11. php-demo-85849d58df-d98gv 2/2 Running 0 26m
  12. php-demo-85849d58df-sl5ss 2/2 Running 0 26m

然后打开kibana的web,按照刚才的办法继续添加一个索引匹配nginx-access-*,如图所示

最后点击左边最上面的菜单Discove,然后可以在左侧看到我们刚才创建的索引匹配,下拉选择nginx-access-*,然后就可以在下面添加要展示的标签,也可以对标签进行筛选,最终效果如图所示,可以看到采集到的日志的所有信息,可以使用 http://node ip+30001的访问访问一下刚才创建的nginx,然后测试是否有日志产生

专注开源的DevOps技术栈技术,可以关注公众号,有问题欢迎一起交流

Kubernetes实战之部署ELK Stack收集平台日志的更多相关文章

  1. 被一位读者赶超,手摸手 Docker 部署 ELK Stack

    被一位读者赶超,容器化部署 ELK Stack 你好,我是悟空. 被奇幻"催更" 最近有个读者,他叫"老王",外号"茴香豆泡酒",找我崔更 ...

  2. ELK Stack (2) —— ELK + Redis收集Nginx日志

    ELK Stack (2) -- ELK + Redis收集Nginx日志 摘要 使用Elasticsearch.Logstash.Kibana与Redis(作为缓冲区)对Nginx日志进行收集 版本 ...

  3. ELK Stack 介绍 & Logstash 日志收集

    ELK Stack 组成 Software Description Function E:Elasticsearch Java 程序 存储,查询日志 L:Logstash Java 程序 收集.过滤日 ...

  4. ELK之收集haproxy日志

    由于HAProxy的运行信息不写入日志文件,但它依赖于标准的系统日志协议将日志发送到远程服务器(通常位于同一系统上),所以需要借助rsyslog来收集haproxy的日志.haproxy代理nginx ...

  5. ELK之收集Java日志、通过TCP收集日志

    1.Java日志收集 使用codec的multiline插件实现多行匹配,这是一个可以将多行进行合并的插件,而且可以使用what指定将匹配到的行与前面的行合并还是和后面的行合并. 语法示例: inpu ...

  6. kubernetes实战之部署一个接近生产环境的consul集群

    系列目录 前面我们介绍了如何在windows单机以及如何基于docker部署consul集群,看起来也不是很复杂,然而如果想要把consul部署到kubernetes集群中并充分利用kubernete ...

  7. ELK技术实战-安装Elk 5.x平台

    ELK技术实战–了解Elk各组件   转载  http://www.ywnds.com/?p=9776 ELK技术实战-部署Elk 2.x平台 ELK Stack是软件集合Elasticsearch. ...

  8. ELK Stack部署

    部署ELK Stack 官网:https://www.elastic.co 环境准备: ip hostname 服务 用户.组 192.168.20.3 node2003 kibana6.5,file ...

  9. ELK:收集Docker容器日志

    简介 之前写过一篇博客 ELK:日志收集分析平台,介绍了在Centos7系统上部署配置使用ELK的方法,随着容器化时代的到来,容器化部署成为一种很方便的部署方式,收集容器日志也成为刚需.本篇文档从 容 ...

随机推荐

  1. Redisson分布式锁学习总结:可重入锁 RedissonLock#lock 获取锁源码分析

    原文:Redisson分布式锁学习总结:可重入锁 RedissonLock#lock 获取锁源码分析 一.RedissonLock#lock 源码分析 1.根据锁key计算出 slot,一个slot对 ...

  2. springboot的build.gradle增加阿里仓库地址以及eclipse增加lombok

    该随笔仅限自己记录,请谨慎参考!! 为什么把这2块内容放一个标题里? 发现lombok和eclipse结合的一些问题 关于lombok如何与eclipse结合,网上应该有很多教程,我这块已经做过了,但 ...

  3. RSA非对称加密算法实现:Python

    RSA是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.当时他们三人都在麻省理工学院工作.RSA ...

  4. shell2-if判断2

    1.条件判断if 判断条件:then //单分支语句 命令1 命令2fi 例子: #!/bin/bash ls if [ $? -eq 0 ]; then echo "执行成功了" ...

  5. unittest_测试报告(6)

    用例执行完成后,执行结果默认是输出在屏幕上,其实我们可以把结果输出到一个文件中,形成测试报告. unittest自带的测试报告是文本形式的,如下代码: import unittest if __nam ...

  6. go.mod file not found in current directory or any parent directory; see 'go help modules'

    go的环境设置问题,执行 go env -w GO111MODULE=auto 我的环境:Windows 7, Go 1.17 D:\Apps\GOPATH\src\code.oldboyedu.co ...

  7. angularJS中$digest already in progress报错解决方法

    看到一个前端群里有人问,就查了下解决"$digest already in progress"最好的方式,就是不要使用$scope.$apply()或者$scope.$digest ...

  8. 使用Swing的GUI编程

    Swing AWT概述 AWT:抽象窗口工具包,提供了一套与本地图形界面进行交互的接口,是Java提供的用来建立和设置Java的图形用户界面的基本工具 Swing以AWT为基础的,尽管Swing消除了 ...

  9. Kube-OVN 1.2.0发布,携手社区成员打造高性能容器网络

    Kube-OVN 1.2.0 新版本如期而至,支持 Vlan 和 OVS-DPDK 两种类型的高性能网络接口.本次发布得益于社区的壮大,感谢Intel爱尔兰开发团队与锐捷网络开发团队持续积极参与Kub ...

  10. XRecyclerView:实现下拉刷新、滚动到底部加载更多以及添加header功能的RecyclerView

    介绍: 一个实现了下拉刷新,滚动到底部加载更多以及添加header功能的的RecyclerView.使用方式和RecyclerView完全一致,不需要额外的layout,不需要写特殊的adater. ...