In mixed clusters where real nodes and virtual nodes coexist, scheduling pods to Elastic Container Instance (ECI) and enabling ECI-specific features typically requires modifying pod YAML files—blurring the line between platform operations and application configuration. The eci-profile removes this burden. As a cluster administrator, you define scheduling rules and annotation injection in a single cluster-level ConfigMap, and pods receive the right configuration automatically—without any changes to application YAML.
How it works
When a pod is created, ack-virtual-node reads the ConfigMap named eci-profile in the kube-system namespace and applies the configuration in its data section to the pod.
The eci-profile provides three capabilities:
ECI Scheduler — Routes pods to ECI based on pod labels or namespace labels, using a mutating webhook mechanism. This removes the need to add scheduling directives to individual pod YAML files.
ECI Effect — Automatically injects annotations and labels into matched pods, enabling advanced ECI features such as specifying Elastic Compute Service (ECS) instance types, enabling image caches, and configuring the Network Time Protocol (NTP) service. For a full list of supported annotations, see ECI Pod Annotation.
Hot updates — Configuration changes to the eci-profile (cluster IP address, hybrid cloud, log collection, vSwitches) take effect immediately for newly created pods. No restart of ack-virtual-node is required. Existing pods pick up the changes only after a rolling update.
Prerequisites
Before you begin, make sure that:
The ack-virtual-node component in your cluster is at the latest version. To update it, see Manage components.
Mutating webhooks are enabled in your cluster (required for ECI Scheduler). Pods in ACK Serverless clusters are scheduled to ECI automatically—ECI Scheduler is not needed there.
Usage notes
After you update the eci-profile, newly created ECI pods use the updated configuration immediately. Existing pods use the updated configuration only after a rolling update.
If you configure neither
namespaceSelectornorobjectSelectorfor a selector but do configureeffect, the effect settings apply to all pods scheduled to ECI.If multiple selectors match a pod, they are evaluated in order. Annotations and labels from earlier-matched selectors take priority over those from later-matched selectors. Existing pod annotations and labels always take priority over anything injected by
effect.
View the eci-profile
Run the following command to view the current eci-profile ConfigMap:
kubectl get cm -n kube-system eci-profile -o yamlThe data section of the ConfigMap contains two types of configuration:
| Parameter | Description |
|---|---|
selectors | Defines ECI Scheduler and ECI Effect rules. See Configure selectors. |
Other parameters (vpcId, vSwitchIds, etc.) | Cluster-level parameters that apply when no pod-level override is present. Support hot updates. See Update cluster-level parameters. |
A default eci-profile looks like this:
apiVersion: v1
data:
enableClusterIp: "true"
enableHybridMode: "false"
enableLinuxArm64Node: "false"
enableLogController: "false"
enablePVCController: "false"
enablePrivateZone: "false"
enableReuseSSLKey: "false"
featureGates: "WaitForFirstConsumer=false"
securityGroupId: sg-2zeeyaaxlkq9sppl****
selectors: ""
slsMachineGroup: ""
vSwitchIds: vsw-2ze23nqzig8inprou****,vsw-2ze94pjtfuj9vaymf****
vpcId: vpc-2zeghwzptn5zii0w7****
kind: ConfigMap
metadata:
creationTimestamp: "2023-01-11T08:28:14Z"
name: eci-profile
namespace: kube-system
resourceVersion: "356"
uid: b345fa8c-919e-41fc-a981-57864b1a****Edit the eci-profile
Use one of the following methods to edit the eci-profile.
kubectl
kubectl edit configmap eci-profile -n kube-systemACK console
Log on to the Container Service ACK console.
On the Clusters page, click the name of the target cluster.
In the left navigation pane, choose Configurations > ConfigMaps.
Select kube-system from the Namespace drop-down list.
Find eci-profile and click Edit YAML in the Actions column.
Configure selectors
Selectors define which pods are routed to ECI (ECI Scheduler) and which annotations or labels are injected into those pods (ECI Effect). When a pod is created, the system evaluates each selector in sequence and applies any matching rules.
Each selector supports the following fields:
`name` (required) — A unique name for the selector.
`namespaceSelector` (optional) — Matches pods based on namespace labels. Specify labels under
matchLabels. Multiple labels use AND logic.`objectSelector` (optional) — Matches pods based on pod labels. Specify labels under
matchLabels. Multiple labels use AND logic.`effect` (optional) — Annotations and labels to inject into matched pods. Injected values do not overwrite existing pod annotations or labels.
When both namespaceSelector and objectSelector are configured, a pod must satisfy both to match the selector. If neither is configured but effect is configured, the effect applies to all pods scheduled to ECI.
Selector template
data:
selectors: |
[
{
"name": "selector-demo1", # Required. Unique selector name.
"namespaceSelector": { # Optional. Matches by namespace labels.
"matchLabels": { # AND logic among multiple labels.
"eci": "true"
}
},
"objectSelector": { # Optional. Matches by pod labels.
"matchLabels": { # AND logic among multiple labels.
"eci": "true"
}
},
"effect": { # Optional. Annotations and labels to inject.
"annotations": {
"k8s.aliyun.com/eci-use-specs": "ecs.c6.xlarge"
},
"labels": {
"created-by-eci": "true"
}
}
},
{
"name": "selector-demo2",
"objectSelector": {
"matchLabels": {
"eci": "test"
}
}
}
]In the example above, selector-demo1 matches pods that have both the eci: true pod label and belong to a namespace with the eci: true label. Matched pods are scheduled to ECI and receive the k8s.aliyun.com/eci-use-specs: ecs.c6.xlarge annotation and the created-by-eci: true label.
Remove inline comments (#) before applying the configuration. JSON does not support comments.Verify that selectors take effect
After updating the selectors, run the following command to confirm they are registered:
kubectl get mutatingwebhookconfigurations -o yaml vk-webhookIf the output contains your configured selectors, the configuration is active. If not, check that your selector JSON is formatted correctly.
Configuration examples
Example 1: Route specific pods to ECI
The following selector routes a pod to ECI when the pod has the created-by-eci: true label and its namespace has the type: eci label.
data:
selectors: |
[
{
"name": "eci-selector",
"namespaceSelector": {
"matchLabels": {
"type": "eci"
}
},
"objectSelector": {
"matchLabels": {
"created-by-eci": "true"
}
}
}
]Example 2: Route pods to ECI with a GPU-accelerated instance type
The following selector routes pods whose namespace has the gpu: true label to ECI, using the ecs.gn6v-c8g1.2xlarge GPU-accelerated instance type, and adds the gpu: test label to matched pods.
data:
selectors: |
[
{
"name": "gpu-namespace-selector",
"namespaceSelector": {
"matchLabels": {
"gpu": "true"
}
},
"effect": {
"annotations": {
"k8s.aliyun.com/eci-use-specs": "ecs.gn6v-c8g1.2xlarge"
},
"labels": {
"gpu": "test"
}
}
}
]Example 3: Route pods to ECI with automatic image cache matching
The following selector routes pods with the imc: auto label to ECI and enables automatic image cache matching.
data:
selectors: |
[
{
"name": "autoimc-object-selector",
"objectSelector": {
"matchLabels": {
"imc": "auto"
}
},
"effect": {
"annotations": {
"k8s.aliyun.com/eci-auto-imc": "true"
}
}
}
]Update cluster-level parameters
The following parameters in the data section are cluster-level defaults. When a pod is created without a pod-level override, the eci-profile values are used. All parameters support hot updates—changes take effect immediately without restarting ack-virtual-node.
These parameters apply only when no pod-level configuration overrides them.
| Parameter | Default | Description |
|---|---|---|
enableClusterIp | "true" | Whether to support the cluster IP address. |
enableHybridMode | "false" | Whether to enable hybrid cloud mode. |
enableLinuxArm64Node | "false" | Whether to enable ARM-based nodes. See Schedule pods to an ARM-based virtual node. |
enableLogController | "false" | Whether to use the Custom Resource Definition (CRD) for Simple Log Service to collect pod logs. If set to "true", also configure slsMachineGroup. |
enablePVCController | "false" | Whether to enable online disk extension. If set to "true", the system can hot-extend PersistentVolumeClaims (PVCs) bound to disks. |
enablePrivateZone | "false" | Whether to use PrivateZone for domain name resolution. |
enableReuseSSLKey | "false" | Whether to reuse SSL keys across pods. By default, ack-virtual-node issues a unique SSL certificate to each pod. Setting this to "true" makes all pods share the same certificate, which improves pod creation throughput at the cost of reduced security. |
featureGates | "WaitForFirstConsumer=false" | Canary feature gate. Only WaitForFirstConsumer is configurable. See the note below. |
securityGroupId | — | The security group for ECI pods. Example: sg-2zeeyaaxlkq9sppl****. |
slsMachineGroup | — | The machine group for ECI pods. Required when enableLogController is "true". Example: test-mg. |
vSwitchIds | — | The IDs of the vSwitches for ECI pods. Separate multiple IDs with commas. Example: vsw-2ze23nqzig8inprou**,vsw-2ze94pjtfuj9vaymf**. |
vpcId | — | The ID of the Virtual Private Cloud (VPC) where ECI pods are deployed. Example: vpc-2zeghwzptn5zii0w7****. |
About `featureGates: WaitForFirstConsumer`
When WaitForFirstConsumer is set to "true":
The csi-provisioner component must be at the latest version before enabling this setting.
PersistentVolumes (PVs) and backend storage are created only after the pod is scheduled. The zone and region specified in the StorageClass are no longer used; instead, the zone and region of the scheduled pod's node are used to create storage resources. This ensures that computing resources are preferentially scheduled.
For more information, see Volume binding mode.
A complete data section example:
data:
enableClusterIp: "true"
enableHybridMode: "false"
enableLinuxArm64Node: "false"
enableLogController: "false"
enablePVCController: "false"
enablePrivateZone: "false"
enableReuseSSLKey: "false"
securityGroupId: sg-2zeeyaaxlkq9sppl****
selectors: ""
slsMachineGroup: ""
vSwitchIds: vsw-2ze23nqzig8inprou****,vsw-2ze94pjtfuj9vaymf****
vpcId: vpc-2zeghwzptn5zii0w7****