参考来源:
- 课程随堂笔记: Kubernetes全栈架构师:基于世界500强的k8s实战课程
- EFK GitHub 地址: fluentd-elasticsearch
- 实验所需文件仓库地址: k8s.git
EFK(ElasticSearch + Fluentd + Kibana)
EFK 是用于 Kubernetes 集群的日志收集工具,我们可以根据自己的业务情况,选择日志收集工具,比如还可以选择以 Sidecar 形式运行在 Pod 中的 Filebeat。这里介绍持久化安装 EFK 至 Kubernetes 集群,用于收集集群的相关日志,但是在生产环境中不建议将 EFK 安装到 Kubernetes 集群中,可以选择安装在集群之外,也可以将日志输出到外部的 ES 集群。
部署 ElasticSearch + Fluentd + Kibana
本次实验的环境如下,服务器可用资源 4 核 8G,Kubernetes 集群版本信息如下
1
2
3
4
5
6
7# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master-01 Ready master 32d v1.21.3
k8s-master-02 Ready master 32d v1.21.3
k8s-master-03 Ready master 32d v1.21.3
k8s-node-01 Ready node 32d v1.21.3
k8s-node-02 Ready node 32d v1.21.3下载部署 EFK 需要的文件
1
git clone https://github.com/dotbalo/k8s.git
创建 EFK 所用的 Namespace
1
2# kubectl create -f create-logging-namespace.yaml
namespace/logging created创建 ElasticSearch 集群(企业已有 ELK 平台的可以不创建)
1
2
3
4
5
6
7
8# kubectl create -f es-service.yaml
service/elasticsearch-logging created
# kubectl create -f es-statefulset.yaml # 这里默认使用的是 emptyDir 作为数据持久化,生产环境记得需要修改持久化配置
serviceaccount/elasticsearch-logging created
clusterrole.rbac.authorization.k8s.io/elasticsearch-logging created
clusterrolebinding.rbac.authorization.k8s.io/elasticsearch-logging created
statefulset.apps/elasticsearch-logging created查看资源是否已创建
1
2
3
4
5
6
7
8# kubectl get service -n logging
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
elasticsearch-logging ClusterIP None <none> 9200/TCP,9300/TCP 5m19s
# kubectl get pods -n logging
NAME READY STATUS RESTARTS AGE
elasticsearch-logging-0 1/1 Running 0 3m7s
elasticsearch-logging-1 1/1 Running 0 87s部署 Kibana(企业内已有 ELK 平台的可以不创建)
1
2
3
4
5# kubectl create -f kibana-deployment.yaml
deployment.apps/kibana-logging created
# kubectl create -f kibana-service.yaml
service/kibana-logging created部署 Fluentd,由于在 Kubernetes 集群中,我们可能并不需要对所有的机器都采集日志,所以可以更改 Fluentd 的部署文件,添加一个 NodeSelector,如下所示:
1
2
3
4
5
6
7
8# grep "nodeSelector" fluentd-es-ds.yaml -A3 -B2
...
timeoutSeconds: 10
terminationGracePeriodSeconds: 30
nodeSelector:
fluentd: "true"
volumes:
- name: varlog之后,在给需要部署 Fluentd 的节点上打上标签,以 k8s-node-01 为例,如下所示
1
2
3# kubectl get nodes -l fluentd=true --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-node-01 Ready node 32d v1.21.3 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,fluentd=true,ingress=true,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node-01,kubernetes.io/os=linux,node-role.kubernetes.io/node=,node.kubernetes.io/node=创建 Fluentd
1
2
3
4
5
6# kubectl create -f fluentd-es-ds.yaml -f fluentd-es-configmap.yaml
serviceaccount/fluentd-es created
clusterrole.rbac.authorization.k8s.io/fluentd-es created
clusterrolebinding.rbac.authorization.k8s.io/fluentd-es created
daemonset.apps/fluentd-es-v3.1.1 created
configmap/fluentd-es-config-v0.2.1 created注意 Fluentd 的 ConfigMap 中有个字段需要注意,在 fluentd-es-configmap.yaml 的最后有一个 output.conf 配置,注意其中的 host,是 ElasticSearch 的 Service 名称
1
2
3
4
5
6
7output.conf: |-
<match **>
....
host elasticsearch-logging
port 9200
....
</match>查看 kinbana 服务以及访问
1
2
3
4# kubectl get svc -n logging
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
elasticsearch-logging ClusterIP None <none> 9200/TCP,9300/TCP 47m
kibana-logging NodePort 10.100.128.91 <none> 5601:31841/TCP 39m如上所示,访问
http://192.168.55.110:31841/kibana
既可访问 Kibana 的 web 页面。关于 Kibana 的使用请参考官网
使用 Filebeat 收集自定义文件日志
创建 kafka 和 Logstash
首先需要部署 kafka 和 logstash 至 Kubernetes 集群,如果企业内已经有比较成熟的技术栈,可以无需部署,直接将 Filebeat 的输出指向外部的 kafka 集群即可:
1
2
3
4
5
6
7
8
9
10# cd k8s/efk-7.10.2/filebeat
# helm install zookeeper zookeeper/ -n logging # 安装 zookeeper
# kubectl get pods -n logging -l app.kubernetes.io/name=zookeeper
NAME READY STATUS RESTARTS AGE
zookeeper-0 1/1 Running 0 82s
# helm install kafka kafka/ -n logging # 安装 Kafka
# kubectl get pods -n logging -l app.kubernetes.io/component=kafka
NAME READY STATUS RESTARTS AGE
kafka-0 1/1 Running 0 4m2s当所有 Pod 都正常后,创建 logstash 服务
1
2
3
4# kubectl create -f logstash-service.yaml -f logstash-cm.yaml -f logstash.yaml -n logging
service/logstash-service created
configmap/logstash-configmap created
deployment.apps/logstash-deployment created需要注意 logstash-cm.yaml 文件中的一些配置:
- input: 数据来源,本次示例配置的是 kafka
- input.kafka.bootstrap_servers: kafka 的地址,由于是安装在集群内,可以直接使用 kafka 集群的 Service 接口,如果是外部地址,按需配置既可;
- input.kafka.topics: Kafka 的 topic,需要和 Filebeat 输出的 topic 一致;
- input.kafka.type: 定义一个 type,可以用于 logstash 输出至不同的 Elasticsearch 集群;
- output: 数据输出至哪里,本次示例输出至 Elasticsearch 集群,在里面配置了一个判断语句,当 type 为 filebeat-sidecar 时,将会输出至 Elasticsearch 集群,并且索引为 filebeat-xxx。
注入 Filebeat Sidecar
当应用的日志没有输出到控制台,而是被输出到一个文件中时,此时可以使用 Filebeat 进行采集。以下示例会创建一个模拟程序,该程序会在 /opt/date.log 文件输出当前日志,配置如下:
1 | command: |
创建模拟程序
1
2
3# cd k8s/efk-7.10.2/filebeat
# kubectl create -f app.yaml -n logging
deployment.apps/app created查看 deployment 状态,以及 pod 的日志
1
2
3
4
5
6# kubectl get pods -n logging
NAME READY STATUS RESTARTS AGE
app-6dd64bdc55-rvrkq 1/1 Running 0 55s
# kubectl exec -ti -n logging app-6dd64bdc55-rvrkq -- tail -1 /opt/date.log
Tue Oct 26 03:49:12 UTC 2021
如果此时去 kibana 查看该日志,是无法查看到该日志的,因为 Fluentd 无法采集内部的日志文件。接下来改造该程序
添加一个 Filebeat 至该部署文件,如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62...
spec:
nodeSelector:
fluentd: "true"
containers:
- name: app
image: registry.cn-beijing.aliyuncs.com/dotbalo/alpine:3.6
imagePullPolicy: IfNotPresent
volumeMounts:
- name: logpath
mountPath: /opt/
env:
- name: TZ
value: "Asia/Shanghai"
- name: LANG
value: C.UTF-8
- name: LC_ALL
value: C.UTF-8
command:
- sh
- -c
- while true; do date >> /opt/date.log; sleep 2; done
- name: filebeat
image: registry.cn-beijing.aliyuncs.com/dotbalo/filebeat:7.10.2
imagePullPolicy: IfNotPresent
env:
- name: podIp
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIp
- name: podName
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: podNamespace
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: podDeployName
value: app
- name: TZ
value: "Asia/Shanghai"
securityContext:
runAsUser: 0
volumeMounts:
- name: logpath
mountPath: /data/log/app/
- name: filebeatconf
mountPath: /usr/share/filebeat/filebeat.yml
subPath: usr/share/filebeat/filebeat.yml
volumes:
- name: logpath
emptyDir: {}
- name: filebeatconf
configMap:
name: filebeatconf
items:
- key: filebeat.yml
path: usr/share/filebeat/filebeat.yml可以看到在 Deployment 部署文件中,添加了 Volume 配置,并配置了一个名为 logpath 的 volume,将其挂载到了应用容器的 /opt/ 目录和 Filebeat 容器的 /data/log/app/ 目录,这样同一个 Pod 内的两个容器就实现了目录的共享。
创建一个 Filebeat 的配置文件,采集该目录下的日志即可,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22apiVersion: v1
kind: ConfigMap
metadata:
name: filebeatconf
data:
filebeat.yml: |-
filebeat.inputs:
- input_type: log
paths: # 配置的共享目录
- /data/log/*/*.log
tail_files: true # 如果配置为 false,则从文件第一行开始采集
fields:
pod_name: '${podName}'
pod_ip: '${podIp}'
pod_deploy_name: '${podDeployName}'
pod_namespace: '${podNamespace}'
output.kafka: # 需要和 logstash 的 kafka 配置为同一个集群,并且 topic 和 logstash 消费的 topic 为同一个。
hosts: ["kafka:9092"]
topic: "filebeat-sidecar"
codec.json:
pretty: false
keep_alive: 30s创建 configMap,更新 Deployment
1
2
3# kubectl apply -f filebeat-cm.yaml -f app-filebeat.yaml -n logging
configmap/filebeatconf created
deployment.apps/app configured之后在 Kibana 上即添加 Filebeat 的索引既可查看日志,添加步骤和 EFK 一致,只需要更改索引名既可。