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


    k8s容器日志收集方案

    一. 在Node上部署logging agent

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

    • 不难看到,这里的核心就在于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文件的写法如下:

      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文件。这对磁盘是很大的浪费。所以说,除非万不得已或者应用容器完全不能修改,否则还是建议你直接使用方案一,或者直接使用方案三。

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

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

    • 在这种方案里,你的应用还可以直接把日志输出到固定的文件里而不是stdout,你的logging-agent还可以使用fluentd,后端存储还可以是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来指定的。这里用到了Volume来把ConfigMap挂在到Pod里。

    • 这种方案部署简单,并且对宿主机非常友好,但是这个sidecar容器很可能会消耗较多的资源,甚至拖垮应用容器。由于日志没有输出到stdout上,所以你通过kubectl logs 是看不到日志信息的。

    总结

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

    转载: https://juejin.im/post/5cb939b0e51d456e311649e0

  • 相关阅读:
    Java实现 LeetCode 56 合并区间
    JQuery实现对html结点的操作(创建,添加,删除)
    JQuery实现对html结点的操作(创建,添加,删除)
    JQuery实现对html结点的操作(创建,添加,删除)
    Java实现 LeetCode 55 跳跃游戏
    Java实现 LeetCode 55 跳跃游戏
    Java实现 LeetCode 55 跳跃游戏
    Java实现 LeetCode 54 螺旋矩阵
    Java实现 LeetCode 54 螺旋矩阵
    Java实现 LeetCode 54 螺旋矩阵
  • 原文地址:https://www.cnblogs.com/peitianwang/p/11661369.html
Copyright © 2020-2023  润新知