OpenKruise x iLogtail:管理可观测数据采集Sidecar容器最佳实践

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 在Kubernetes集群中使用Sidecar容器采集业务容器的可观测性数据是一种常见的数据采集部署方式,然而Sidecar容器对业务部署的侵入性和生命周期管理的复杂性使得这种部署模式的管理代价不仅高昂而且容易出错。本文对Sidecar采集容器管理的难点进行分析,使用OpenKruise提供的管理能力逐一解决,并以iLogtail为例给出基于OpenKruise管理可观测数据采集Sidecar容器的最佳实践。

Sidecar部署方式的使用场景

可观测系统是IT系统的眼睛,在K8S的 官方文档中介绍了多种的可观测数据采集形式,总结起来主要有下述3种:原生方式、DaemonSet方式和Sidecar方式。 三种方式都有利有弊,没有哪种方式能够完美的解决100%问题的,所以要根据场景来贴合。其中Sidecar方式为每个Pod单独部署采集agent,相对资源占用较多,但稳定性、灵活性以及多租户隔离性较强,建议在Job类任务采集场景或作为PaaS平台为多个业务方服务的集群使用该方式。

  • 稳定性:Sidecar采集方式利用K8s同一个Pod内的容器可以共享存储和网络的特性,无容器发现过程。同时只要采集容器没有退出,共享存储卷上的文件就不会被删除,因此无论是业务容器的生命周期非常短或是日志采集出现延时的情况都可以保证采集数据的完整性。
  • 灵活性:作为在每个Pod单独部署的Agent,为其分配多少资源、采集哪些数据都可以根据业务需求定制,甚至不同业务可以因不同采集需求而部署不同种类和版本的Agent。
  • 多租户隔离性:各个Sidecar容器内部署的Agent仅能观测到各自Pod内的数据,无法获取其他租户的信息。Agent之间互相独立运行,当某个Agent崩溃或无法正常采集数据时,同节点上的其他Agent仍然可以正常工作。

K8s Sidecar模式的痛点

使用K8s Sidecar模式采集业务可观测性数据需要修改业务的部署声明,将采集Agent容器与业务App容器部署在同一个Pod内,并通过共享Volume和网络使Agent可以采集数据并上传。如果要做到数据采集在任何情况下都不发生丢失,那么还需要确保Agent进程在业务App进程启动前启动、Agent进程在App进程结束后退出。对于Job类型的工作负载还需要考虑如何使Agent在App容器完成后主动退出的问题。因此,下面以iLogtail作为采集Agent为例,给出通用的Sidecar采集部署配置。

iLogtail是阿里云开源的一款高性能的轻量级可观测性数据采集Agent,支持多种Logs、Traces、Metrics可观测数据采集到Kafka、ElasicSearch、ClickHouse等多种下游中,其稳定性已在阿里巴巴以及数万阿里云客户生产中使用验证。

apiVersion: batch/v1
kind: Job
metadata:
  name: nginx-mock
  namespace: default
spec:
  template:
    metadata:
      name: nginx-mock
    spec:
      restartPolicy: Never
      containers:
        - name: nginx
          image: registry.cn-hangzhou.aliyuncs.com/log-service/docker-log-test:latest
          command: ["/bin/sh", "-c"]
          args:
            - until [[ -f /tasksite/cornerstone ]]; do sleep 1; done;
              /bin/mock_log --log-type=nginx --path=/var/log/nginx/access.log --total-count=100;
              retcode=$?;
              touch /tasksite/tombstone;
              exit $retcode
              # 通知Sidecar容器业务完成,否则Sidecar不会随业务容器退出
          volumeMounts:
            # 通过volumeMounts与iLogtail sidecar容器共享 log 目录
            - mountPath: /var/log/nginx
              name: log
            # 通过volumeMounts与iLogtail sidecar容器通信进程状态
            - mountPath: /tasksite
              name: tasksite
        # iLogtail Sidecar
        - name: ilogtail
          image: sls-opensource-registry.cn-shanghai.cr.aliyuncs.com/ilogtail-community-edition/ilogtail:latest
          command: ["/bin/sh", "-c"]
          # 第一个`sleep 10`的目的是等待iLogtail开始采集。iLogtail可能需要等从远端成功拉取配置后才开始采集。
          # 第二个`sleep 10`的目的是等待iLogtail完成采集。直到iLogtail将所有收集数据发送给下游才算完成采集。
          args:
            # 通知业务容器Sidecar就绪
            - /usr/local/ilogtail/ilogtail_control.sh start;
              sleep 10;
              touch /tasksite/cornerstone;
              until [[ -f /tasksite/tombstone ]]; do sleep 1; done;
              sleep 10;
              /usr/local/ilogtail/ilogtail_control.sh stop;
          volumeMounts:
            - name: log
              mountPath: /var/log/nginx
            - name: tasksite
              mountPath: /tasksite
            - mountPath: /usr/local/ilogtail/ilogtail_config.json
              name: ilogtail-config
              subPath: ilogtail_config.json
      volumes:
        - name: log
          emptyDir: {
   
   }
        - name: tasksite
          emptyDir:
            medium: Memory
        - name: ilogtail-config
          secret:
            defaultMode: 420
            secretName: ilogtail-secret

