Kubernetes 组件默认日志位置
kubernetes : /var/log/kubernetes
etcd : /var/log/messages
容器 : /var/log/containers/ -> /var/log/pods/ # 指向了这个位置
1 | [root@k8s01 ~]# ll /var/log/kubernetes |
日志的需求
- 系统各组件的日志 : eg: kubelet、kube-proxy,docker 等日志
- 容器化运行的应用程序自身日志 : eg: Nginx 的运行日志
- k8s 内部各种 Event : eg: kubctl create pod 后,kubectl describe pod *** 的pod 的 Event信息
日志系统
Kubernetes 的日志系统在设计的时候,必须得独立于节点和 Pod 的生命周期,且保证日志数据可以实时采集到服务端,即完全独立于 Kubernetes 系统,使用自己的后端存储和查询工具
日志收集方式
一般有如下 四种方案来做日志收集:

- 直接在应用程序中将日志信息推送到采集后端; (不推荐, 耦合严重。本身已有完善日志处理系统的公司可以采用)

- 在节点上运行一个 Agent 来采集节点级别的日志; (使用 daemonset,比较常用,但只适合 容器内应用日志是标准输出场景,即应用把日志 输出的 stdout 和 stderr)

3.当容器的日志只能输出到某些文件里的时候,我们可以通过一个 sidecar 容器把这些日志文件重新输出到 sidecar 的 stdout 和 stderr 上,这样就能够继续使用第一种方案了; (Sidecar 容器读取日志文件,并重定向到自己的标准输出。会增加额外开销,cpu 内存,磁盘空间等,大规模集群,这些开销不可忽视,所以非特殊情况,一般推荐二和四)

- 通过一个
sidecar容器,直接把应用的日志文件发送到远程存储里面去。也就是相当于把方案二里的logging agent,放在了应用Pod里。(应用还可以直接把日志输出到固定的文件里而不是 stdout,logging-agent 还可以使用 fluentd,后端存储还可以是 ElasticSearch。只不过, fluentd 的输入源,变成了应用的日志文件。一般来说,我们会把 fluentd 的输入源配置保存在一个 ConfigMap 里)
sidecar 指的就是我们可以在一个 Pod 中,启动一个辅助容器,来完成一些独立于主进程(主容器)之外的工作。
sidecar 与 fluentd 方案示例
Pod 只有一个容器,它会把日志输出到容器里的 /var/log/1.log 和 2.log 这两个文件里
log_to_file.yaml1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26apiVersion: v1
kind: Pod
metadata:
name: counter
spec:
containers:
- name: count
image: busybox
args:
- /bin/sh
- -c
- >
i=0;
while true;
do
echo "$i: $(date)" >> /var/log/1.log;
echo "$(date) INFO $i" >> /var/log/2.log;
i=$((i+1));
sleep 1;
done
volumeMounts:
- name: varlog
mountPath: /var/log
volumes:
- name: varlog
emptyDir: {}
因为非 stdout 和 stderr, kubectl logs 命令是看不到应用的任何日志的。所以方案二不能使用。
使用方案三 : Pod 添加两个 sidecar 容器,分别将上述两个日志文件里的内容重新以 stdout 和 stderr 的方式输出出来 tail -f
1 | apiVersion: v1 |
方案四
fluentd-from-config.yaml1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25apiVersion: v1
kind: ConfigMap
metadata:
name: fluentd-config
data:
fluentd.conf: |
<source>
type tail
format none
path /var/log/1.log
pos_file /var/log/1.log.pos
tag count.format1
</source>
<source>
type tail
format none
path /var/log/2.log
pos_file /var/log/2.log.pos
tag count.format2
</source>
<match **>
type google_cloud
</match>
声明一个 Fluentd 容器作为 sidecar,专门负责将应用生成的 1.log 和 2.log 转发到 ElasticSearch 当中.
1 | apiVersion: v1 |
这个 sidecar 容器很可能会消耗较多的资源,甚至拖垮应用容器。并且,由于日志还是没有输出到 stdout 上,所以你通过 kubectl logs 是看不到任何日志输出的。
推荐方案
使用 EFK 进行日志收集和管理,通过 Fluentd 将日志导入到 Elasticsearch 中,然后通过 Kibana 查看所有的日志。
使用 EFLK 收集容器内文件日志: Elasticsearch + Filebeat + Logstash + Kibana。
EFK 部署(基于 Helm)
简介
项目地址:1
2
3https://github.com/bitnami/charts/tree/main/bitnami/elasticsearch
https://github.com/fluent/helm-charts/tree/main/charts/fluent-bit # fluent-bit
基于 helm 制作的 yaml 文件放于以下路径:1
2
3https://raw.githubusercontent.com/itswl/shellbackup/main/k8s_config/EFK/es.yaml
https://raw.githubusercontent.com/itswl/shellbackup/main/k8s_config/EFK/fluent-bit.yaml
开启了 prometheus 拉取, 先装的 es, ns 为 elasticsearch 方便管理。
使用






EFLK 部署(Filebeat + Kafka + Logstash + Elasticsearch + Kibana)

环境信息
使用的 hadoop 完全分布式集群:
1 | 192.168.2.241 hadoop01 |
所有组件均已完成安装(参考前文), 以收集 nginx 日志为例。
Filebeat 配置
/opt/bigdata/filebeat/current/filebeat-nginx-to-kafka.yml1
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
30filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/nginx/*.log
fields:
log_topic: nginxlogs
filebeat.config.modules:
path: ${path.config}/modules.d/*.yml
reload.enabled: false
setup.template.settings:
index.number_of_shards: 1
name: "hadoop01"
setup.kibana:
output.kafka:
enabled: true
hosts: ["hadoop01:9092", "hadoop02:9092", "hadoop03:9092"]
version: "0.10"
topic: '%{[fields][log_topic]}'
codec.format.string: '%{[message]}'
partition.round_robin:
reachable_only: true
worker: 2
required_acks: 1
compression: gzip
max_message_bytes: 10000000
processors:
- drop_fields:
fields: ["input", "host", "agent.type", "agent.ephemeral_id", "agent.id", "agent.version", "ecs"]
logging.level: info
启动1
2cd /opt/bigdata/filebeat/current/
nohup ./filebeat -e -c filebeat-nginx-to-kafka.yml &
Logstash 配置
/opt/bigdata/logstash/current/kafka_nginx_into_es.conf1
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
32input {
kafka {
bootstrap_servers => "hadoop01:9092,hadoop02:9092,hadoop03:9092"
topics => ["nginxlogs"]
add_field => { "[@metadata][myid]" => "nginxlogs" }
}
}
filter {
if [@metadata][myid] == "nginxlogs" {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:localtime}\|\~\|%{IPORHOST:clientip}\|\~\|(%{GREEDYDATA:http_user_agent})\|\~\|(%{DATA:http_referer})\|\~\|%{GREEDYDATA:media_id}\|\~\|%{GREEDYDATA:nginx_id}" }
}
date {
match => ["localtime", "yyyy-MM-dd'T'HH:mm:ssZZ"]
target => "@timestamp"
}
mutate {
remove_field => "@version"
remove_field => "message"
remove_field => "localtime"
}
}
}
output {
if [@metadata][myid] == "nginxlogs" {
elasticsearch {
hosts => ["hadoop01:9200","hadoop02:9200","hadoop03:9200"]
index => "nginxlogs-%{+YYYY.MM.dd}"
}
}
}
启动1
2cd /opt/bigdata/logstash/current/
nohup bin/logstash -f kafka_nginx_into_es.conf &
验证
使用 kibana


