在生产环境中,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
FROM alpine:3.12
ARG VERSION=7.15.1
COPY docker-entrypoint.sh /
RUN set -x \
&& cd /tmp \
&& wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-${VERSION}-linux-x86_64.tar.gz \
&& tar xzvf filebeat-${VERSION}-linux-x86_64.tar.gz \
&& mv filebeat-${VERSION}-linux-x86_64 /opt \
&& rm /tmp/* \
&& chmod +x /docker-entrypoint.sh
ENV PATH $PATH:/opt/filebeat-${VERSION}-linux-x86_64
WORKDIR /opt/filebeat-${VERSION}-linux-x86_64
ENTRYPOINT ["/docker-entrypoint.sh"]
我们以 alphine:3.12 为底版,然后下载 filebeat 7.15.1的二进制包并释放到 /opt 下,最后指定入口文件 /docker-entrypoint.sh
奥妙全在这个 docker-entrypoint.sh 中了
#!/bin/bash
cat > /etc/filebeat.yaml << EOF
filebeat.config.modules:
path: /opt/filebeat-7.15.1-linux-x86_64/modules.d/*.yml
reload.enabled: true
# 加入自定义的字段
fields_under_root: true
fields:
project: kuaijian-tomcat
pod_ip: ${POD_IP}
pod_name: ${POD_NAME}
node_name: ${NODE_NAME}
pod_namespace: ${POD_NAMESPACE}
# 收集云厂商的数据和docker的变量
processors:
- add_cloud_metadata: ~
- add_docker_metadata: ~
filebeat.modules:
- module: apache
access:
enabled: true
var.paths:
- "/usr/local/tomcat/logs/localhost_access_log.*.txt"
error:
enabled: true
var.paths:
- "/usr/local/tomcat/logs/application.log*"
- "/usr/local/tomcat/logs/catalina.*.log"
- "/usr/local/tomcat/logs/host-manager.*.log"
- "/usr/local/tomcat/logs/localhost.*.log"
- "/usr/local/tomcat/logs/manager.*.log"
setup.template.name: "tomcat-logs"
setup.template.pattern: "tomcat-logs-*"
output.elasticsearch:
hosts: ["172.19.20.xxx:9200","172.19.20.xxx:9200"]
index: "tomcat-logs-%{+yyyy.MM}"
EOF
set -xe
# If user don't provide any command
# Run filebeat
if [[ "$1" == "" ]]; then
exec /opt/filebeat-7.15.1-linux-x86_64/filebeat -c /etc/filebeat.yaml
else
# Else allow the user to run arbitrarily commands like bash
exec "$@"
fi
我们为什么不在 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文件:
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat
labels:
app: tomcat
spec:
replicas: 1
selector:
matchLabels:
app: tomcat
template:
metadata:
labels:
app: tomcat
spec:
containers:
- name: filebeat-sidecar
image: xxxx.xxxx.xxx/filebeat:xxx
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: NODE_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
- name: POD_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
volumeMounts:
- name: logs-volume
mountPath: /usr/local/tomcat/logs
- name: tomcat
image: tomcat
ports:
- containerPort: 8080
volumeMounts:
- name: logs-volume
mountPath: /usr/local/tomcat/logs
volumes:
- name: logs-volume
emptyDir: {}
可以看到我们在这个 deployment 里定义了 pod 是单副本,里面跑了两个 container,一个是 filebeat,一个是 tocmat,两者通过同一个 volume 连接在一起,这样就可以做到不修改 tomcat container 而拿到里面的日志了。
这样就把 tomcat 应用的日志收到 ES 去了。