配置中的volumeMounts部分声明了共享存储,其中name为log的用于共享数据,name为tasksite的用于进程协调。args部分大量代码用于控制Sidecar和业务容器间进程的启动及退出顺序。通过以上配置代码可以看到,Sidecar模式存在如下一些弊端:

  • 业务Pod耦合(运维、代理)多种Sidecar容器,增加业务开发人员的学习成本。
  • Pod中的多个Sidecar容器和业务需要考虑运行依赖关系,增加了配置的复杂性。
  • Sidecar容器升级将导致业务Pod重建,由于Sidecar容器一般是独立的中间件团队负责,如果升级会存在极大的业务方阻力。

OpenKruise管理Sidecar容器的利器

SidecarSet

SidecarSet是OpenKruise中针对Sidecar容器管理抽象出来的概念,负责注入和升级K8s集群中的Sidecar容器,是OpenKruise的核心workload之一,详细可参考:SidecarSet文档

  • 自动注入Sidecar:将Sidecar容器配置与业务Workload(Deployment、CloneSet等)配置解耦,简化用户使用成本。
  • 独立升级Sidecar容器:不重建Pod,单独升级Sidecar容器,对业务无感。

Container Launch Priority

Container Launch Priority 提供了控制一个 Pod 中容器启动顺序的方法,详细可参考:Container Launch Priority文档

  • 控制一个 Pod 中容器启动顺序:按声明中的顺序启动或根据自定义顺序启动,简化配置。

Job Sidecar Terminator

对 Job 类型的 Workload 提供业务主容器完成任务并退出后,通知日志收集等 Sidecar 容器退出的能力,详细可参考:Job Sidecar Terminator文档

  • 提供 Job Sidecar 主动退出能力:主容器退出后通知 Sidecar容器退出,从而使得 Job Controller 能够正确完成,简化配置。

iLogtail Sidecar部署实践

社区中有很多应用iLogtail部署可观测方案的案例,参考Kubernetes使用iLogtail社区版使用案例。本文聚焦如何使用OpenKruise的上述能力简化iLogtail Sidecar的管理,如果遇到iLogtail方面的问题请到GitHub Discussions提问。

OpenKruise Feature Gate

在kruise-controller-manager Deployment中启用SidecarTerminator特性,另外两项特性默认打开。

    spec:
      containers:
        - args:
            - '--enable-leader-election'
            - '--metrics-addr=:8080'
            - '--health-probe-addr=:8000'
            - '--logtostderr=true'
            - '--leader-election-namespace=kruise-system'
            - '--v=4'
            - '--feature-gates=SidecarTerminator=true'
            - '--sync-period=0'

iLogtail SidecarSet

ConfigServer开源版中创建iLogtail采集配置,如下:

enable: true
inputs:
  - Type: file_log
    LogPath: /var/log/nginx
    FilePattern: access.log
flushers:
  - Type: flusher_kafka
    Brokers:
      - <kafka_host>:<kafka_port>
      - <kafka_host>:<kafka_port>
    Topic: nginx-access-log

关联到机器组

定义iLogtail SidecarSet配置,如下:

apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
  name: ilogtail-sidecarset
