Kubernetes Logging Architecture

Kubernetes Cluster-level logging architectures

Kubernetes 官方不提供原生的集群日志方案,但是提供了一些解决思路:

  • 在每个 Node 上运行一个日志客户端。
  • 在应用的 Pod 里以 sidecar 形式运行一个日志容器。
  • 应用直接把日志推送到后端日志存储里。

Using a node logging agent

k8s_logging_nodeAgent

一台 Node 上所有容器的 stdout/stderr 日志会被统一保存到宿主机的目录,只需要以 DaemonSet 的形式在每个 Node 上运行一个日志收集客户端即可将这台 Node 上所有容器的 标准输出/标准错误 日志收集起来存到后端存储里。

这里的日志收集客户端建议 fluentd

Using a sidecar container with the logging agent

使用 Sidecar 方式有两种方案:

  • Sidecar 容器将应用日志导流到标准输出或标准错误。

k8s_logging_sidecar_stream

这种方式有利于适配 kubelet,或每台 Node 已经运行日志收集客户端的情况。Sidecar 容器可以从文件、socket 或 journald 收集日志,为应用里的每个日志模块运行一个特定的 sidecar 容器,整个 Pod 共享一个共享目录,最终把每个日志模块的日志对应的输出到各自的 sidecar 容器的标准输出或标准错误。

这是一个在容器内部写两个日志文件的应用范例,然后是同一个 Pod 里运行两个 sidecar 容器分别对两个日志文件进行收集:

two-files-counter-pod-streaming-sidecar.yaml

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
apiVersion: 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
- name: count-log-1
image: busybox
args: [/bin/sh, -c, 'tail -n+1 -f /var/log/1.log']
volumeMounts:
- name: varlog
mountPath: /var/log
- name: count-log-2
image: busybox
args: [/bin/sh, -c, 'tail -n+1 -f /var/log/2.log']
volumeMounts:
- name: varlog
mountPath: /var/log
volumes:
- name: varlog
emptyDir: {}

然后,你就可以使用 kubectl logs counter count-log-1查看 1.log 的内容。同理2。

Node 上的日志客户端会自动采集这两个 sidecar容器的标准输出/标准错误,实际也就是采集了 1.log 和 2.log 两个日志文件。


  • Sidecar 容器运行一个日志收集客户端,主动去收集应用日志。

k8s_logging_sidecar_agent

这种方式适用于 Node 上没有日志收集客户端的情况。需要注意的是这种方式存在过多资源消耗的问题,而且无法使用 kubectl logs 命令直接查看应用日志。

这里举例使用 fluentd 作为 sidecar logging agent 收集日志:

fluentd-sidecar-config.yaml

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
apiVersion: 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>

two-files-counter-pod-agent-sidecar.yaml

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
apiVersion: 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
- name: count-agent
image: k8s.gcr.io/fluentd-gcp:1.30
env:
- name: FLUENTD_ARGS
value: -c /etc/fluentd-config/fluentd.conf
volumeMounts:
- name: varlog
mountPath: /var/log
- name: config-volume
mountPath: /etc/fluentd-config
volumes:
- name: varlog
emptyDir: {}
- name: config-volume
configMap:
name: fluentd-config

Exposing logs directly from the application

k8s_logging_directly

这是最简单的方式,不过涉及应用的改造。