New to KubeDB? Please start here.
Autoscaling the Compute Resources of an Etcd Cluster
This guide shows you how to use KubeDB to autoscale the compute resources (cpu and memory) of
an etcd cluster.
Before You Begin
At first, you need a Kubernetes cluster, and the
kubectlcommand-line tool must be configured to communicate with your cluster.Install the
KubeDBProvisioner, Ops-manager and Autoscaler operators in your cluster following the steps here.etcd support is behind an alpha feature gate. Make sure the operators are installed with
Etcd=trueenabled (Helm valuefeatureGates.Etcd=true), otherwise theEtcdandEtcdAutoscalerCRDs are not reconciled.Install
Metrics Serverfrom here.You should be familiar with the following
KubeDBconcepts:
To keep everything isolated, we are going to use a separate namespace called demo throughout
this tutorial.
$ kubectl create ns demo
namespace/demo created
Note: YAML files used in this tutorial are stored in docs/examples/etcd folder in GitHub repository kubedb/docs.
Deploy Etcd
In this section, we deploy a three member etcd cluster with version 3.6.4. In the next section
we set up autoscaling for it using the EtcdAutoscaler CRD. Below is the YAML of the Etcd CR
that we are going to create.
apiVersion: kubedb.com/v1alpha2
kind: Etcd
metadata:
name: etcd-autoscale
namespace: demo
spec:
version: "3.6.4"
replicas: 3
storageType: Durable
storage:
storageClassName: "standard"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
podTemplate:
spec:
containers:
- name: etcd
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "1"
memory: "2Gi"
deletionPolicy: WipeOut
Let’s create the Etcd CR we have shown above,
$ kubectl create -f https://github.com/kubedb/docs/raw/v2026.7.10/docs/examples/etcd/autoscaling/compute/etcd.yaml
etcd.kubedb.com/etcd-autoscale created
Now, wait until etcd-autoscale has the status Ready.
$ kubectl get etcd -n demo
NAME VERSION STATUS AGE
etcd-autoscale 3.6.4 Ready 2m
Let’s check the resources of the etcd container in one of the member pods,
$ kubectl get pod -n demo etcd-autoscale-0 -o json | jq '.spec.containers[] | select(.name=="etcd") | .resources'
{
"limits": {
"cpu": "1",
"memory": "2Gi"
},
"requests": {
"cpu": "500m",
"memory": "1Gi"
}
}
And the resources recorded on the Etcd object itself,
$ kubectl get etcd -n demo etcd-autoscale -o json | jq '.spec.podTemplate.spec.containers[0].resources'
{
"limits": {
"cpu": "1",
"memory": "2Gi"
},
"requests": {
"cpu": "500m",
"memory": "1Gi"
}
}
You can see from the outputs above that the resources are the ones we assigned while deploying
the etcd cluster. We are now ready to apply the EtcdAutoscaler CRO.
Compute Resource Autoscaling
Create EtcdAutoscaler Object
To set up compute resource autoscaling for this etcd cluster, we create an EtcdAutoscaler CRO
with the desired configuration. Below is the YAML of the EtcdAutoscaler object that we are
going to create,
apiVersion: autoscaling.kubedb.com/v1alpha1
kind: EtcdAutoscaler
metadata:
name: etcd-compute-autoscaler
namespace: demo
spec:
databaseRef:
name: etcd-autoscale
opsRequestOptions:
apply: IfReady
timeout: 5m
compute:
etcd:
trigger: "On"
podLifeTimeThreshold: 5m
resourceDiffPercentage: 20
minAllowed:
cpu: 600m
memory: 1.2Gi
maxAllowed:
cpu: 2
memory: 4Gi
controlledResources: ["cpu", "memory"]
containerControlledValues: "RequestsAndLimits"
Here,
spec.databaseRef.namespecifies that we are performing compute resource autoscaling on theetcd-autoscaledatabase.spec.compute.etcd.triggerspecifies that compute resource autoscaling is enabled for theetcdcontainer. The default isOff.spec.compute.etcd.podLifeTimeThresholdspecifies the minimum lifetime for at least one of the pods before a vertical scaling is initiated. The default is15m.spec.compute.etcd.resourceDiffPercentagespecifies the minimum resource difference, in percent, that is worth acting on. The default is50. If the difference between the current and the recommended resources is smaller than this, the Autoscaler operator ignores the update.spec.compute.etcd.minAllowedspecifies the minimum resources the recommender may recommend. The default is no minimum.spec.compute.etcd.maxAllowedspecifies the maximum resources the recommender may recommend. The default is no maximum. Setting this is strongly recommended so that a transient spike cannot recommend an unschedulable pod.spec.compute.etcd.controlledResourcesspecifies which resources are controlled by the autoscaler. The default is["cpu", "memory"].spec.compute.etcd.containerControlledValuesspecifies which resource values are controlled,RequestsAndLimitsorRequestsOnly. The default isRequestsAndLimits.spec.opsRequestOptionsholds the options that are copied onto theEtcdOpsRequestthe autoscaler creates. See spec.timeout and spec.apply.
Note:
spec.computealso has anetcd-sibling field,nodeTopology, which snaps the recommendation to the node groups of aNodeTopologyobject. Keep in mind that the resultingEtcdOpsRequestcarries no placement fields in its spec — see the caveat in the overview.
Let’s create the EtcdAutoscaler CR we have shown above,
$ kubectl apply -f https://github.com/kubedb/docs/raw/v2026.7.10/docs/examples/etcd/autoscaling/compute/etcd-compute-autoscaler.yaml
etcdautoscaler.autoscaling.kubedb.com/etcd-compute-autoscaler created
Verify autoscaling is set up successfully
Let’s check that the etcdautoscaler resource was created successfully,
$ kubectl get etcdautoscaler -n demo
NAME AGE
etcd-compute-autoscaler 3m
$ kubectl describe etcdautoscaler etcd-compute-autoscaler -n demo
Name: etcd-compute-autoscaler
Namespace: demo
Labels: <none>
Annotations: <none>
API Version: autoscaling.kubedb.com/v1alpha1
Kind: EtcdAutoscaler
Metadata:
Creation Timestamp: 2026-02-11T09:12:44Z
Generation: 1
Resource Version: 41822
UID: 1b0f2d6c-8c30-4b0b-9d4a-2d2c9d51f0a1
Spec:
Compute:
Etcd:
Container Controlled Values: RequestsAndLimits
Controlled Resources:
cpu
memory
Max Allowed:
Cpu: 2
Memory: 4Gi
Min Allowed:
Cpu: 600m
Memory: 1.2Gi
Pod Life Time Threshold: 5m0s
Resource Diff Percentage: 20
Trigger: On
Database Ref:
Name: etcd-autoscale
Ops Request Options:
Apply: IfReady
Timeout: 5m0s
Status:
Checkpoints:
Cpu Histogram:
Bucket Weights:
Index: 0
Weight: 10000
Reference Timestamp: 2026-02-11T09:15:00Z
Total Weight: 0.8733542386168607
First Sample Start: 2026-02-11T09:12:41Z
Last Sample Start: 2026-02-11T09:18:06Z
Last Update Time: 2026-02-11T09:18:38Z
Memory Histogram:
Bucket Weights:
Index: 11
Weight: 10000
Reference Timestamp: 2026-02-11T09:18:00Z
Total Weight: 0.7827734162991002
Ref:
Container Name: etcd
Vpa Object Name: etcd-autoscale
Total Samples Count: 6
Version: v3
Conditions:
Last Transition Time: 2026-02-11T09:19:07Z
Message: Successfully created EtcdOpsRequest demo/etcdops-etcd-autoscale-vft8xm
Observed Generation: 1
Reason: CreateOpsRequest
Status: True
Type: CreateOpsRequest
Vpas:
Conditions:
Last Transition Time: 2026-02-11T09:13:12Z
Status: True
Type: RecommendationProvided
Recommendation:
Container Recommendations:
Container Name: etcd
Lower Bound:
Cpu: 600m
Memory: 1.2Gi
Target:
Cpu: 600m
Memory: 1.2Gi
Uncapped Target:
Cpu: 540m
Memory: 1073741824
Upper Bound:
Cpu: 2
Memory: 4Gi
Vpa Name: etcd-autoscale
Events: <none>
So the EtcdAutoscaler resource was created successfully.
In the Status.Vpas.Recommendation section you can see the recommendation the operator generated
for the etcd container. The Autoscaler operator continuously watches that recommendation and,
when it differs from the running resources by more than resourceDiffPercentage, creates an
EtcdOpsRequest to move the cluster onto it.
Watch the generated EtcdOpsRequest
Let’s watch the etcdopsrequest objects in the demo namespace. After a while you should see an
autoscaler-created one appear. Note the etcdops- name prefix — that is how the Autoscaler
operator names the requests it generates.
$ watch kubectl get etcdopsrequest -n demo
Every 2.0s: kubectl get etcdopsrequest -n demo
NAME TYPE STATUS AGE
etcdops-etcd-autoscale-vft8xm VerticalScaling Progressing 45s
Let’s wait for the ops request to become successful.
$ watch kubectl get etcdopsrequest -n demo
Every 2.0s: kubectl get etcdopsrequest -n demo
NAME TYPE STATUS AGE
etcdops-etcd-autoscale-vft8xm VerticalScaling Successful 3m
If we describe the EtcdOpsRequest, we get an overview of the steps that were followed to scale
the cluster. Note the owner reference back to the EtcdAutoscaler — that is what tells you this
request was generated rather than hand-written.
$ kubectl describe etcdopsrequest -n demo etcdops-etcd-autoscale-vft8xm
Name: etcdops-etcd-autoscale-vft8xm
Namespace: demo
Labels: app.kubernetes.io/component=database
app.kubernetes.io/instance=etcd-autoscale
app.kubernetes.io/managed-by=kubedb.com
app.kubernetes.io/name=etcds.kubedb.com
Annotations: <none>
API Version: ops.kubedb.com/v1alpha1
Kind: EtcdOpsRequest
Metadata:
Creation Timestamp: 2026-02-11T09:19:07Z
Generation: 1
Owner References:
API Version: autoscaling.kubedb.com/v1alpha1
Block Owner Deletion: true
Controller: true
Kind: EtcdAutoscaler
Name: etcd-compute-autoscaler
UID: 1b0f2d6c-8c30-4b0b-9d4a-2d2c9d51f0a1
Resource Version: 41903
UID: 6d2c1a55-0f61-4a3e-9c1b-2b9b0f6e0d77
Spec:
Apply: IfReady
Database Ref:
Name: etcd-autoscale
Timeout: 5m0s
Type: VerticalScaling
Vertical Scaling:
Etcd:
Resources:
Limits:
Cpu: 2
Memory: 4Gi
Requests:
Cpu: 600m
Memory: 1.2Gi
Mode: Restart
Status:
Conditions:
Last Transition Time: 2026-02-11T09:19:07Z
Message: Vertical Scaling is in progress
Observed Generation: 1
Reason: Running
Status: True
Type: Running
Last Transition Time: 2026-02-11T09:19:15Z
Message: Successfully updated the petset resources
Observed Generation: 1
Reason: UpdateEtcdPetSet
Status: True
Type: UpdateEtcdPetSet
Last Transition Time: 2026-02-11T09:19:16Z
Message: Successfully updated the Etcd resources
Observed Generation: 1
Reason: UpdateDatabase
Status: True
Type: UpdateDatabase
Last Transition Time: 2026-02-11T09:21:41Z
Message: Successfully restarted the etcd members with the new resources
Observed Generation: 1
Reason: VerticalScale
Status: True
Type: VerticalScale
Last Transition Time: 2026-02-11T09:21:42Z
Message: Successfully vertically scaled the etcd cluster
Observed Generation: 1
Reason: Successful
Status: True
Type: Successful
Observed Generation: 1
Phase: Successful
Events: <none>
The generated request uses the default vertical scaling mode, Restart. The Ops-manager operator
patches the PetSet template and then rolls the member pods one at a time, moving the Raft
leadership off the leader before restarting it and waiting for quorum in between, so the cluster
keeps serving clients throughout. The mode is not configurable from the EtcdAutoscaler; if you
want the resize applied without recreating pods, create an EtcdOpsRequest with
spec.verticalScaling.mode: InPlace by hand instead — see
Vertical Scaling.
Verify the new resources
Now let’s verify from the Pod and from the Etcd object that the resources were updated.
$ kubectl get pod -n demo etcd-autoscale-0 -o json | jq '.spec.containers[] | select(.name=="etcd") | .resources'
{
"limits": {
"cpu": "2",
"memory": "4Gi"
},
"requests": {
"cpu": "600m",
"memory": "1.2Gi"
}
}
$ kubectl get etcd -n demo etcd-autoscale -o json | jq '.spec.podTemplate.spec.containers[0].resources'
{
"limits": {
"cpu": "2",
"memory": "4Gi"
},
"requests": {
"cpu": "600m",
"memory": "1.2Gi"
}
}
The output above confirms that the compute resources of the etcd cluster were autoscaled.
Cleaning Up
To clean up the Kubernetes resources created by this tutorial, run:
kubectl delete etcdautoscaler -n demo etcd-compute-autoscaler
kubectl delete etcd -n demo etcd-autoscale
kubectl delete ns demo
Next Steps
- Storage Autoscaling of an Etcd cluster.
- Detail concepts of the Etcd object.
- Want to hack on KubeDB? Check our contribution guidelines.
































