Kubernetes 集群日志记录须知

探索 Kubernetes 中不同的容器日志记录模式是如何工作的。
50 位读者喜欢这篇文章。
Kubernetes

Jason Baker. CC BY-SA 4.0.

服务器和应用程序日志记录是开发人员、运维人员和安全团队了解应用程序在其生产环境中运行状态的重要工具。

日志记录允许运维人员确定应用程序和所需的组件是否运行顺畅,并检测是否发生了异常情况,以便他们能够对情况作出反应。

对于开发人员来说,日志记录提供了在开发期间和之后对代码进行故障排除的可见性。 在生产环境中,开发人员通常依赖于日志记录工具,而不是调试工具。 结合来自系统的日志记录,开发人员可以与运维人员携手合作,有效地解决问题。

日志记录功能最重要的受益者是安全团队,尤其是在云原生环境中。 能够从应用程序和系统日志中收集信息,使安全团队能够分析来自身份验证、应用程序访问和恶意软件活动的数据,并在需要时对其做出响应。

Kubernetes 是领先的容器平台,越来越多的应用程序部署在生产环境中。 我相信,理解 Kubernetes 的日志记录架构对于每个开发、运维和安全团队来说都是一项非常重要的工作。

在本文中,我将讨论 Kubernetes 中不同的容器日志记录模式是如何工作的。

系统日志记录和应用程序日志记录

在我深入研究 Kubernetes 日志记录架构之前,我想先探讨不同的日志记录方法,以及这两种功能如何成为 Kubernetes 日志记录的关键特性。

有两种类型的系统组件:一种是在容器中运行的,另一种是不在容器中运行的。 例如

  • Kubernetes 调度器和 kube-proxy 在容器中运行。
  • kubelet 和容器运行时不在容器中运行。

与容器日志类似,系统容器日志存储在 /var/log 目录中,你应该定期轮换它们。

在这里我考虑容器日志记录。 首先,我来看一下集群级别的日志记录以及为什么它对集群运维人员很重要。 集群日志提供有关集群性能的信息。 诸如 Pod 为何被驱逐或节点死亡之类的信息。 集群日志记录还可以捕获诸如集群和应用程序访问以及应用程序如何利用计算资源之类的信息。 总的来说,集群日志记录工具为集群运维人员提供了对集群运行和安全有用的信息。

捕获容器日志的另一种方法是通过应用程序的本机日志记录工具。 现代应用程序设计很可能具有一种日志记录机制,该机制通过标准输出 (stdout) 和错误流 (stderr) 帮助开发人员解决应用程序性能问题。

为了拥有有效的日志记录工具,Kubernetes 实现需要应用程序和系统日志记录组件。

Kubernetes 容器日志记录的 3 种类型

在大多数 Kubernetes 实现中,你可以看到三种突出的集群级别日志记录方法。

  1. 节点级别日志记录代理
  2. 用于日志记录的 Sidecar 容器应用程序
  3. 将应用程序日志直接公开给日志记录后端

节点级别日志记录代理

我想考虑一下节点级别的日志记录代理。 你通常使用 DaemonSet 作为部署策略来实现这些,以在所有 Kubernetes 节点中部署 Pod(充当日志记录代理)。 然后配置此日志记录代理以从所有 Kubernetes 节点读取日志。 你通常配置代理以读取节点 /var/logs 目录,捕获 stdout/stderr 流并将其发送到日志记录后端存储。

下图显示了作为代理在所有节点中运行的节点级别日志记录。

要使用 fluentd 方法设置节点级别日志记录,你需要执行以下操作:

  1. 首先,你需要创建一个名为 fluentdd 的 ServiceAccount。 Fluentd Pod 使用此服务帐户来访问 Kubernetes API,你需要使用标签 app: fluentd 在日志记录命名空间中创建它们。
    #fluentd-SA.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: fluentd
      namespace: logging
      labels:
        app: fluentd

    你可以在此 repo 中查看完整的示例。

  2. 然后,你需要创建一个 ConfigMap fluentd-configmap。 这为 fluentd daemonset 提供了一个包含所有必需属性的配置文件。
    #fluentd-daemonset.yaml
    apiVersion: extensions/v1beta1
    kind: DaemonSet
    metadata:
      name: fluentd
      namespace: logging
      labels:
        app: fluentd
        kubernetes.io/cluster-service: "true"
    spec:
      selector:
        matchLabels:
          app: fluentd
          kubernetes.io/cluster-service: "true"
      template:
        metadata:
          labels:
            app: fluentd
            kubernetes.io/cluster-service: "true"
        spec:
          serviceAccount: fluentd
          containers:
          - name: fluentd
            image: fluent/fluentd-kubernetes-daemonset:v1.7.3-debian-elasticsearch7-1.0
            env:
              - name:  FLUENT_ELASTICSEARCH_HOST
                value: "elasticsearch.logging.svc.cluster.local"
              - name:  FLUENT_ELASTICSEARCH_PORT
                value: "9200"
              - name: FLUENT_ELASTICSEARCH_SCHEME
                value: "http"
              - name: FLUENT_ELASTICSEARCH_USER
                value: "elastic"
              - name: FLUENT_ELASTICSEARCH_PASSWORD
                valueFrom:
                  secretKeyRef:
                    name: efk-pw-elastic
                    key: password
              - name: FLUENT_ELASTICSEARCH_SED_DISABLE
                value: "true"
            resources:
              limits:
                memory: 512Mi
              requests:
                cpu: 100m
                memory: 200Mi
            volumeMounts:
            - name: varlog
              mountPath: /var/log
            - name: varlibdockercontainers
              mountPath: /var/lib/docker/containers
              readOnly: true
            - name: fluentconfig
              mountPath: /fluentd/etc/fluent.conf
              subPath: fluent.conf
          terminationGracePeriodSeconds: 30
          volumes:
          - name: varlog
            hostPath:
              path: /var/log
          - name: varlibdockercontainers
            hostPath:
              path: /var/lib/docker/containers
          - name: fluentconfig
            configMap:
              name: fluentdconf

    你可以在此 repo 中查看完整的示例。

