目录隐藏 |
Docker 日志都在哪里?怎么收集? | |
日志分两类,一类是 Docker 引擎日志;另一类是 容器日志。 Docker 引擎日志 Docker 引擎日志 一般是交给了 Upstart(Ubuntu 14.04) 或者 systemd (CentOS 7, Ubuntu 16.04)。前者一般位于 /var/log/upstart/docker.log 下,后者一般通过 jounarlctl -u docker 来读取。不同系统的位置都不一样,SO上有人总结了一份列表,我修正了一下,可以参考: 系统 日志位置 Ubuntu(14.04) /var/log/upstart/docker.log Ubuntu(16.04) journalctl -u docker.service CentOS 7/RHEL 7/Fedora journalctl -u docker.service CoreOS journalctl -u docker.service OpenSuSE journalctl -u docker.service OSX ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/log/docker.log Debian GNU/Linux 7 /var/log/daemon.log Debian GNU/Linux 8 journalctl -u docker.service Boot2Docker /var/log/docker.log 容器日志 容器的日志 则可以通过 docker logs 命令来访问,而且可以像 tail -f 一样,使用 docker logs -f 来实时查看。如果使用 Docker Compose,则可以通过 docker-compose logs <服务名> 来查看。 如果深究其日志位置,每个容器的日志默认都会以 json-file 的格式存储于 /var/lib/docker/containers/<容器id>/<容器id>-json.log 下,不过并不建议去这里直接读取内容,因为 Docker 提供了更完善地日志收集方式 - Docker 日志收集驱动。 关于日志收集,Docker 内置了很多日志驱动,可以通过类似于 fluentd, syslog 这类服务收集日志。无论是 Docker 引擎,还是容器,都可以使用日志驱动。比如,如果打算用 fluentd 收集某个容器日志,可以这样启动容器: $ docker run -d \ --log-driver=fluentd \ --log-opt fluentd-address=10.2.3.4:24224 \ --log-opt tag="docker.{{.Name}}" \ nginx 其中 10.2.3.4:24224 是 fluentd 服务地址,实际环境中应该换成真实的地址。 具体使用 fluentd 的方法,请参考我写的一组 fluentd 日志收集的例子: https://coding.net/u/twang2218/p/docker-example/git/tree/master/fluentd |
|
不同容器的日志汇聚到 fluentd 后如何区分? | |
有两种概念的区分,一种是区分开不同容器的日志,另一种是区分开来不同服务的日志。 区分不同容器的日志是很直观的想法。运行了几个不同的容器,日志都送向日志收集,那么显然不希望 nginx 容器的日志和 MySQL 容器的日志混杂在一起看。 但是在 Swarm 集群环境中,区分容器就已经不再是合理的做法了。因为同一个服务可能有许多副本,而又有很多个服务,如果一个个的容器区分去分析,很难看到一个整体上某个服务的服务状态是什么样子的。而且,容器是短生存周期的,在维护期间容器生存死亡是很常见的事情。如果是像传统虚拟机那样子以容器为单元去分析日志,其结果很难具有价值。因此更多的时候是对某一个服务的日志整体分析,无需区别日志具体来自于哪个容器,不需要关心容器是什么时间产生以及是否消亡,只需要以服务为单元去区分日志即可。 这两类的区分日志的办法,Docker 都可以做到,这里我们以 fluentd 为例说明。 version: '2' services: web: image: nginx:1.11-alpine ports: - "3000:80" labels: section: frontend group: alpha service: web image: nginx base_os: alpine logging: driver: fluentd options: fluentd-address: "localhost:24224" tag: "frontend.web.nginx.{{.Name}}" labels: "section,group,service,image,base_os" 这里我们运行了一个 nginx:alpine 的容器,服务名为 web。容器的日志使用 fluentd 进行收集,并且附上标签 frontend.web.nginx.<容器名>。除此以外,我们还定义了一组 labels,并且在 logging 的 options 中的 labels 中指明希望哪些标签随日志记录。这些信息中很多一部分都会出现在所收集的日志里。 让我们来看一下 fluentd 收到的信息什么样子的。 { "frontend.web.nginx.service_web_1": { "image": "nginx", "base_os": "alpine", "container_id": "f7212f7108de033045ddc22858569d0ac50921b043b97a2c8bf83b1b1ee50e34", "section": "frontend", "service": "web", "log": "172.20.0.1 - - [09/Dec/2016:15:02:45 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.49.1\" \"-\"", "group": "alpha", "container_name": "/service_web_1", "source": "stdout", "remote": "172.20.0.1", "host": "-", "user": "-", "method": "GET", "path": "/", "code": "200", "size": "612", "referer": "-", "agent": "curl/7.49.1", "forward": "-" } } 如果去除 nginx 正常的访问日志项目外,我们就可以更清晰的看到有哪些元数据信息可以利用了。 { "frontend.web.nginx.service_web_1": { "image": "nginx", "base_os": "alpine", "container_id": "f7212f7108de033045ddc22858569d0ac50921b043b97a2c8bf83b1b1ee50e34", "section": "frontend", "service": "web", "group": "alpha", "container_name": "/service_web_1", "source": "stdout", } } 可以看到,我们在 logging 下所有指定的 labels 都在。我们完全可以对每个服务设定不同的标签,通过标签来区分服务。比如这里,我们对 web 服务指定了 service=web 的标签,我们同样可以对数据库的服务设定标签为 service=mysql,这样在汇总后,只需要对 service 标签分组过滤即可,分离聚合不同服务的日志。 此外,我们可以设置不止一个标签,比如上面的例子,我们设置了多组不同颗粒度的标签,在后期分组的时候,可以很灵活的进行组合,以满足不同需求。 此外,注意 frontend.web.nginx.service_web_1,这是我们之前利用 --log-opt tag=frontend.web.nginx.<容器名> 进行设定的,其中 <容器名> 我们使用的是 Go 模板表达式 {{.Name}}。Go 模板很强大,我们可以用它实现非常复杂的标签。在 fluentd 中,项可以根据标签来进行筛选。 这里可以唯一表示容器的,有容器 ID container_id,而容器名 container_name 也从某种程度上可以用来区分不同容器。因此进行容器区分日志的时候,可以使用这两项。 还有一个 source,这表示了日志是从标准输出还是标准错误输出得到的,由此可以区分正常日志和错误日志。 现在我们可以知道,除了容器自身输出的信息外,Docker 还可以为每一个容器的日志添加很多元数据,以帮助后期的日志处理中应对不同需求的搜索和过滤。 在后期处理中,fluentd 中可以利用或者插件根据 tag 或者其它元数据进行分别处理。而日志到了 ElasticSearch 这类系统后,则可以用更丰富的查询语言进行过滤、聚合。 |