向虚拟节点Pod注入Sidecar容器

OpenKruise SidecarSet采用Admission Webhook机制,在创建Pod的阶段对匹配了目标Label的所有Pod注入Sidecar容器。此时Pod还未调度到虚拟节点,无法仅对调度到虚拟节点的Pod生效。您可以借助虚拟节点组件(ACK Virtual Node)仅为调度到虚拟节点上的Pod自动注入Sidecar容器,来解耦虚拟节点Pod的Sidecar容器与业务容器

基本概念

  • Sidecar:一种将应用功能从应用本身剥离出来作为单独进程的设计方式。该模式允许您向应用无侵入添加多种功能,避免为满足第三方组件需求而向应用添加额外的配置代码。

  • Sidecar容器:将一个容器添加到另一个Pod中作为一个附加容器,以扩展和增强主容器,而无需改变主容器本身。

  • SidecarSet:是阿里云开源的云原生应用自动化引擎OpenKruise的核心功能之一。使用SidecarSet可以为集群中创建的符合条件的Pod自动注入Sidecar容器,实现Sidecar容器(如监控、日志等agent)的定义和生命周期与业务容器解耦。

使用限制

ACK Virtual Node组件支持OpenKruise v1.3及以下版本的SidecarSet全部功能,不支持1.3以上版本中新增的SidecarSet功能。

前提条件

  • 已创建Kubernetes版本为1.22及以上的ACK集群Pro版ACK Serverless集群Pro版或者ACK专有集群。具体操作,请参见创建ACK托管集群创建集群创建ACK专有集群

  • 已安装ack-kruise组件,且版本为v1.3.0及以上。更多信息,请参见ack-kruise

  • 已安装虚拟节点组件(ACK Virtual Node),且版本为v2.10.0及以上。更多信息,请参见ACK Virtual Node

  • 已启用SidecarSetServerlessPod=true特性门控。具体操作,请参见自定义控制面组件参数,在Kube API Server组件featureGates中设置SidecarSetServerlessPod=true

功能介绍

SidecarSet

您可以使用与默认SidecarSet完全一致的方式来匹配所有调度到虚拟节点的Pod,即通过标签serverless.alibabacloud.com/virtual-node: "true"指定。该标签会在Pod确定调度到虚拟节点后打上。关于默认SidecarSet的使用方法,请参见SidecarSet

另一个常用的功能是跨命名空间引用ConfigMap和Secret。DaemonSet核心容器运行经常依赖ConfigMap,如配置参数。将DaemonSet核心容器注入到业务Pod中,业务Pod与ConfigMap通常在不同的命名空间,在Sidecar容器Volume中通过namespace/name方式引用其他命名空间的ConfigMap。

展开查看代码详情

apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
  name: filebeat-sidecarset
spec:
  selector:
    matchLabels:      
      serverless.alibabacloud.com/virtual-node: "true" # 表示匹配所有调度到虚拟节点的Pod。
  updateStrategy:
    type: NotUpdate
  containers:
  - name: filebeat
    image: busybox
    imagePullPolicy: IfNotPresent    
    args: [
      "/bin/sh",
      "-c",
      "cat /etc/filebeat.yml && sleep 36000", # 此示例仅打印filebeat配置内容。
    ]    
    volumeMounts:
    - name: config
      mountPath: /etc/filebeat.yml
      readOnly: true
      subPath: filebeat.yml    
  volumes:
  - name: config
    configMap:
      name: kube-system/filebeat-config # 使用namespace/name方式指定引用其他namespace下ConfigMap。

跨命名空间访问ConfigMap和Secret需要授权。具体方式,请参见下方SidecarSetResourceBinding

SidecarSetResourceBinding

出于安全考虑,在Sidecar容器Volume中引入其他命名空间的ConfigMap和Secret需要通过SidecarSetResourceBinding显式授权。

说明

该授权仅授予对ConfigMap和Secret的只读权限(Get,List,Watch)。

展开查看代码详情

# 授权filebeat-sidecarset,SidecarSet匹配的Pod能够访问kube-system命名空间下filebeat-config ConfigMap。
apiVersion: sidecarset.alibabacloud.com/v1alpha1
kind: SidecarSetResourceBinding
metadata:
  name: filebeat-sidecarset-resourcebinding
  namespace: kube-system # 此SidecarSetResourceBinding只能对kube-system命名空间下的资源做授权。
  labels:
