在生产环境中,ES 通常是不会在 k8s 集群中存在的,一般 MySQL 和 Elasticsearch 都是独立在 k8s 之外。
那么无论哪种 pod,要甩日志到 ES,最轻量的方案肯定是用 filebeat 甩过去了。
当然,如果是阿里的 ACK,logtail 和 logstore 配搭已经非常不错了,根本用不到 filebeat 和 ES。
可但是,我们不想为阿里 sls、logstore 出钱买单,就只能用 filebeat + ES 了
说一下 filebeat 的 sidecar 边车(僚机)用法:
如上图所示,简单说就是起一个 filebeat 的 logging-agent 边车(僚机),边车和主应用之间共享某个文件夹(mountPath),达到收集主应用日志并发送到 ES,而不用动 app-container 分毫。
我们以部署一个 Tomcat 应用为例来说明:
一、打造 filebeat 边车镜像
首先准备 Dockerfile
1FROM alpine:3.12
2
3ARG VERSION=7.15.1
4
5COPY docker-entrypoint.sh /
6
7RUN set -x \
8 && cd /tmp \
9 && wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-${VERSION}-linux-x86_64.tar.gz \
10 && tar xzvf filebeat-${VERSION}-linux-x86_64.tar.gz \
11 && mv filebeat-${VERSION}-linux-x86_64 /opt \
12 && rm /tmp/* \
13 && chmod +x /docker-entrypoint.sh
14
15
16ENV PATH $PATH:/opt/filebeat-${VERSION}-linux-x86_64
17
18WORKDIR /opt/filebeat-${VERSION}-linux-x86_64
19
20ENTRYPOINT ["/docker-entrypoint.sh"]
我们以 alphine:3.12 为底版,然后下载 filebeat 7.15.1的二进制包并释放到 /opt 下,最后指定入口文件 /docker-entrypoint.sh
奥妙全在这个 docker-entrypoint.sh 中了
1#!/bin/bash
2
3cat > /etc/filebeat.yaml << EOF
4filebeat.config.modules:
5 path: /opt/filebeat-7.15.1-linux-x86_64/modules.d/*.yml
6 reload.enabled: true
7
8# 加入自定义的字段
9fields_under_root: true
10fields:
11 project: kuaijian-tomcat
12 pod_ip: ${POD_IP}
13 pod_name: ${POD_NAME}
14 node_name: ${NODE_NAME}
15 pod_namespace: ${POD_NAMESPACE}
16
17# 收集云厂商的数据和docker的变量
18processors:
19 - add_cloud_metadata: ~
20 - add_docker_metadata: ~
21
22filebeat.modules:
23 - module: apache
24 access:
25 enabled: true
26 var.paths:
27 - "/usr/local/tomcat/logs/localhost_access_log.*.txt"
28 error:
29 enabled: true
30 var.paths:
31 - "/usr/local/tomcat/logs/application.log*"
32 - "/usr/local/tomcat/logs/catalina.*.log"
33 - "/usr/local/tomcat/logs/host-manager.*.log"
34 - "/usr/local/tomcat/logs/localhost.*.log"
35 - "/usr/local/tomcat/logs/manager.*.log"
36
37setup.template.name: "tomcat-logs"
38setup.template.pattern: "tomcat-logs-*"
39output.elasticsearch:
40 hosts: ["172.19.20.xxx:9200","172.19.20.xxx:9200"]
41 index: "tomcat-logs-%{+yyyy.MM}"
42EOF
43
44set -xe
45
46# If user don't provide any command
47# Run filebeat
48if [[ "$1" == "" ]]; then
49 exec /opt/filebeat-7.15.1-linux-x86_64/filebeat -c /etc/filebeat.yaml
50else
51 # Else allow the user to run arbitrarily commands like bash
52 exec "$@"
53fi
我们为什么不在 k8s 里用 configmap 来配置 filebeat.yml 呢?
理由是收集日志文件多且路径、类型各不相同,这么一堆的配置都放在 configmap 里会让人癫狂的。所以干脆放到镜像里,便于调试也便于修改。
上面我们也充分利用了 filebeat 的 module,有 module 可用就必须用 module,而不是手动指定 filebeat.inputs ,可用的 mudole 实在太多了,一定要善用!!!另外 tomcat 和 apache 的日志格式是一样的。
我们在最后执行的时候,也加了 exec $@
便于调试,如果没有指定 CMD,就启动 filebeat,如果指定了比如 /bin/bash,就进入调试状态。
我们打好镜像就 push 到 harbor 里待用
附录:https://www.elastic.co/guide/en/beats/filebeat/current/configuration-general-options.html filebeat的配置列表
二、sidecar部署
我们写一个 k8s 的 tomcat deployment文件:
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4 name: tomcat
5 labels:
6 app: tomcat
7spec:
8 replicas: 1
9 selector:
10 matchLabels:
11 app: tomcat
12 template:
13 metadata:
14 labels:
15 app: tomcat
16 spec:
17 containers:
18 - name: filebeat-sidecar
19 image: xxxx.xxxx.xxx/filebeat:xxx
20 env:
21 - name: POD_NAMESPACE
22 valueFrom:
23 fieldRef:
24 apiVersion: v1
25 fieldPath: metadata.namespace
26 - name: NODE_NAME
27 valueFrom:
28 fieldRef:
29 apiVersion: v1
30 fieldPath: spec.nodeName
31 - name: POD_IP
32 valueFrom:
33 fieldRef:
34 apiVersion: v1
35 fieldPath: status.podIP
36 - name: POD_NAME
37 valueFrom:
38 fieldRef:
39 apiVersion: v1
40 fieldPath: metadata.name
41 volumeMounts:
42 - name: logs-volume
43 mountPath: /usr/local/tomcat/logs
44 - name: tomcat
45 image: tomcat
46 ports:
47 - containerPort: 8080
48 volumeMounts:
49 - name: logs-volume
50 mountPath: /usr/local/tomcat/logs
51 volumes:
52 - name: logs-volume
53 emptyDir: {}
可以看到我们在这个 deployment 里定义了 pod 是单副本,里面跑了两个 container,一个是 filebeat,一个是 tocmat,两者通过同一个 volume 连接在一起,这样就可以做到不修改 tomcat container 而拿到里面的日志了。
这样就把 tomcat 应用的日志收到 ES 去了。