spec:
  selector:
    # 需要注入 sidecar 容器的 pod labels
    matchLabels:
      kruise.io/inject-ilogtail: "true"
  # SidecarSet默认是对整个集群生效,可以通过namespace字段指定生效的范围
  namespace: default
  containers:
    - command:
        - /bin/sh
        - '-c'
        - '/usr/local/ilogtail/ilogtail_control.sh start_and_block 10'
        # 参数10的目的是等待10秒数据发送完毕后退出
      image: sls-opensource-registry.cn-shanghai.cr.aliyuncs.com/ilogtail-community-edition/ilogtail:edge
      livenessProbe:
        exec:
          command:
            - /usr/local/ilogtail/ilogtail_control.sh
            - status
      name: ilogtail
      env:
        - name: KRUISE_CONTAINER_PRIORITY
          value: '100'
        - name: KRUISE_TERMINATE_SIDECAR_WHEN_JOB_EXIT
          value: 'true'
        - name: ALIYUN_LOGTAIL_USER_DEFINED_ID
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: 'metadata.labels[''ilogtail-tag'']'
      volumeMounts:
        - mountPath: /var/log/nginx
          name: log
        - mountPath: /usr/local/ilogtail/checkpoint
          name: checkpoint
        - mountPath: /usr/local/ilogtail/ilogtail_config.json
          name: ilogtail-config
          subPath: ilogtail_config.json
  volumes:
    - name: log
      emptyDir: {
   
   }
    - name: checkpoint
      emptyDir: {
   
   }
    - name: ilogtail-config
      secret:
        defaultMode: 420
        secretName: ilogtail-secret

注意,此处仅写了livenessProbe,请勿使用readinessProbe,否则后续Sidecar容器升级时会导致Pod状态先变成Not Ready。

针对机器资源不太充足的场景,为减少Pod资源的申请,可以将Sidecar container request.cpu=0,此种情况下Pod的QoS将会是 Burstable

自动注入iLogtail Sidecar容器

定义Nginx Mock Job,只包含 nginx 相关配置,如下:

apiVersion: batch/v1
kind: Job
metadata:
  name: nginx-mock
  namespace: default
spec:
  template:
    metadata:
      name: nginx-mock
      labels:
        # 注入 ilogtail sidecar 容器的label
        kruise.io/inject-ilogtail: "true"
    spec:
      restartPolicy: Never
      containers:
        - name: nginx
          image: registry.cn-hangzhou.aliyuncs.com/log-service/docker-log-test:latest
          command: ["/bin/sh", "-c"]
          args:
            - /bin/mock_log --log-type=nginx --path=/var/log/nginx/access.log --total-count=100
          volumeMounts:
          # 通过volumeMounts与iLogtail sidecar容器共享 log 目录
          - mountPath: /var/log/nginx
            name: log
      volumes:
        - name: log
          emptyDir: {
   
   }
        - name: tasksite
          emptyDir:
            medium: Memory

将Nginx Mock Job Apply到K8s集群后,发现创建的Pod都被注入了 iLogtail Sidecar 容器,说明kruise.io/inject-ilogtail: "true"起到了效果,如下:

若没有此项配置,将只有nginx container而没有ilogtail container。

通过查阅K8s事件可知,ilogtail container优先于nginx container创建,说明KRUISE_CONTAINER_PRIORITY起到了效果,如下:

若没有此项配置,ilogtail container可能晚于nginx container启动,导致采集数据不完整。

通过查阅K8s事件还可知,ilogtail container在nginx container完成后退出,说明KRUISE_TERMINATE_SIDECAR_WHEN_JOB_EXIT起到了效果,如下:

若没有此项配置,Pod将一直处于Running状态,因为Sidecar不会随业务容器退出,除非手动Delete Job。

以上两项Sidecar容器启动和退出的正确顺序保证了iLogtail采集数据的完整性。查询采集到Kafka的数据,从点位计算可知,数据采集完整,共100条(92-40+106-58=100),如下:

独立升级iLogtail Sidecar容器(edge -> latest)

我们将上面iLogtail SidecarSet的配置更新为latest并apply。

      image: sls-opensource-registry.cn-shanghai.cr.aliyuncs.com/ilogtail-community-edition/ilogtail:latest

