十七. k8s--日志收集方案

k8s容器日志收集方案

一. 在Node上部署logging agent

将日志文件转发到后端存储里保存起来json

  • 不难看到,这里的核心就在于logging agent,它通常都会以DaemonSet的方式运行在节点上,而后将宿主机上的容器日志目录挂载进去,最后由logging-agent把日志转发出去。
  • 举个例子,咱们能够经过Fluentd项目做为宿主机上的logging-agent,而后把日志转发到远端的ElasticSearch里保存起来供未来进行检索。具体的操做过程官网不少kubernetes的部署里,会自动为你启用logrotate,在日志文件超过10MB的时候自动对日志文件进行roate操做。
  • 能够看到在Node上部署logging agent最大的优势,在于只须要部署一个agent,而且不会对应用和pod有任何入侵性。因此这个方案在社区里是最经常使用的一种。
  • 可是这种方案的不足之处就在于,它要求应用输出的日志,都必须是直接输出到容器的stdout和stderr里

二. 对特殊状况的一个处理

  • 当容器的日志只能输出到某些文件里的时候,咱们能够经过一个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: {}
  • 在这种状况下,你用kubectl logs命令是看不到应用的任何日志的。这时咱们就能够为这个pod添加两个sidecar容器,分别将上述两个日志文件里的内容从新以stdout和stderr的方式输出来,这个YAML文件的写法以下:api

    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: {}
  • 因为sidecar跟主容器之间是共享Volume的,因此这里的sidecar方案的额外性能损耗并不高,也就多占用一点cpu和内存。可是,这时候宿主机上实际会存在两份相同的日志文件:一份是应用本身写入的;另外一份是sidecar的stdout和stderr对应的json文件。这对磁盘是很大的浪费。因此说,除非万不得已或者应用容器彻底不能修改,不然仍是建议你直接使用方案一,或者直接使用方案三。app

三. 送过sidecar容器直接把日志文件发送到远程存储

  • 至关于把方案一里的logging agent,放在了应用pod里。

  • 在这种方案里,你的应用还能够直接把日志输出到固定的文件里而不是stdout,你的logging-agent还可使用fluentd,后端存储还能够是ElasticSearch。只不过,fluentd的输入源变成了应用的日志文件。通常来讲,咱们会把fluentd的输入源配置保存在一个ConfigMap里,以下因此:elasticsearch

    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中,这个配置,以下所示:ide

    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来指定的。这里用到了Volume来把ConfigMap挂在到Pod里。post

  • 这种方案部署简单,而且对宿主机很是友好,可是这个sidecar容器极可能会消耗较多的资源,甚至拖垮应用容器。因为日志没有输出到stdout上,因此你经过kubectl logs 是看不到日志信息的。性能

总结

以上,就是k8s最经常使用的三种收集日志的手段了,综合对比以上方案,比较建议你将应用日志输出到stdout和stderr,而后经过在宿主机上部署logging-agent的方式集中处理日志、这种方案不但简单,并且kubectl logs依然可使用,也是官方推荐的一种。google

转载: http://www.javashuo.com/article/p-dgjmrfdr-ea.html

相关文章
相关标签/搜索