• 第6章 日志问题


    6.1 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/d‌ocker.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

    6.2 不同容器的日志汇聚到 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 中,<match> 项可以根据标签来进行筛选。

    这里可以唯一表示容器的,有容器 ID container_id,而容器名 container_name 也从某种程度上可以用来区分不同容器。因此进行容器区分日志的时候,可以使用这两项。

    还有一个 source,这表示了日志是从标准输出还是标准错误输出得到的,由此可以区分正常日志和错误日志。

    现在我们可以知道,除了容器自身输出的信息外,Docker 还可以为每一个容器的日志添加很多元数据,以帮助后期的日志处理中应对不同需求的搜索和过滤。

    在后期处理中,fluentd 中可以利用 <match> 或者 <filter> 插件根据 tag 或者其它元数据进行分别处理。而日志到了 ElasticSearch 这类系统后,则可以用更丰富的查询语言进行过滤、聚合。

  • 相关阅读:
    ehcache 2.4 即将发布,亮点多多
    2010 年个人回忆与总结
    ehcache 2.4 即将发布,亮点多多
    JBoss Seam 3.0.0.Beta1 发布
    JBoss Seam 3.0.0.Beta1 发布
    jQuery 1.5 正式版如期发布
    jQuery 1.5 正式版如期发布
    Contracts for Java
    2010 年个人回忆与总结
    Contracts for Java
  • 原文地址:https://www.cnblogs.com/syavingcs/p/8400338.html
Copyright © 2020-2023  润新知