本文的测试环境为CentOS 7.3,Kubernetes集群为1.11.2,安装步骤参见kubeadm安装kubernetes V1.11.1 集群 。想要了解更多 Kubernetes 相关知识,可以阅读 Kubernetes 系列学习文章。
日志对于我们管理Kubernetes集群及其上的应用具有非常重要的作用,特别是在出现故障或者Bug的时候。如果你能回答下面几个问题,那么可以不用再看本文了,如果不能回答,本文可能正好适合你。
- Docker都会产生哪些日志?
- Docker产生的日志都放在哪里?
- Docker的日志的分割、清理策略默认为什么?
- 如何配置Docker日志的分割、清理策略?
- Kubernetes都会产生哪些日志?
- Kubernetes产生的日志都存放在那里?
- 如何集中管理Kubernetes产生的日志?
1. Docker的日志处理方案
Docker产生的日志有两类:
- 一类是Docker引擎日志。Docker引擎日志在不同的操作系统下管理方式不一样,在Centos中是通过journalctl来进行管理。
- 一类是容器日志。容器中的应用产生的日志默认都输出到
stdout
和stderr
中,可以通过docker logs
来访问。Docker为容器日志提供了多种实现机制称为logging driver。通过docker info
可以查看本机使用的logging driver,默认为json-file
形式,这种形式下每个容器的日志默认以json格式存储在/var/lib/docker/containers/<容器id>/<容器id>-json.log
下。下面两种情况使用docker logs
看不到什么有用的信息:- 容器内的应用不是交互式应用,而是实现了自己的日志输出,例如对于Apache、Nginx等Web服务,通常会将访问日志和错误日志记录到不同的文件,而不是打到标准输出和错误输出。
- 使用不同的logging driver将日志送到了文件、外部服务器、数据库等集中的日志后台。
Docker目前支持的logging driver类型:
- none
- json-file
- syslog
- journald
- gelf
- fluentd
- awslogs
- splunk
- etwlogs
- gcplogs
- logentries
1.1 配置logging driver
运行容器时,可以通过命令行参数指定logging driver的类型。
1 | bogon:log rousseau$ docker run -it --log-driver none alpine sh |
对于日志输出到文件的应用,可以通过软连接的方式将日志输出到标准输出和标准错误输出。例如:The official nginx image creates a symbolic link from /var/log/nginx/access.log to /dev/stdout, and creates another symbolic link from /var/log/nginx/error.log to /dev/stderr, overwriting the log files and causing logs to be sent to the relevant special device instead.
对于多行格式的日志信息,有一点需要特别关注。The Docker json logging driver treats each line as a separate message. When using the Docker logging driver, there is no direct support for multi-line messages. You need to handle multi-line messages at the logging agent level or higher.
1.3 日志分割策略配置
在CentOS中,可以通过修改/etc/docker/daemon.json
来配置Docker的日志分割策略。
1 | { |
总结:对于单机的Docker来说,可以将日志以json-file的形式存储到本地磁盘,同时提供了根据文件大小进行文件分割的配置,也提供了根据文件数量进行文件清理的策略。配置好这两个参数,基本上就不需要担心容器应用将磁盘写满的风险了。而Docker引擎本身的日志则是通过journald来进行管理的。
2. Kubernetes的日志处理方案
Kubernetes的日志管理方式与Docker有所不同,因为容器封装在Pod中,当遇到Pod被删除或者Node节点故障的情况下,日志会被删除,单纯依靠Docker本身的日志机制将无法在故障后查询日志,因此在管理集群时需要认真考虑日志的管理问题。
Kubernetes集群的日志包括以下几种:
- 各种event事件,可以通过
kubectl describe pod
查看到详细信息 - 容器应用产生的日志
- Node节点上Docker Daemon产生的日志
- Node节点上kubelet产生的日志
2.1 日志的位置
Kubernetes集群中包含众多组件,在用kubeadm方式安装的集群上,有些组件不是容器化运行的,包括Master节点的kubelet、kube-scheduler、kube-controller-manager、kube-apiserver,Node节点上运行了kubelet和kube-proxy。有些组件是容器化方式运行的,当然包括我们的应用。因此日志就分为两类:容器化组件及应用的日志,非容器化组件的日志。
2.1.1 容器化组件及应用的日志管理
对于容器化的组件和应用,其日志的管理方式都通过Docker的log-driver来进行指定,因此Kubernetes本身并不提供日志分割的功能。有两种方式来实现日志的分割:
- 通过Docker配置
log-opt
参数,与上一节的方式相同。 - 通过其他的脚本,例如kube-up.sh来分割日志文件。
如果使用外部工具对日志进行了分割,再通过
docker logs
目录查看日志时,仅返回最新的文件中的内容。
2.1.2 非容器化的组件日志管理。
系统组件也分为两种,一种是运行在容器中的应用,包括scheduler
、kube-proxy
等;一种是没有运行在容器中的应用,包括kubelet
和容器运行环境。这些组件的日志都是通过journald
来进行管理的。
2.2 集群级别的日志管理
Kubernetes本身没有提供集群级别的日志管理功能,如想实现集群级别的日志管理有三种方案:
- 在每个Node中运行日志采集代理,将日志收集到集中的日志管理平台。这种方案对应用没有侵入性,是优选方案。
- 在前一种方案的基础上,在每个应用Pod中增加Sidecar容器来实现日志的分离。
- 应用直接将日志输出到统一的日志管理平台,不在本地落地,这种方案对于应用的侵入性较大
2.3.1 日志采集代理方案
这种方案在每台Node上运行一个专用的日志采集代理,可以是容器化的应用(需要能够在容器内访问节点上的日志文件),可以采用DaemonSet
来确保代理在每个Node中都运行。
2.3.2 Sidecar方案
Sidecar的本意是挎斗摩托车,这种车型在摩托车旁边加了一个边斗来提高运载量,是二战时期日军广泛使用的一种运输工具。
类似于挎斗摩托车,Sidecar方案是在应用Pod中增加一个或多个负责处理日志的容器,根据增加容器的作用,可以分为日志分离和容器内代理。
2.3.2.1 日志分离
尽管CPU和内存资源的消耗非常少,但是读取日志文件并且重写到标准输出会加倍磁盘的负载,这一点需要特别注意。
2.3.2.2 容器内代理
采用这种方案,通过容器内代理直接将应用的日志上传到统一的日志管理平台,会增加Pod的资源消耗,同时无法通过kubectl logs
命令来查看日志。
2.3.3 流式处理方案
这种方案需要对应用做改造,应用通过流式日志的接口,直接将日志发送到在线的日志集群中。好处是无论Pod发生重启、迁移等不可预知的操作,只要服务能够起来,都能够将日志发送并保存下来。
参考资料
- Logging Architecture
- Docker日志都在哪里?怎么收集?
- Systemd之journalctl
- Kubectl logs
- Docker Logging Overview
- fluentd
- Stackdriver
- TLDC
- Kubernetes日志收集
- Kubernetes容器集群中的日志系统集成实践
- Where are the Kubernetes kublet logs located?
- Kubernetes Log Analysis with Fluentd, Elasticsearch and Kibana
- Kubernetes Log File Locations
- Kubernetes Logs