IT 铁人赛 k8s 入门30天 -- day20 k8s Logging Architecture

前言

参考来源: https://kubernetes.io/docs/concepts/cluster-administration/logging/

这个章节会来研究关於 k8s 的 Log 架构

应用程序的 log 能够帮助理解应用程序的运行状态

对於容器化的应用程序最基础的 log 方式就是透过 stream 的方式把 standard output 与 standard error 导出容器之外

然而只有应用程序层面的 log 对於容器状态的管控还是不够, 再跑容器时还想纪录关於容器的失败跑起来的纪录

在 k8s 会想纪录 Pod 的状态在 Pod 要关闭时, 在结点死掉时

而要这样做需要让 log 的生命周期独立於 nodes, pods, 还有 containers 并且具有额外的储存空间

这种概念称作 Cluster-level logging

Cluster-level logging 架构需要具有一个独立於 Cluster 之外的後端去储存, 分析, 跟查询 logs.

k8s 本身不具有原生提供的储存方案来处理 log 资料

目前有许多第三方 logging 方案有跟 k8s 整合

下面将依序说明这些方案

k8s 基础的 logging

以下用一个范例来示范

设定 counter-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)"; i=$((i+1)); sleep 1; done']

使用以下指令建立 Pod

kubectl apply -f counter-pod.yaml

察看 Pod 的 log 使用以下指令:

kubectl logs counter

在 node level 的 logging

container 引擎会把容器化应用的 stdout 跟 stderr 透过 stream 的方式导出

举例来说, Docker Engine 会透过 logger driver 来处理 stdout, stderr 到 JSON format 的 file

在 k8s 中, 如果一个 container 重新启动, kubelet 预设会保存该 container 的 log. 而如果一个 Pod 被从结点移除, 则所有相关的 Container 以及 log 都会被移除

在 node level 很重要的一个概念是要做 log rotation, 否则 log 将会随着运行占据太多空间

k8s 本身并不做这 log rotation 机制, 而是 Deployment 内部在 container 自行去设定各自的 log rotation

当使用一个 CRI container runtime, kubelet 会负责处理 log rotation 还有管理 logging 资料夹结构.

以下有两个参数可以设定在 kubelet config:

containerLogMaxSize 这个设定用来决定每个 log 档案大小

containerLogMaxFiles 这个设定用来决定最多几个档案

使用 kubelet logs 指令时, kubelet 会直接读取 log 档案来显示

系统元件 log

k8s 的系统元件分为两种: 跑在容器内与不跑在容器内的

举例来说:

k8s scheduler 还有 kube-proxy 跑在一个容器内

k8s kubelet 还有 container runtime 不跑在容器内

在有 systemd 的机器上, kubelet 跟 container runtime 会把 log 写入 journald

假设没有 systemd, 则kubelet 跟 container runtime 会把 log 写入 /var/log 下的 .log 党内

而跑在容器内的元件则固定写 log 到 /var/log 资料夹下

系统元件使用 klog 来当作 log 工具

系统元件有实作 log rotation 机制

Cluster-level 的 logging 架构

以下有几种选项是可行的方案

使用一个 node-level logging agent 来跑在每个 node


建立一个 node-level logging agent 在每个 node

这个 logging agent 本身就是负责发送 log 到後端

一般来说, 这个 logging agent 会是一个 container 举有一个资料架包含所有应用的log

因为这个 agent 要跑在所有 node, 建议使用 DaemonSet 来做布署

这种做不需要影响到其他的应用

引用 sidecar container 在 application Pod 做 logging

sidecar container 可以有两种作法:

1 sidecar container 直接串流应用程序的log 到自己的 stdout

使用 sidecar container 来建立 stdout, stderr stream, 就可以利用原本的 kubelet 以及 logging agent 功能

如此一来可以建立两个 stream 分别不同 format 格式分开

举例来说:

假设一个 Pod 跑在一个节点内要写入两个档案已两种不同的格式如下

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: {}

因为有两个档案 所以不建议都用 stdout来显示

这时候可以透过建立两个 sidecar Container 来做处理

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: {}

可以分别针对不同格式做 log

2 sidecar container 跑一个 logging agent, logging agent 负责把 应用程序的 log 串接回来

当 node-level 的 logging agent 不够弹性时, 就可以使用一个 sidecar container 来跑 logging agent

直接通过应用推送 log 到一个後端储存

直接从应用推送 log 到後端


<<:  [Day19] TS:什麽!泛型的参数还能有预设值?

>>:  [Day 19] - 初探永丰银行线上收款API - 订单查询及其他(1)

【Day10】AddInvitationFragment(下) X DatePickerDialog

接下上集!!,我们已经完成layout,还有上传照片了。那麽接下来我们要做的就是把选取时间的日历叫...

iOS工程师面试深入浅出(OC)- NSInterger 与 Int 有什麽不一样?

iOS工程师面试深入浅出(Objective-C)- NSInterger 与 Int 有什麽不一样...

DynamoDB汇出至S3

NoSQL资料除了前次的备份还原之外, 也可以汇出至S3当作额外备份, 或是给其他AWS服务使用. ...

Day-01 跻身铁人炼成钢

为什麽参加铁人赛? 庚子以来,世事舛变。文科人生,走马思迁。学习网页设计两月有余,深感最大问题不在无...

求救 各位linux大神! 关於mediapipe build 成apk的问题

在 build an Android example app 的时候:输入: bazel build...