12、容器日志搜集
12、容器日志搜集
1. K8s需要收集哪些日志
- 系统和K8s组件日志:
/var/log/messages
:这是Linux系统中存储一般消息和错误信息的日志文件。/var/log/kube-xxx.log
:这些是Kubernetes 组件的日志文件。
- 业务应用程序日志:
- “云原生——控制台日志”:在云原生环境中,应用程序通常以容器的形式运行。控制台日志是指从应用程序的控制台输出捕获的日志信息。
- “非云原生——容器内日志文件”:对于非云原生的应用程序,它们可能将日志写入容器内的特定日志文件。
传统架构(ELK)中 Logstash 太“重”可能不做任何工作,500兆内存已经没了,而且维护起来相当麻烦。下面将会对k8s中采用的日志收集技术栈进行讲解。

2. EFK架构
2.1 架构说明
Kubernetes官方提出了EFK(Elasticsearch + Fluentd + Kibana)的日志收集解决方案,相对于ELK中的Logstash,Fluentd采用“一锅端”的形式,可以直接将某些日志文件中的内容存储至Elasticsearch,然后通过Kibana进行展示。
Tips:Fluentd只能收集控制台日志(程序直接输出到控制台的日志),不能收集非控制台日志。
2.2 部署EFK
部署 Elasticsearch+Fluentd+Kibana,项目地址:git clone https://github.com/dotbalo/k8s.git ,将该目录下载下来(使用目录中的efk-7.10.2)。
提前下载镜像推送到本地Harbor仓库
docker pull alpine:3.6
docker pull quay.io/fluentd_elasticsearch/elasticsearch:v7.10.2
docker pull registry.cn-beijing.aliyuncs.com/dotbalo/kibana-oss:7.10.2
创建 EFK 所用的命名空间
kubectl create -f create-logging-namespace.yaml
创建 Elasticsearch 集群
#进入efk-7.10.2目录提前修改本地镜像地址
[root@k8s-master01 efk-7.10.2]# grep -n "image:" es-statefulset.yaml
70: - image: 10.0.0.138:5000/logs/elasticsearch:v7.10.2
115: - image: 10.0.0.138:5000/logs/alpine:3.6
#创建Service
kubectl create -f es-service.yaml
#创建Statefulset
kubectl create -f es-statefulset.yaml
创建 Kibana
#提前修改本地镜像地址
[root@k8s-master01 efk-7.10.2]# grep -n "image:" kibana-deployment.yaml
24: image: 10.0.0.138:5000/logs/kibana-oss:7.10.2
#创建Service
kubectl create -f kibana-service.yaml
#创建Deployment
kubectl create -f kibana-deployment.yaml
由于在 Kubernetes 集群中,我们可能并不需要对所有的机器都采集日志,所以可以更改Fluentd 的部署文件如下,添加一个 NodeSelector,只部署至需要采集的主机即可。
[root@k8s-master01 efk-7.10.2]# grep -n "image:" fluentd-es-ds.yaml
72: image: 10.0.0.138:5000/logs/fluentd:v3.1.0
[root@k8s-master01 efk-7.10.2]# grep -n -A1 "nodeSelector" fluentd-es-ds.yaml
105: nodeSelector:
106- fluentd: "true"
之后给需要采集日志的节点打上一个标签
kubectl label node k8s-master01 fluentd=true
kubectl label node k8s-master02 fluentd=true
kubectl label node k8s-master03 fluentd=true
查询打上该label的节点
创建 Fluentd
kubectl create -f fluentd-es-ds.yaml -f fluentd-es-configmap.yaml
2.3 Kibana使用
查看全部Pod已经running
接下来查看 Kibana 暴露的端口号,访问 Kibana。访问格式:节点IP:暴露的端口号/kibana
点击 Explore on my own,之后再点击 Visualize:
之后点击 Add your data → Create index pattern:
3. Filebeat收集自定义文件日志
3.1 架构说明
EFK也有诸多限制,比如Fluentd只能收集控制台日志(程序直接输出到控制台的日志),不能收集非控制台日志,所以很难满足生产环境的需求。因为大部分情况下,没有遵循云原生理念开发的程序,往往都会输出很多日志文件,这些容器内的日志无法采集,除非在每个Pod内添加一个 Sidecar,将日志文件的内容进行tail -f转成控制台日志,但这也是非常麻烦的。
另一个问题是,大部分公司内都有很成熟的 ELK 平台,如果再搭建一个 EFK 平台,属于重复造轮子。当然,用来存储日志的 Elasticsearch 集群是不建议搭建在Kubernetes集群中的,因为会非常浪费 Kubernetes 集群资源,所以大部分情况下通过Fluentd采集日志输出到外部的Elasticsearch集群中。
Fluentd功能有限,Logstash太重,所以就需要一个中和的工具进行收集,此时就可以采用一个比较轻量级的收集工具:Filebeat。
了解Filebeat
在早期的 ELK 架构中,日志收集均以 Logstash 为主,Logstash 负责收集和解析日志,它对内存、CPU、IO 资源的消耗比较高,但是 Filebeat 所占系统的 CPU 和内存几乎可以忽略不计。
由于 Filebeat 本身是比较轻量级的日志采集工具,因此 Filebeat 经常被用于以 Sidecar 的形式配置在 Pod 中,用来采集容器内程序输出的自定义日志文件。当然,Filebeat 同样可以采用 DaemonSet 的形式部署在 Kubernetes 集群中,用于采集系统日志和程序控制台输出的日志。
具体实现
Filebeat 可以将其和应用程序部署至一个 Pod 中,通过 Volume 进行日志文件的共享,之后 Filebeat 即可采集里面的数据,并推送至日志平台。
为了减轻 Elasticsearch 的压力,引入 Kafka 消息队列来缓存日志数据,之后通过 Logstash 简单处理一下日志,最后再输出到 Elasticsearch 集群。
3.2 提前下载镜像推送本地仓库
在之前 clone 下来的项目文件进入到 filebeat 目录。
[root@k8s-master01 filebeat]# pwd
/root/efk-7.10.2/filebeat
[root@k8s-master01 filebeat]# ll
total 28
-rw-r--r-- 1 root root 2373 Aug 14 22:27 app-filebeat.yaml
-rw-r--r-- 1 root root 992 Aug 14 22:27 app.yaml
-rw-r--r-- 1 root root 530 Aug 14 22:27 es-svc.yaml
-rw-r--r-- 1 root root 491 Aug 14 22:27 filebeat-cm.yaml
drwxr-xr-x 5 root root 141 Aug 14 22:27 kafka
-rw-r--r-- 1 root root 1087 Aug 14 22:27 logstash-cm.yaml
-rw-r--r-- 1 root root 181 Aug 14 22:27 logstash-service.yaml
-rw-r--r-- 1 root root 930 Aug 14 22:27 logstash.yaml
drwxr-xr-x 4 root root 128 Aug 15 15:30 zookeeper
提前下载 Zookeeper、Kafka、logstash、filebeat 镜像到本地,推送到远程仓库。
#Zookeeper相关
docker pull bitnami/zookeeper:3.7.0-debian-10-r56
docker pull bitnami/bitnami-shell:10-debian-10-r97
#Kafka相关
docker pull bitnami/kafka:2.8.0-debian-10-r30
docker pull bitnami/kubectl:1.19.11-debian-10-r14
docker pull bitnami/bitnami-shell:10-debian-10-r98
docker pull bitnami/kafka:2.8.0-debian-10-r29
docker pull bitnami/kafka-exporter:1.3.1-debian-10-r14
docker pull bitnami/jmx-exporter:0.15.0-debian-10-r121
#logstash相关
docker pull registry.cn-beijing.aliyuncs.com/dotbalo/logstash:7.10.1
#filebeat相关
docker pull registry.cn-beijing.aliyuncs.com/dotbalo/filebeat:7.10.2
3.3 部署Kafka集群
Kafka依赖Zookeeper,所以需要先部署Zookeeper,修改values.yaml中的镜像和副本。
[root@k8s-master01 filebeat]# grep -A 2 "10.0.0.138" zookeeper/values.yaml
registry: 10.0.0.138:5000 #xxx.com
repository: logs/bitnami/zookeeper # bitnami/zookeeper
tag: 3.7.0
--
registry: 10.0.0.138:5000
repository: logs/bitnami/bitnami-shell
tag: 10-debian-10-r97
[root@k8s-master01 filebeat]# grep "replicaCount:" zookeeper/values.yaml
replicaCount: 3
安装zookeeper到logging命名空间下
helm install -n logging zookeeper zookeeper/
查看Pod情况和Service信息
部署Kafka,修改values.yaml中的镜像和副本。
[root@k8s-master01 filebeat]# grep -A 2 "10.0.0.138" kafka/values.yaml
registry: 10.0.0.138:5000
repository: logs/bitnami/kafka
tag: 2.8.0-debian-10-r30
--
registry: 10.0.0.138:5000
repository: logs/bitnami/kubectl
tag: 1.19.11-debian-10-r14
--
registry: 10.0.0.138:5000
repository: logs/bitnami/bitnami-shell
tag: 10-debian-10-r98
--
registry: 10.0.0.138:5000
repository: logs/bitnami/kafka
tag: 2.8.0-debian-10-r29
--
registry: 10.0.0.138:5000
repository: logs/bitnami/kafka-exporter
tag: 1.3.1-debian-10-r14
--
registry: 10.0.0.138:5000
repository: logs/bitnami/jmx-exporter
tag: 0.15.0-debian-10-r121
[root@k8s-master01 filebeat]# grep "replicaCount:" kafka/values.yaml
replicaCount: 3
安装kafka到logging命名空间下
helm install -n logging kafka kafka/
查看 Pod 情况和 Service 信息
3.4 部署Logstash服务
待 Kakfa、Zookeeper 的 Pod 都正常后,需先修改镜像地址,然后创建 Logstash 服务到 logging 命名空间下。
#修改镜像地址为本地仓库
[root@k8s-master01 filebeat]# grep "image" logstash.yaml
image: 10.0.0.190/yinjay/logstash:7.10.1
#部署Logstash服务
kubectl create -f logstash-service.yaml -f logstash-cm.yaml -f logstash.yaml -n logging
需要注意 logstash-cm.yaml 文件中的一些配置:
- input:数据来源,本次示例配置的是 Kakfa;
- 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 集群,并且 index 为 filebeat-xxx。
查看Pod情况和Service信息
#修改镜像地址为本地仓库
[root@k8s-master01 filebeat]# grep "image" logstash.yaml
image: 10.0.0.138:5000/logs/logstash:7.10.1
#部署Logstash服务
kubectl create -f logstash-service.yaml -f logstash-cm.yaml -f logstash.yaml -n logging
需要注意 logstash-cm.yaml 文件中的一些配置:
- input:数据来源,本次示例配置的是 Kakfa;
- 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 集群,并且 index 为 filebeat-xxx。
查看Pod情况和Service信息
3.5 注入Filebeat Sidecar
下面可以看到在 Deployment 部署文件中,添加了 Volumes 配置,并配置了一个名为 logpath 的 volume,将其挂载到了应用容器的 /opt/ 目录和 Filebeat 的 /data/log/app/ 目录,这样同一个Pod内的两个容器就实现了目录的共享。
[root@k8s-master01 filebeat]# cat app-filebeat.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
labels:
app: app
env: release
spec:
selector:
matchLabels:
app: app
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
# minReadySeconds: 30
template:
metadata:
labels:
app: app
spec:
containers:
- name: filebeat
image: 10.0.0.138:5000/logs/filebeat:7.10.2
resources:
requests:
memory: "100Mi"
cpu: "10m"
limits:
cpu: "200m"
memory: "300Mi"
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
- name: app
image: 10.0.0.138:5000/logs/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
volumes:
- name: logpath
emptyDir: {}
- name: filebeatconf
configMap:
name: filebeatconf
items:
- key: filebeat.yml
path: usr/share/filebeat/filebeat.yml
filebeat 配置文件的 ConfigMap,其中 fields 字段是用来添加自定义字段到每个日志事件的元数据中的配置选项之一。它允许你为每个事件添加额外的信息,以便更好地对日志进行分类、过滤或分析。
[root@k8s-master01 filebeat]# cat filebeat-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: filebeatconf
data:
filebeat.yml: |-
filebeat.inputs:
- input_type: log
paths:
- /data/log/*/*.log
tail_files: true
fields:
pod_name: '${podName}'
pod_ip: '${podIp}'
pod_deploy_name: '${podDeployName}'
pod_namespace: '${podNamespace}'
output.kafka:
hosts: ["kafka:9092"]
topic: "filebeat-sidecar"
codec.json:
pretty: false
keep_alive: 30s
Tips:需要注意 paths 是配置的共享目录,output.kafka 需要和 logstash 的 kafka 为同一个集群,并且 topic 和 logstash 消费的 topic 为同一个。
创建测试的 Deployment,查看 Pod 下 filebeat 容器中的 /data/log/app/date.log。
kubectl apply -f filebeat-cm.yaml -f app-filebeat.yaml -n logging
将之前的 EFK 架构部署好
3.6 Kibana建立索引并查看数据(实现Pod名称和Namespace检索日志)
3.7 清理
#清理kafka、zookeeper、filebeat、lostash
[root@k8s-master01 filebeat]# pwd
/root/efk-7.10.2/filebeat
kubectl delete -f filebeat-cm.yaml -f app-filebeat.yaml -n logging
kubectl delete -f logstash-service.yaml -f logstash-cm.yaml -f logstash.yaml -n logging
helm delete -n logging kafka
helm delete -n logging zookeeper
#清理Elasticsearch、Fluentd、Kibana
[root@k8s-master01 efk-7.10.2]# pwd
/root/efk-7.10.2
kubectl delete -f kibana-service.yaml -f kibana-deployment.yaml
kubectl delete -f fluentd-es-ds.yaml -f fluentd-es-configmap.yaml
kubectl delete -f es-statefulset.yaml -f es-service.yaml
kubectl delete -f create-logging-namespace.yaml
4. Loki架构
4.1 架构说明
无论是ELK、EFK还是Filebeat,都需要用到Elasticsearch来存储数据,Elasticsearch本身就像“一座大山”,维护难度和资源使用都是偏高的。对于很多公司而言,特别是新创公司,可能并不想大费周章地去搭建一个ELK、EFK或者其他重量级的日志平台,刚开始的人力投入可能是大于收益的,所以就需要一个更轻量的日志收集平台。
一个基于Kubernetes平台的原生日志收集平台Loki Stack应运而生,相对于上述技术栈,Loki的安装、架构、使用都比较简单,能够满足大部分的工作需求。
可以看到主要包含如下组件:
- Loki:主服务器,负责日志的存储和查询,参考了Prometheus的服务发现机制,将标签添加到日志流,而不是像其他平台一样进行全文索引。
- Promtail:负责收集日志并将其发送给Loki,主要用于发现采集目标以及添加对应Label,最终发送给Loki。
- Grafana:用来展示或查询相关日志,可以在页面查询指定标签Pod的日志。
Loki不对日志进行全文索引,仅索引相关日志的元数据,所以Loki操作起来更简单、更省成本。而且Loki是基于Kubernetes进行设计的,可以很方便地部署在Kubernetes上,并且对集群的Pod进行日志采集,采集时会将Kubernetes集群中的一些元数据自动添加到日志中,让技术人员可以根据命名空间、标签等字段进行日志的过滤,可以很快速地定位到相关日志。
4.2 部署Loki
添加helm仓库并拉取helm包
helm repo add grafana https://grafana.github.io/helm-charts
helm pull grafana/loki-stack
helm包版本是loki-stack-2.9.11,提前拉取需要部署服务的镜像到本地Harbor仓库,对以下文件中的镜像地址进行修改。
#一下镜像版本的查看
#loki-stack/values.yaml 下看grafana的配置,tag 是8.3.5
#loki-stack/charts/promtail/Chart.yaml 下看appVersion 是2.8.3
#/root/efk-7.10.2/loki-stack/values.yaml
docker pull bats/bats:1.8.2
#/root/efk-7.10.2/loki-stack/charts/grafana/values.yaml
docker pull grafana/grafana:8.3.5
docker pull bats/bats:1.4.1
docker pull curlimages/curl:7.85.0
docker pull busybox:1.13.1
docker pull quay.io/kiwigrid/k8s-sidecar:1.19.2
docker pull grafana/grafana-image-renderer
#/root/efk-7.10.2/loki-stack/charts/promtail/values.yaml
docker pull docker.io/grafana/promtail:2.8.3
docker pull docker.io/jimmidyson/configmap-reload:v0.8.0
#/root/efk-7.10.2/loki-stack/charts/loki/values.yaml
docker pull grafana/loki:2.6.1
创建 Loki Namespace、 Loki Stack
#/root/efk-7.10.2/loki-stack/下进行
kubectl create ns loki
helm install loki . --set grafana.enabled=true --set grafana.service.type=NodePort -n loki
查看 Pod 状态、以及查看 Grafana 的 Service 暴露的端口号
#查看 Grafana 密码(账号 admin)
kubectl get secret --namespace loki loki-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
Tips:Loki默认没持久化数据,可以进行修改配置文件实现持久化存储。
LogQL 的官方文档:https://grafana.com/docs/loki/latest/logql/。
4.3 清理
[root@k8s-master01 loki-stack]# pwd
/root/efk-7.10.2/loki-stack
[root@k8s-master01 loki-stack]# helm delete -n loki loki
[root@k8s-master01 loki-stack]# kubectl delete ns loki
注:本篇学习笔记内容参考杜宽的《云原生Kubernetes全栈架构师》,视频、资料文档等,大家可以多多支持!还有YinJayChen语雀、k8s训练营、“我为什么这么菜”知乎博主等资料文档,感谢无私奉献!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南