通过K8s事件可以发现Pod并没有重建,ilogtail容器由于声明发生了变化进行了重建,而同时nginx容器并没有受影响中断。如下:

该特性依赖Kruise原地升级的能力实现,详情参考文档:Kruise原地升级。 不过独立升级sidecar容器也存在一定的风险性,如果sidecar容器升级过程中失败,则将导致Pod Not Ready,进而影响业务,因此SidecarSet本身提供了非常丰富的灰度发布能力来尽量规避该风险, 详情参考文档:Kruise SidecarSet,如下:

apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
  name: sidecarset
spec:
  # ...
  updateStrategy:
    type: RollingUpdate
    # 最大不可用数量
    maxUnavailable: 20%
    # 分批发布
    partition: 90
    # 金丝雀发布,通过pod labels
    selector:
      matchLabels:
        # Some Pods contain canary labels,
        # or any other labels where a small number of pods can be selected
        deploy-env: canary

另外,如果是类似于ServiceMesh Envoy Mesh类容器则需要借助于SidecarSet热升级特性,详情请参考:SidecarSet热升级

Argo-cd部署SidecarSet(Optional)

如果使用Argo-cd发布Kruise SidecarSet,则需要配置 SidecarSet Custom CRD Health Checks。 Argo-cd根据该配置能够实现SidecarSet自定义资源的检查,如SidecarSet是否发布完成,以及Pod是否ready等,如下:

apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    app.kubernetes.io/name: argocd-cm
    app.kubernetes.io/part-of: argocd
  name: argocd-cm
  namespace: argocd
data:
  resource.customizations.health.apps.kruise.io_SidecarSet: |
    hs = {}
    -- if paused
    if obj.spec.updateStrategy.paused then
      hs.status = "Suspended"
      hs.message = "SidecarSet is Suspended"
      return hs
    end

    -- check sidecarSet status
    if obj.status ~= nil then
      if obj.status.observedGeneration < obj.metadata.generation then
        hs.status = "Progressing"
        hs.message = "Waiting for rollout to finish: observed sidecarSet generation less then desired generation"
        return hs
      end

      if obj.status.updatedPods < obj.spec.matchedPods then
        hs.status = "Progressing"
        hs.message = "Waiting for rollout to finish: replicas hasn't finished updating..."
        return hs
      end

      if obj.status.updatedReadyPods < obj.status.updatedPods then
        hs.status = "Progressing"
        hs.message = "Waiting for rollout to finish: replicas hasn't finished updating..."
        return hs
      end

      hs.status = "Healthy"
      return hs
    end

    -- if status == nil
    hs.status = "Progressing"
    hs.message = "Waiting for sidecarSet"
    return hs

总结

Pod包含多个container的方式将越来越被更多的开发者接受,进而K8S生态里面急需一种能够有效管理Sidecar容器的方式。 Kruise SidecarSet、Container Launch Priority、Job Sidecar Terminator等功能是在Sidecar容器管理上面的一些探索,

使用OpenKruise管理iLogtail日志采集大幅降低了管理Sidecar的难度,解耦了Sidecar和业务容器的配置,使得容器间的启动顺序维护变得清晰,并且支持不重建Pod更新Sidecar容器。但是我们也看到比如Sidecar容器应该分配多少资源、日志路径挂载如何规划、不同业务Pod中的Sidecar的配置如何区分等问题并没有完全解决。 所以,我们也希望能够与社区的更多开发者一起探索,同时也欢迎大家都能提供一些思路,共同繁荣K8S生态。

加入钉钉群聊OpenKruise 社区:https://qr.dingtalk.com/action/joingroup?code=v1,k1,24NpKJPrv75JraA8vb/T8W8aTXpc97wboFP2cOjSL4U=&_dt_no_comment=1&origin=1


加入钉钉群聊iLogtail社区:https://qr.dingtalk.com/action/joingroup?code=v1,k1,A7uxZF3XMTsiAL3GGd18DZFGmAHD1QVijwkYzxCl8Lc=&_dt_no_comment=1&origin=11

