Virtual nodes do not support DaemonSets, so you cannot run per-node agents such as log collectors or monitoring probes the traditional way. Use the OpenKruise SidecarSet feature to automatically inject sidecar containers into pods scheduled to virtual nodes. SidecarSet manages injected containers independently from your application pod spec, so you can update a log agent across all virtual-node pods without modifying application deployments.
Key concepts
SidecarSet is a core feature of OpenKruise, Alibaba Cloud's open source cloud-native application automation engine. A SidecarSet defines which sidecar containers to inject and which pods to target. It manages the full lifecycle of injected containers independently from the application container.
SidecarSetResourceBinding is an ACK custom resource that grants a SidecarSet read-only access (Get, List, Watch) to ConfigMaps or Secrets in other namespaces. Cross-namespace access requires explicit authorization through this resource.
Virtual nodes support both Elastic Container Instance (ECI) and ACS computing power. ACS supports both CPU and GPU workloads.
Virtual nodes do not support DaemonSets. Use sidecar containers injected via SidecarSet as the equivalent.
Prerequisites
Before you begin, ensure that you have:
An ACK managed cluster Pro or ACK dedicated cluster running Kubernetes 1.22 or later
The ack-virtual-node component at version v2.10.0 or later. See ACK Virtual Node
The ack-kruise component at version v1.3.0 or later. See OpenKruise
ImportantAll SidecarSet features from OpenKruise v1.3.0 and earlier are fully supported in virtual node scenarios. New SidecarSet features introduced after v1.3.0 are not supported.
The
SidecarSetServerlessPod=truefeature gate enabled in the Kube API Server'sfeatureGatesparameter. See Customize control plane component parameters
How injection works
The SidecarSet controller determines whether to inject into a pod based on the pod's labels:
If the pod has the label
serverless.alibabacloud.com/virtual-node: "true", the SidecarSet matches and injects the defined sidecar containers.If the pod does not have this label, injection does not apply.
ACK adds the label automatically after confirming a pod is scheduled to a virtual node.
To exclude a specific pod from injection, remove this label from the pod spec or use a more targeted selector in your SidecarSet.
Capabilities
Match virtual node pods
Use the label serverless.alibabacloud.com/virtual-node: "true" as the SidecarSet selector to match all pods on virtual nodes:
apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
name: filebeat-sidecarset
spec:
selector:
matchLabels:
serverless.alibabacloud.com/virtual-node: "true" # Matches all pods scheduled to virtual nodes.For full SidecarSet selector options, see SidecarSet.
Reference ConfigMaps and Secrets across namespaces
Because virtual nodes do not support DaemonSets, sidecar containers replace DaemonSet core containers. These containers often need access to ConfigMaps — such as agent configuration files — that live in a different namespace from the application pod.
Reference a ConfigMap or Secret from another namespace using the Namespace/Name format in the volume definition:
volumes:
- name: config
configMap:
name: kube-system/filebeat-config # Use the Namespace/Name format to reference a ConfigMap in another namespace.Cross-namespace access requires a SidecarSetResourceBinding authorization. See Authorize cross-namespace access below.
Authorize cross-namespace access
Create a SidecarSetResourceBinding to grant the SidecarSet read-only access to ConfigMaps or Secrets in another namespace. Create the resource in the namespace that owns the ConfigMap or Secret:
# Authorizes filebeat-sidecarset. Pods matching the SidecarSet can access the filebeat-config ConfigMap in the kube-system namespace.
apiVersion: sidecarset.alibabacloud.com/v1alpha1
kind: SidecarSetResourceBinding
metadata:
name: filebeat-sidecarset-resourcebinding
namespace: kube-system # This SidecarSetResourceBinding only authorizes resources in the kube-system namespace.
labels:
spec:
subjects:
- kind: SidecarSet
name: filebeat-sidecarset
resourceRefs:
- kind: ConfigMap # Only grants read-only permission (Get, List, Watch).
name: filebeat-configControl container startup and shutdown order
Sidecar containers often need to start before application containers and exit after them. Configure startup and shutdown ordering for:
Terminate sidecar containers for Job pods
For Job-type pods, a sidecar container that keeps running after the application container exits blocks the Job from completing. Set the ECI_SIDECAR_CONTAINER environment variable to "true" to make the sidecar container exit automatically when the application container finishes:
containers:
- name: filebeat
image: busybox
env:
- name: ECI_SIDECAR_CONTAINER # Causes the sidecar container to exit after the application container exits.
value: "true"For complete configuration details, see Forcibly terminate the sidecar container and ignore the container exit code.
Upgrade sidecar containers without downtime
OpenKruise supports hot upgrades for sidecar containers, enabling seamless upgrades without affecting pod availability. This mechanism is fully compatible with virtual nodes. See Sidecar hot upgrade in the OpenKruise documentation for configuration details.
Collect standard output logs
Mount the pod's standard output logs as a stdlog volume into the sidecar container to collect logs from the application container:
apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
name: filebeat-sidecarset
spec:
selector:
matchLabels:
serverless.alibabacloud.com/virtual-node: "true" # Matches all pods scheduled to virtual nodes.
updateStrategy:
type: NotUpdate
containers:
- name: filebeat
image: busybox
imagePullPolicy: IfNotPresent
args: [
"/bin/sh",
"-c",
"cat /var/log/std/filebeat/0.log && sleep 36000",
]
volumeMounts:
- name: stdlog # Mounts the pod's standard output log volume for the sidecar container to read.
mountPath: /var/log/std
readOnly: true
volumes:
- name: stdlog
csi:
driver: stdlogplugin.csi.alibabacloud.comLogs are available at /var/log/std/<container-name>/0.log inside the sidecar container. For more information, see Mount container logs by using stdlog.
End-to-end example
This example injects a filebeat sidecar container into an echo-server application pod on a virtual node. The sidecar mounts a cross-namespace ConfigMap and collects the application pod's standard output logs.
Step 1: Deploy the ConfigMap
Create filebeat-config.yaml with the following content, then apply it. This example mounts the configuration file into the sidecar container for demonstration — the variables in this file are placeholders and are not active.
kubectl apply -f filebeat-config.yamlapiVersion: 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} # Not effective. Do not modify. Use directly.
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} # Not effective. Do not modify. Use directly.
cloud.auth: ${ELASTIC_CLOUD_AUTH} # Not effective. Do not modify. Use directly.
output.elasticsearch:
hosts: ['${ELASTICSEARCH_HOST:elasticsearch}:${ELASTICSEARCH_PORT:9200}']
username: ${ELASTICSEARCH_USERNAME} # Not effective. Do not modify. Use directly.
password: ${ELASTICSEARCH_PASSWORD} # Not effective. Do not modify. Use directly.Step 2: Deploy the SidecarSet
Create sidecarset.yaml with the following content, then apply it. The filebeat container uses busybox for demonstration instead of an actual filebeat binary, and prints the mounted configuration file.
kubectl apply -f sidecarset.yamlapiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
name: filebeat-sidecarset
spec:
selector:
matchLabels:
serverless.alibabacloud.com/virtual-node: "true" # Matches all pods scheduled to virtual nodes.
updateStrategy:
type: NotUpdate
containers:
# This example does not actually run filebeat; it uses busybox cat instead.
#- 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 # Causes the sidecar container to exit after the application container exits.
value: "true"
volumeMounts:
- name: config
mountPath: /etc/filebeat.yml
readOnly: true
subPath: filebeat.yml
- name: stdlog # Mounts the pod's standard output logs for the sidecar container to read.
mountPath: /var/log/std
readOnly: true
volumes:
- name: config
configMap:
name: kube-system/filebeat-config # Uses the Namespace/Name format to reference a ConfigMap in another namespace.
- name: stdlog
csi:
driver: stdlogplugin.csi.alibabacloud.comStep 3: Authorize cross-namespace ConfigMap access
The application pod runs in the default namespace while the ConfigMap is in kube-system. Create a SidecarSetResourceBinding to authorize access.
Create sidecarset-resourcebinding.yaml with the following content, then apply it:
kubectl apply -f sidecarset-resourcebinding.yaml# Authorizes filebeat-sidecarset. Pods matching the SidecarSet can access the filebeat-config ConfigMap in the kube-system namespace.
apiVersion: sidecarset.alibabacloud.com/v1alpha1
kind: SidecarSetResourceBinding
metadata:
name: filebeat-sidecarset-resourcebinding
namespace: kube-system # This SidecarSetResourceBinding only authorizes resources in the kube-system namespace.
labels:
spec:
subjects:
- kind: SidecarSet
name: filebeat-sidecarset
resourceRefs:
- kind: ConfigMap
name: filebeat-configStep 4: Deploy the application pod
Create echo-server.yaml with the following content, then apply it. The alibabacloud.com/eci: "true" label schedules the pod to a virtual node.
kubectl apply -f echo-server.yamlapiVersion: 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"Step 5: Verify the injection
Check that the pod has two containers, confirming the sidecar was injected:
kubectl get podExpected output:
NAME READY STATUS RESTARTS AGE echo-server-f8bdc5844-r44nj 2/2 Running 0 14mVerify the sidecar can read the application pod's standard output logs:
kubectl exec echo-server-f8bdc5844-r44nj -c filebeat -- cat /var/log/std/echo-server/0.logExpected output:
2025-04-29T11:26:06.783205694+08:00 stderr F 2025/04/29 03:26:06 Server is listening on :8080Verify the sidecar can read the cross-namespace ConfigMap:
kubectl exec echo-server-f8bdc5844-r44nj -c filebeat -- cat /etc/filebeat.yml
What's next
ACK Virtual Node — Manage virtual node components and settings
OpenKruise SidecarSet — Full SidecarSet feature reference
Mount an stdlog volume to collect standard output logs from a container — Log collection from virtual node pods
Customize control plane component parameters — Enable feature gates on the Kube API Server