spec:
  subjects:
    - kind: SidecarSet
      name: filebeat-sidecarset
  resourceRefs:
    - kind: ConfigMap # 仅授权只读权限(Get, List, Watch)。
      name: filebeat-config

容器启动和退出顺序

Sidecar容器经常需要在业务容器前启动,在业务容器后退出,您可以通过设置容器启动和退出顺序实现。

自动结束Sidecar容器

对于Job类Pod,Sidecar容器可能会导致业务容器完成后Job无法退出的情况,您可以通过强制终止Sidecar容器并忽略容器退出码来解决问题。

升级Sidecar容器

使用Sidecar模式后,您可能会有Sidecar容器升级等运维需求。您可以使用OpenKruise已有的Sidecar热升级功能,该方式能在不影响Pod可用性情况下无缝升级Sidecar容器,且与当前虚拟节点方式完全兼容。

日志收集

通过将虚拟节点Pod标准输出日志卷挂载到Sidecar容器指定目录,可以收集业务容器的日志。具体信息,请参见挂载stdlog实现挂载容器标准输出日志

展开查看代码详情

apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
  name: filebeat-sidecarset
spec:
  selector:
    matchLabels:
      serverless.alibabacloud.com/virtual-node: "true" # 表示匹配所有调度到虚拟节点的Pod。
  updateStrategy:
    type: NotUpdate
  containers:
  # 此示例仅打印Sidecar容器日志内容。
  - name: filebeat
    image: busybox
    imagePullPolicy: IfNotPresent
    args: [
      "/bin/sh",
      "-c",
      "cat /var/log/std/filebeat/0.log && sleep 36000",
    ]    
    volumeMounts:    
    - name: stdlog # 挂载Pod标准输出日志卷/var/log/std目录以便sidecar容器读取。
      mountPath: /var/log/std
      readOnly: true
  volumes:  
  - name: stdlog
    flexVolume:
      driver: alicloud/pod-stdlog # Pod标准输出日志卷。

操作示例