现在,我来看看如何将 fluentd daemonset 部署为日志代理的代码。

#fluentd-daemonset.yaml
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: logging
  labels:
    app: fluentd
    kubernetes.io/cluster-service: "true"
spec:
  selector:
    matchLabels:
      app: fluentd
      kubernetes.io/cluster-service: "true"
  template:
    metadata:
      labels:
        app: fluentd
        kubernetes.io/cluster-service: "true"
    spec:
      serviceAccount: fluentd
      containers:
      - name: fluentd
        image: fluent/fluentd-kubernetes-daemonset:v1.7.3-debian-elasticsearch7-1.0
        env:
          - name:  FLUENT_ELASTICSEARCH_HOST
            value: "elasticsearch.logging.svc.cluster.local"
          - name:  FLUENT_ELASTICSEARCH_PORT
            value: "9200"
          - name: FLUENT_ELASTICSEARCH_SCHEME
            value: "http"
          - name: FLUENT_ELASTICSEARCH_USER
            value: "elastic"
          - name: FLUENT_ELASTICSEARCH_PASSWORD
            valueFrom:
              secretKeyRef:
                name: efk-pw-elastic
                key: password
          - name: FLUENT_ELASTICSEARCH_SED_DISABLE
            value: "true"
        resources:
          limits:
            memory: 512Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
        - name: fluentconfig
          mountPath: /fluentd/etc/fluent.conf
          subPath: fluent.conf
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers
      - name: fluentconfig
        configMap:
          name: fluentdconf

总而言之:

kubectl apply -f fluentd-SA.yaml \
              -f fluentd-configmap.yaml \
              -f fluentd-daemonset.yaml

用于日志记录的 Sidecar 容器应用程序

另一种方法是使用带有日志记录代理的专用 Sidecar 容器。 Sidecar 容器最常见的实现是使用 Fluentd 作为日志收集器。 在企业部署中(你不用担心少量的计算资源开销),使用 fluentd(或 类似)实现的 Sidecar 容器比集群级别日志记录提供了更大的灵活性。 这是因为你可以根据日志的类型、频率以及需要捕获的其他可能的调整来调整和配置收集器代理。

下图显示了作为日志记录代理的 Sidecar 容器。

例如,一个 Pod 运行一个容器,该容器使用两种不同的格式写入两个不同的日志文件。 这是 Pod 的配置文件

#log-sidecar.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
    image: busybox
    args: [/bin/sh, -c, 'tail -n+1 -f /var/log/1.log']
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  volumes:
  - name: varlog
    emptyDir: {}

总而言之,你可以运行这个 Pod

$ kubectl apply -f log-sidecar.yaml

要验证 Sidecar 容器是否作为日志记录代理工作,你可以执行

$ kubectl logs counter count-log

预期的输出应如下所示

$ kubectl logs counter count-log-1

Thu 04 Nov 2021 09:23:21 NZDT
Thu 04 Nov 2021 09:23:22 NZDT
Thu 04 Nov 2021 09:23:23 NZDT
Thu 04 Nov 2021 09:23:24 NZDT

将应用程序日志直接公开给日志记录后端

第三种方法(我个人认为)是 Kubernetes 容器和应用程序日志最灵活的日志记录解决方案,它将日志直接推送到日志记录后端解决方案。 虽然此模式不依赖于 Kubernetes 的本机功能,但它提供了大多数企业需要的灵活性,例如

  1. 扩展对更广泛的网络协议和输出格式的支持。
  2. 允许负载均衡功能并提高性能。
  3. 可配置为通过上游聚合接受复杂的日志记录要求

由于第三种方法通过直接从每个应用程序推送日志来依赖于非 Kubernetes 功能,因此它超出了 Kubernetes 的范围。

结论

Kubernetes 日志记录工具是 Kubernetes 集群企业部署的一个非常重要的组件。 我讨论了三种可能的模式可供使用。 你需要找到适合你需求的模式。

如所示,使用 daemonset 的节点级别日志记录是最容易使用的部署模式,但它也有一些可能不符合你组织需求的限制。 另一方面,Sidecar 模式提供了灵活性和定制,允许你定制要捕获的日志类型,从而为你提供计算资源开销。 最后,将应用程序日志直接公开给后端日志工具是另一种有吸引力的方法,可以进一步定制。

选择权在你。 你只需要找到适合你组织需求的方法。

接下来阅读什么
标签
ID
Mike Calizo 是 Elastic.co 的首席客户成功经理,专注于政府客户,常驻澳大利亚堪培拉。 Mike 认为“数据就是力量”,利用这种力量可以改进组织,使其能够利用自己的见解,通过创新实现差异化,并通过成本优化策略提高效率。

评论已关闭。

Creative Commons License本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
© . All rights reserved.