相关文章
|
15天前
|
Kubernetes 监控 开发者
掌握容器化:Docker与Kubernetes的最佳实践
【10月更文挑战第26天】本文深入探讨了Docker和Kubernetes的最佳实践,涵盖Dockerfile优化、数据卷管理、网络配置、Pod设计、服务发现与负载均衡、声明式更新等内容。同时介绍了容器化现有应用、自动化部署、监控与日志等开发技巧,以及Docker Compose和Helm等实用工具。旨在帮助开发者提高开发效率和系统稳定性,构建现代、高效、可扩展的应用。
|
1月前
|
缓存 监控 测试技术
掌握容器化持续集成/持续部署(CI/CD)的最佳实践
【10月更文挑战第8天】本文介绍了容器化持续集成/持续部署(CI/CD)的最佳实践,涵盖容器化CI/CD的概念、优势和实施步骤。通过使用容器技术,可以实现环境一致性、快速迭代和易于扩展,提高软件开发的效率和可靠性。文章还详细讨论了编写高效的Dockerfile、自动化测试、安全性、监控和日志管理等方面的最佳实践。
|
2月前
|
Kubernetes API Docker
跟着iLogtail学习容器运行时与K8s下日志采集方案
iLogtail 作为开源可观测数据采集器,对 Kubernetes 环境下日志采集有着非常好的支持,本文跟随 iLogtail 的脚步,了解容器运行时与 K8s 下日志数据采集原理。
|
3月前
|
Kubernetes Cloud Native 开发者
OpenKruise:Kubernetes的超级插件,一键解锁容器运行时操作的超能力!
【8月更文挑战第8天】在云原生领域,Kubernetes虽已成为容器编排的标准,但仍有限制,比如批量操作不便和高级调度功能缺失。OpenKruise是一款增强工具,提供CloneSet、Advanced StatefulSet等功能,既保持Kubernetes API特性又增加了扩展性,使Pod管理更灵活。可通过Helm安装OpenKruise,并使用CloneSet轻松实现批量部署。这类增强工具让开发者能更高效地突破原生Kubernetes的限制,预计未来将更加受到欢迎。
65 8
|
6月前
|
监控 Java 网络性能优化
容器内存可观测性新视角:WorkingSet 与 PageCache 监控
本文介绍了 Kubernetes 中的容器工作内存(WorkingSet)概念,它用于表示容器内存的实时使用量,尤其是活跃内存。
56262 19
容器内存可观测性新视角:WorkingSet 与 PageCache 监控
|
4月前
|
存储 Linux 应用服务中间件
容器卷管理
容器卷管理
30 2
|
3月前
|
人工智能 Kubernetes 持续交付
Kubernetes环境下基于微服务架构的容器化AI应用部署与管理最佳实践
【8月更文第19天】随着AI技术的快速发展,越来越多的企业开始将AI应用部署到生产环境。然而,AI应用往往包含大量的组件和服务,这使得其部署和管理变得非常复杂。微服务架构和容器化技术(如Docker)结合Kubernetes集群管理,为解决这些问题提供了强大的工具。本文将介绍如何在Kubernetes环境中部署和管理基于微服务架构的容器化AI应用。
179 0
|
3月前
|
数据采集 监控 Kubernetes
Job类日志采集问题之iLogtail以减小容器发现和开始采集的延时如何优化
Job类日志采集问题之iLogtail以减小容器发现和开始采集的延时如何优化
|
4月前
|
安全 关系型数据库 开发者
Docker Compose凭借其简单易用的特性,已经成为开发者在构建和管理多容器应用时不可或缺的工具。
Docker Compose是容器编排利器,简化多容器应用管理。通过YAML文件定义服务、网络和卷,一键启动应用环境。核心概念包括服务(组件集合)、网络(灵活通信)、卷(数据持久化)。实战中,编写docker-compose.yml,如设置Nginx和Postgres服务,用`docker-compose up -d`启动。高级特性涉及依赖、环境变量、健康检查和数据持久化。最佳实践涵盖环境隔离、CI/CD、资源管理和安全措施。案例分析展示如何构建微服务应用栈,实现一键部署。Docker Compose助力开发者高效驾驭复杂容器场景。
70 1
|
5月前
|
机器学习/深度学习 Kubernetes 算法框架/工具
容器服务 ACK 大模型推理最佳实践系列一:TensorRT-LLM
在 ACK 中使用 KServe 部署 Triton+TensorRT-LLM