下文将以filebeat容器作为Sidecar容器注入到echo-server业务Pod为例,展示完整的使用流程。

  1. 部署filebeat容器配置文件。

    配置文件是kube-system命名空间的ConfigMap,将被挂载到filebeat容器里。本示例仅将该配置文件挂载到Sidecar容器并打印,相关变量不生效,无需替换。

    展开查看代码详情

    kubectl apply -f - << EOF
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: filebeat-config
      namespace: kube-system
      labels:
        k8s-app: filebeat
    data:
      filebeat.yml: |-
        filebeat.inputs:
        - type: log
          paths:
            - /var/log/std/*.log
          processors:
            - add_kubernetes_metadata:
                host: ${NODE_NAME} # 不生效,无需修改,请直接使用。
                matchers:
                - logs_path:
                    logs_path: "/var/log/std/"
    
        # To enable hints based autodiscover, remove `filebeat.inputs` configuration and uncomment this:
        #filebeat.autodiscover:
        #  providers:
        #    - type: kubernetes
        #      node: ${NODE_NAME}
        #      hints.enabled: true
        #      hints.default_config:
        #        type: container
        #        paths:
        #          - /var/log/containers/*${data.kubernetes.container.id}.log
    
        processors:
          - add_cloud_metadata:
          - add_host_metadata:
    
        cloud.id: ${ELASTIC_CLOUD_ID}  # 不生效,无需修改,请直接使用。
        cloud.auth: ${ELASTIC_CLOUD_AUTH}  # 不生效,无需修改,请直接使用。
    
        output.elasticsearch:
          hosts: ['${ELASTICSEARCH_HOST:elasticsearch}:${ELASTICSEARCH_PORT:9200}']
          username: ${ELASTICSEARCH_USERNAME}  # 不生效,无需修改,请直接使用。
          password: ${ELASTICSEARCH_PASSWORD}  # 不生效,无需修改,请直接使用。
    EOF
  2. 部署filebeat容器的SidecarSet描述。

    本示例filebeat容器仅打印配置内容。同时,filebeat容器还挂载了业务Pod的标准输出卷,可以收集业务Pod的标准输出日志。

    展开查看代码详情

    kubectl apply -f - << EOF
    apiVersion: apps.kruise.io/v1alpha1
    kind: SidecarSet
    metadata:
      name: filebeat-sidecarset
    spec:
      selector:
        matchLabels:
          serverless.alibabacloud.com/virtual-node: "true" # 表示匹配所有调度到虚拟节点的Pod。
      updateStrategy:
        type: NotUpdate
      containers:
      # 此示例未真正运行filebeat,替换为bosybox cat。
      #- name: filebeat
      #  image: docker.elastic.co/beats/filebeat:8.6.1
      #  args: [
      #    "-c", "/etc/filebeat.yml",
      #    "-e",
      #  ]
      - name: filebeat
        image: busybox
        imagePullPolicy: IfNotPresent
        args: [
          "/bin/sh",
          "-c",
          "cat /etc/filebeat.yml && sleep 36000",
        ]
        env:
        - name: ECI_SIDECAR_CONTAINER # 表示Sidecar容器在业务容器后退出。
          value: "true"
        volumeMounts:
        - name: config
          mountPath: /etc/filebeat.yml
          readOnly: true
          subPath: filebeat.yml
        - name: stdlog # 挂载Pod标准输出日志卷/var/log/std目录以便sidecar容器读取。
          mountPath: /var/log/std
          readOnly: true
      volumes:
      - name: config
        configMap:
          name: kube-system/filebeat-config # 使用namespace/name方式指定引用其他namespace下ConfigMap。
      - name: stdlog
        flexVolume:
          driver: alicloud/pod-stdlog # Pod标准输出日志卷。
    EOF
  3. 授权filebeat容器能够访问kube-system命名空间下的配置文件。

    因为echo-server业务Pod位于default命名空间下,filebeat容器被注入后跨namespace访问配置文件需要显式授权。

    展开查看代码详情

    kubectl apply -f - << EOF
    # 授权filebeat-sidecarset,SidecarSet匹配的Pod能够访问kube-system命名空间下filebeat-config ConfigMap。
    apiVersion: sidecarset.alibabacloud.com/v1alpha1
    kind: SidecarSetResourceBinding
    metadata:
      name: filebeat-sidecarset-resourcebinding
      namespace: kube-system # 此SidecarSetResourceBinding只能对kube-system命名空间下的资源做授权。
      labels:
    spec:
      subjects:
        - kind: SidecarSet
          name: filebeat-sidecarset
      resourceRefs:
        - kind: ConfigMap
          name: filebeat-config
    EOF
  4. 部署echo-server业务Pod。

    展开查看代码详情

    kubectl apply -f - << EOF
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: echo-server
      labels:
        app: echo-server
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: echo-server
      template:
        metadata:
          labels:
            app: echo-server        
            alibabacloud.com/eci: "true"
        spec:
          containers:
            - name: echo-server
              image: hashicorp/http-echo
              imagePullPolicy: IfNotPresent
              args:
                - -listen=:8080
                - -text="hello world"
    EOF
  5. 查看业务Pod。

    kubectl get pod
    NAME                           READY   STATUS    RESTARTS   AGE
    echo-server-54f5cf556c-8ms5z   2/2     Running   0          41s

    输出表明,Pod包含2个容器,说明注入成功。

  6. 验证filebeat容器已挂载业务Pod标准输出日志。

    kubectl exec echo-server-54f5cf556c-8ms5z -c filebeat -- cat /var/log/std/echo-server/0.log
    2023-07-07T00:40:07.927378153+08:00 stderr F 2023/07/06 16:40:07 Server is listening on :8080

    输出表明,可以看到业务Pod标准输出日志。

  7. 验证filebeat容器已挂载跨命名空间的配置文件filebeat-config。

    展开查看代码详情

    kubectl exec echo-server-54f5cf556c-8ms5z -c filebeat -- cat /etc/filebeat.yml
    filebeat.inputs:
    - type: log  
      paths:
        - /var/log/std/*.log
    
    # To enable hints based autodiscover, remove `filebeat.inputs` configuration and uncomment this:
    #filebeat.autodiscover:
    #  providers:
    #    - type: kubernetes
    #      node: ${NODE_NAME}
    #      hints.enabled: true
    #      hints.default_config:
    #        type: container
    #        paths:
    #          - /var/log/containers/*${data.kubernetes.container.id}.log
    
    processors:
      - add_cloud_metadata:
      - add_host_metadata:
    
    cloud.id: ${ELASTIC_CLOUD_ID}
    cloud.auth: ${ELASTIC_CLOUD_AUTH}
    
    output.elasticsearch:
      hosts: ['${ELASTICSEARCH_HOST:elasticsearch}:${ELASTICSEARCH_PORT:9200}']
      username: ${ELASTICSEARCH_USERNAME}
      password: ${ELASTICSEARCH_PASSWORD}

    输出表明,挂载正常。