我们说一下,K8S中的日志管理

我们讲解了Kubernetes的核心监控体系和自定义监控体系的设计和实现思路,在本篇中,我们讲解一下Kubernetes中关于容器日志的处理方式

Kubernetes中关于容器日志的处理方式,统一的称为cluster-level-logging,这个日志处理系统,和容器,Pod以及Node的生命周期都是无缘的,这样,无论是容器挂了,还是节点宕机的时候,都可以正常的获取到日志的信息

默认情况下,当应用进行日志的输出的时候,是输出到了stdout和stderr的,这样容器项目会在默认的时候将这些日志输出到宿主机上的一个JSON文件中,这样,通过kubectl logs的命令就可以看到这些容器的日志

而Kubernetes本身,是不会为其做容器日志收集工作的,为了实现上述的cluster-level-logging,需要在部署集群的时候,提前对具体的日志方案进行规划,常见的方案包含三种

第一种,在Node上部署logging agent,将日志文件转发到后端存储里保存起来,这个方案的架构如下

图片

这里的核心,就在于logging agent,会以DaemonSet的方式运行在节点上,就将宿主机上的容器日志挂载进去,由logging-agent将日志转发出去

常见的logging-agent有Fluentd项目,其可以将日志转发到远端的ElasticSearch里保存起来供其将来进行检索

这样部署的话,就可以在一个节点上只部署一个agent,而且对应用和Pod没有任何的侵入性,所以,这个方案是社区中常见的方案.

但是有一定的缺陷,就是这个方案要求应用输出的日志,必须都要直接输出到容器的stdout和stderr中,所以有着Kubernetes容器日志方案的第二种,就是对于这种特殊情况的一种处理,当容器的日志只能输出到某些文件中的时候,我们可以通过一个sidecar容器将这些日志文件重新输出到sidecar的stdout和stderr了,这样就能够使用第一种来进行远端的保存了,这种方案的工作原理如下

图片

具体的操作如下,我们的应用Pod只有一个容器,就会将日志输出到容器的/var/log/1.log和2.log这两个文件中,这个Pod的YAML文件如下所示

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

volumes:

– name: varlog

emptyDir: {}

这种情况下,因为没有输出到容器原本的log文件中,导致kubectl logs是看不到应用的任何日志的,我们定义的常见的方案,也是没法使用的,这时候,我们就可以为这个Pod添加两个sidecar容器,分别将上述的两个日志文件的内容重新以stdout和stderr的方式输出

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: {}

这时候,这两个sidecat容器就可以以kubeclt logs的方式进行查看了,间接的看到应用的日志内容.

而且,我们新开启的sidecar容器和主容器也是共享Volume的,所以这里的sidecar方案的额外性能消耗并不高,只是多占用一些CPU和内存罢了

但是,唯一的问题在于,宿主机上会存在两个相同的日志文件,一份是应用自己写的,一份是sidecar的stdout和stderr的JSON文件,这对磁盘是很大的浪费,所以不到万不得已,还是不选择方案二了.

那就是第三种,就是通过一个sidecar容器,将应用的日志文件发送给远程存储里面去.相当于将方案一中的logging agent,放到了应用Pod里,这种方案的架构如下

图片

我们直接将日志输出到固定的文件而不是一个stdout,而交由一个logging-agent进行相关的管理,也可以提交给后端的ElasticSearch,只不过fluentd的输入源,变为了应用的日志文件,我们将fluentd的输入源配置保存在一个ConfigMap中

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>

我们应用Pod的定义中,声明了一个Fluentd容器作为sidecar,将生成的对应的1.log 2.log转发给ElasticSearch中,配置如下

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

这样,这个Fluentd容器的输入源,就是通过引用我们的ConfigMap来指定的,我们用了Projected Volume来将ConfigMap挂载到Pod中

这种方式部署简单,对宿主机相对友好,但是每个Pod都有一个sidecar容器,都会消耗一些额外的资源,甚至拖垮应用容器,而且,是直接转发出去了,kubectl logs还是看不到日志输出的

这就是Kubernetes项目对容器应用日志进行管理的常用的三种手段的

总结一下

我们讲解了下Kubernetes项目对容器应用日志的收集方式,综合对比了三种方案,其实还是最原始的,将logging-agent部署在宿主机上,应用日志输出到stdout和stderr.

这种方案管理简单,kubectl logs可以直接使用,还可以输出到其他的存储后端上

或者在编写应用的时候,直接配置一个日志的存储后端,如下所示

图片

这样,Kubernetes就不用操心日志的收集,收集已经是完善的了

但是,无论何种日志存储方案,都需要及时的将日志文件从宿主机上清理掉,或者给日志目录专门挂载一些容器巨大的存储盘,避免磁盘爆满

那么日志量大的时候,直接将日志输出到stdout和stderr上,会有隐患吗?

还有什么容器收集的方案吗?

发表评论

邮箱地址不会被公开。 必填项已用*标注