You are looking at the documentation of a prior release. To read the documentation of the latest release, please
visit here.
New to KubeDB? Please start here.
Vertical Scale Etcd
This guide will show you how to use the KubeDB Ops-manager operator to update the compute
resources of an Etcd cluster.
Before You Begin
At first, you need to have a Kubernetes cluster, and the
kubectlcommand-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using kind.Install
KubeDBProvisioner and Ops-manager operator in your cluster following the steps here. Etcd support is an alpha feature, so the operators must be installed with theEtcdfeature gate turned on (--set featureGates.Etcd=true).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/scaling/vertical-scaling directory of the kubedb/docs repository.
Apply Vertical Scaling
Here, we are going to deploy an Etcd cluster using a version supported by the KubeDB operator,
and then apply vertical scaling on it.
Deploy Etcd
Below is the YAML of the Etcd CR that we are going to create,
apiVersion: kubedb.com/v1alpha2
kind: Etcd
metadata:
name: etcd-cluster
namespace: demo
spec:
version: "3.6.4"
replicas: 3
storageType: Durable
storage:
storageClassName: "standard"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
deletionPolicy: WipeOut
Let’s create the Etcd CR we have shown above,
$ kubectl create -f https://github.com/kubedb/docs/raw/v2026.8.26-rc.2/docs/examples/etcd/scaling/vertical-scaling/etcd.yaml
etcd.kubedb.com/etcd-cluster created
Now, wait until etcd-cluster has status Ready. i.e,
$ kubectl get etcd -n demo
NAME VERSION STATUS AGE
etcd-cluster 3.6.4 Ready 4m
Let’s check the resources of the etcd container:
$ kubectl get pod -n demo etcd-cluster-0 -o json | jq '.spec.containers[] | select(.name=="etcd") | .resources'
{
"limits": {
"memory": "2Gi"
},
"requests": {
"cpu": "500m",
"memory": "1Gi"
}
}
These are the default resources assigned by the KubeDB operator (etcd is latency sensitive but its working set is bounded by the backend quota rather than by the dataset size, so the default footprint is deliberately modest).
We are now ready to apply an EtcdOpsRequest to update these resources.
Vertical Scaling
Create EtcdOpsRequest
Below is the YAML of the EtcdOpsRequest CR that we are going to create,
apiVersion: ops.kubedb.com/v1alpha1
kind: EtcdOpsRequest
metadata:
name: etcd-vscale
namespace: demo
spec:
type: VerticalScaling
databaseRef:
name: etcd-cluster
verticalScaling:
mode: Restart
etcd:
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "1"
memory: "2Gi"
timeout: 10m
apply: IfReady
Here,
spec.databaseRef.namespecifies that we are performing the vertical scaling operation on theetcd-clusterdatabase.spec.typespecifies that we are performingVerticalScalingon our database.spec.verticalScaling.etcd.resourcesspecifies the desired resources of theetcdcontainer after scaling.spec.verticalScaling.modespecifies how the scaling is actuated —Restart(the default; the member pods are restarted one at a time, leader last) orInPlace(the running pods are resized through thepods/resizesubresource with no restart at all). See Vertical Scaling Modes.- Have a look here to understand the
timeoutandapplyfields.
spec.verticalScaling.etcdandspec.verticalScaling.exporterare the only two containers the API accepts, and at least one of them must be set — the validating webhook rejects an emptyverticalScaling. In practice you always wantetcd: KubeDB does not run an exporter sidecar for etcd (see the note in the overview).
Let’s create the EtcdOpsRequest CR we have shown above,
$ kubectl apply -f https://github.com/kubedb/docs/raw/v2026.8.26-rc.2/docs/examples/etcd/scaling/vertical-scaling/etcdops-vscale.yaml
etcdopsrequest.ops.kubedb.com/etcd-vscale created
Verify the Etcd resources are updated successfully
Let’s wait for the EtcdOpsRequest to become Successful. Run the following command to watch the
EtcdOpsRequest CR,
$ watch kubectl get etcdopsrequest -n demo
Every 2.0s: kubectl get etcdopsrequest -n demo
NAME TYPE STATUS AGE
etcd-vscale VerticalScaling Successful 3m12s
If we describe the EtcdOpsRequest, we get an overview of the steps that were followed:
$ kubectl describe etcdopsrequest -n demo etcd-vscale
Name: etcd-vscale
Namespace: demo
API Version: ops.kubedb.com/v1alpha1
Kind: EtcdOpsRequest
Metadata:
Creation Timestamp: 2026-08-15T09:41:02Z
Generation: 1
Resource Version: 120451
UID: 3ca1e0c4-7a0f-4f1d-9b3a-6f2a4c1c9f01
Spec:
Apply: IfReady
Database Ref:
Name: etcd-cluster
Timeout: 10m
Type: VerticalScaling
Vertical Scaling:
Etcd:
Resources:
Limits:
Cpu: 1
Memory: 2Gi
Requests:
Cpu: 1
Memory: 2Gi
Mode: Restart
Status:
Conditions:
Last Transition Time: 2026-08-15T09:41:02Z
Message: Vertical Scaling is in progress
Observed Generation: 1
Reason: Running
Status: True
Type: Running
Last Transition Time: 2026-08-15T09:41:12Z
Message: Successfully updated the petset resources
Observed Generation: 1
Reason: UpdateEtcdPetSet
Status: True
Type: UpdateEtcdPetSet
Last Transition Time: 2026-08-15T09:41:12Z
Message: Successfully updated the Etcd resources
Observed Generation: 1
Reason: UpdateDatabase
Status: True
Type: UpdateDatabase
Last Transition Time: 2026-08-15T09:41:47Z
Message: check pod ready; ConditionStatus:True; PodName:etcd-cluster-1
Observed Generation: 1
Status: True
Type: CheckPodReady--etcd-cluster-1
Last Transition Time: 2026-08-15T09:41:52Z
Message: etcd cluster healthy; ConditionStatus:True; PodName:etcd-cluster-1
Observed Generation: 1
Status: True
Type: EtcdClusterHealthy--etcd-cluster-1
Last Transition Time: 2026-08-15T09:42:27Z
Message: check pod ready; ConditionStatus:True; PodName:etcd-cluster-2
Observed Generation: 1
Status: True
Type: CheckPodReady--etcd-cluster-2
Last Transition Time: 2026-08-15T09:42:32Z
Message: etcd cluster healthy; ConditionStatus:True; PodName:etcd-cluster-2
Observed Generation: 1
Status: True
Type: EtcdClusterHealthy--etcd-cluster-2
Last Transition Time: 2026-08-15T09:43:07Z
Message: check pod ready; ConditionStatus:True; PodName:etcd-cluster-0
Observed Generation: 1
Status: True
Type: CheckPodReady--etcd-cluster-0
Last Transition Time: 2026-08-15T09:43:12Z
Message: Successfully restarted the etcd members with the new resources
Observed Generation: 1
Reason: VerticalScale
Status: True
Type: VerticalScale
Last Transition Time: 2026-08-15T09:43:14Z
Message: Successfully vertically scaled the etcd cluster
Observed Generation: 1
Reason: Successful
Status: True
Type: Successful
Observed Generation: 1
Phase: Successful
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal PauseDatabase 3m12s KubeDB Ops-manager Operator Pausing Etcd demo/etcd-cluster
Normal UpdateEtcdPetSet 3m2s KubeDB Ops-manager Operator Successfully updated the petset resources
Normal UpdateDatabase 3m2s KubeDB Ops-manager Operator Successfully updated the Etcd resources
Normal VerticalScale 12s KubeDB Ops-manager Operator Successfully restarted the etcd members with the new resources
Normal ResumeDatabase 10s KubeDB Ops-manager Operator Successfully resumed Etcd demo/etcd-cluster
Normal Successful 10s KubeDB Ops-manager Operator Successfully vertically scaled the etcd cluster
A few things worth pointing out in that condition list:
- The per-pod
CheckPodReady--<pod>/EtcdClusterHealthy--<pod>conditions are written for every member the operation touched, not only for the steps that had to wait — they are both the sequencing gate and the operator’s own record of what is already done, so they survive a restart of the operator. The gate itself is: the operator does not evict the next member until the previous one isReadyand the cluster reports a healthy quorum (healthy members >= N/2+1) again. The matchingGetLeader--<pod>andEvictPod--<pod>conditions are elided from the output above. - The followers (
etcd-cluster-1,etcd-cluster-2in this run) are restarted before the Raft leader (etcd-cluster-0here). Which pod is the leader is discovered at runtime, so the order you observe depends on where leadership happens to sit when the ops request starts. - Before the leader is evicted, the operator issues a
MoveLeaderRPC to hand leadership to another voting member, and always records aMoveLeader--<pod>condition naming the pod it moved leadership away from.
Now let’s verify from the PetSet and the pods that the resources have been updated:
$ kubectl get petset -n demo etcd-cluster \
-o jsonpath='{.spec.template.spec.containers[?(@.name=="etcd")].resources}' | jq
{
"limits": {
"cpu": "1",
"memory": "2Gi"
},
"requests": {
"cpu": "1",
"memory": "2Gi"
}
}
$ kubectl get pod -n demo etcd-cluster-0 -o json | jq '.spec.containers[] | select(.name=="etcd") | .resources'
{
"limits": {
"cpu": "1",
"memory": "2Gi"
},
"requests": {
"cpu": "1",
"memory": "2Gi"
}
}
The new resources are also persisted onto the Etcd object itself, so the Provisioner operator
re-renders the same template after the database is resumed:
$ kubectl get etcd -n demo etcd-cluster \
-o jsonpath='{.spec.podTemplate.spec.containers[?(@.name=="etcd")].resources}' | jq
{
"limits": {
"cpu": "1",
"memory": "2Gi"
},
"requests": {
"cpu": "1",
"memory": "2Gi"
}
}
In-Place Vertical Scaling
To resize the member pods without restarting them, set spec.verticalScaling.mode to InPlace.
The operator resizes the running containers through the Kubernetes pods/resize subresource; no pod
is evicted, no Raft leadership is moved, and there is no election risk at all.
apiVersion: ops.kubedb.com/v1alpha1
kind: EtcdOpsRequest
metadata:
name: etcd-vscale-inplace
namespace: demo
spec:
type: VerticalScaling
databaseRef:
name: etcd-cluster
verticalScaling:
mode: InPlace
etcd:
resources:
requests:
cpu: "1"
memory: "3Gi"
limits:
cpu: "1"
memory: "3Gi"
timeout: 10m
apply: IfReady
$ kubectl apply -f https://github.com/kubedb/docs/raw/v2026.8.26-rc.2/docs/examples/etcd/scaling/vertical-scaling/etcdops-vscale-inplace.yaml
etcdopsrequest.ops.kubedb.com/etcd-vscale-inplace created
The condition list looks the same up to UpdateDatabase; the actuation step is then reported through
RequestInPlaceResize--<pod> / CheckInPlaceResizeSettled--<pod> conditions and finishes with:
Message: Successfully resized the etcd members in place
Reason: VerticalScale
Status: True
Type: VerticalScale
If the kubelet reports the resize as Infeasible for a pod (its Node cannot fit the new request
without a reschedule), the operator logs that and falls back to the Restart behavior for that pod
only, using the same leader-last ordering. So a partially infeasible InPlace request still
converges — some pods are resized live, the rest are rolled.
Note:
InPlacerequires the KubernetesInPlacePodVerticalScalingfeature gate (on by default from Kubernetes v1.33). On older clusters useRestart.
Cleaning Up
To clean up the Kubernetes resources created by this tutorial, run:
kubectl delete etcdopsrequest -n demo etcd-vscale etcd-vscale-inplace
kubectl delete etcd -n demo etcd-cluster
kubectl delete ns demo
Next Steps
- Scale the cluster horizontally.
- Expand the volume of an Etcd cluster.
- Detail concepts of the EtcdOpsRequest object.
































