kubernetes-sigs / kubernetes-sigs/cluster-api
Support opt-in two-member stacked-etcd KubeadmControlPlane for incremental bare-metal expansion
- Dominant language
- Go
- Stars
- 4.3k
- Forks
- 1.6k
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 113
Description
### User Story
As an operator of small bare-metal edge clusters, I need KubeadmControlPlane to support exactly two control-plane nodes with stacked etcd, with an explicit opt-in if necessary.
Hardware arrives incrementally: create a cluster on one node, add a second control-plane node, then add a third a week later. Two members must be a supported desired state during that interval, rather than only a transient state while reconciling toward three. Existing two-control-plane clusters also encounter this admission restriction when preparing KCP adoption.
We accept that two voting etcd members require both members for quorum and provide no member-failure tolerance. This request does not claim high availability for that topology.
### Current behavior and reproduction
With CAPI core, kubeadm bootstrap, and kubeadm control-plane providers v1.14.2, server-side dry runs produced:
| Desired KCP replicas | Local/stacked etcd admission result |
| --- | --- |
| 1 | Accepted |
| 2 | Rejected: `spec.replicas: Forbidden: cannot be an even number when etcd is stacked` |
| 3 | Accepted |
The configured Kubernetes version was v1.33.11; the infrastructure provider was k0smotron RemoteMachine v2.1.1. These were admission tests only: no resources were persisted, and successful admission does not demonstrate lifecycle support or adoption.
Minimal manifest below uses generic names. Save it as `kcp-two.yaml` and run `kubectl create --dry-run=server -f kcp-two.yaml` in a management cluster with the providers installed and an existing `edge-lab` namespace:
```yaml
apiVersion: controlplane.cluster.x-k8s.io/v1beta2
kind: KubeadmControlPlane
metadata:
name: edge-lab-control-plane
namespace: edge-lab
annotations:
cluster.x-k8s.io/paused: ""
spec:
replicas: 2
version: v1.33.11
machineTemplate:
spec:
infrastructureRef:
apiGroup: infrastructure.cluster.x-k8s.io
kind: RemoteMachineTemplate
name: edge-lab-control-plane
kubeadmConfigSpec:
clusterConfiguration:
etcd:
local:
dataDir: /var/lib/etcd
```
Repeat with `replicas: 1` and `replicas: 3` for the admission controls.
### Requested behavior
Provide a supported way to opt into exactly two stacked-etcd control-plane replicas, consistently across create, update, and the scale subresource. A documented existing mechanism would also resolve this request; I have not found one.
The required sequence is `1 -> 2 -> 3`, with the cluster allowed to remain at two for days or longer. Making the second node a worker does not meet the requirement. Declaring three desired replicas while only supplying two hosts does not accurately describe the intended state.
Quorum protections should remain in place. Please clarify the supported upgrade, replacement, and remediation behavior at two members, including when spare capacity is necessary. Simply removing admission validation is not evidence that those operations are safe; lifecycle tests and documented constraints would be needed.
### Related history
This restriction appears intentional: #4057 and #5466 addressed paths that allowed even replica counts, including the scale subresource. Accordingly, this is a request for an explicit supported exception, rather than a claim that the current webhook violates its existing contract.
Relevant v1.14.2 validation:
- [KubeadmControlPlane validation](https://github.com/kubernetes-sigs/cluster-api/blob/v1.14.2/controlplane/kubeadm/webhooks/admission/kubeadmcontrolplane.go)
- [Scale validation](https://github.com/kubernetes-sigs/cluster-api/blob/v1.14.2/controlplane/kubeadm/webhooks/admission/kubeadmcontrolplane_scale.go)
/kind feature
/area control-plane
Contributor guide
Research direction
Start by reading controlplane/kubeadm/webhooks/admission/kubeadmcontrolplane.go and kubeadmcontrolplane_scale.go, then reproduce the server-side dry runs with replicas 1, 2, and 3. Trace the related history in #4057 and #5466 before deciding how an explicit opt-in would work. Done means create, update, and scale consistently support the opt-in, while lifecycle tests and documented upgrade, replacement, remediation, and quorum constraints cover two-member operation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, kubernetes
- Domain
- distributed-systems, infrastructure
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100