Stale KRaft ControllerRegistration IDs block metadata upgrade to 3.9-IV0 from 3.7.IV4 after controller NodePool ID migration #13001
Replies: 3 comments 4 replies
|
Also commented on the PR here |
|
Thsi has been discussed multiple times in the past. The only workaround is as far as I know to add the nodes again, upgrade the metadata version and then remove them. I do not think Kafka offers any other way. |
|
For Future travelers Recovering a KRaft metadata-version upgrade blocked by stale controller IDsScope and safety boundaryThis is a controlled recovery runbook : Commands are hard-coded with below example values, please change accordingly -
The historical controller IDs The Strimzi workaround is to re-add IDs Desired steady state# broker KafkaNodePool
metadata:
annotations:
strimzi.io/next-node-ids: "[0-49]"
# controller KafkaNodePool
metadata:
annotations:
strimzi.io/next-node-ids: "[90-99]"
spec:
replicas: 3
# Kafka
spec:
kafka:
version: 3.9.2
metadataVersion: "3.9-IV0"Phase 0: preflightkubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
get kafka strimzi
kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
get kafkanodepool broker controller \
-o custom-columns=NAME:.metadata.name,REPLICAS:.spec.replicas,ROLES:.spec.roles,NEXT:.metadata.annotations.strimzi\\.io/next-node-ids,REMOVE:.metadata.annotations.strimzi\\.io/remove-node-ids
kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
get kafka strimzi \
-o jsonpath='metadata={.status.kafkaMetadataVersion}{"\\n"}registered={.status.registeredNodeIds}{"\\n"}conditions={.status.conditions}{"\\n"}'
kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
get pods -l strimzi.io/cluster=strimzi⚠ Before Phase 1, the cluster must be Keep GitOps aligned with every intermediate annotation and replica value. Otherwise the next reconciliation can revert an in-progress stage. Phase 1: reserve IDs and add controllers 3, 4, and 5# Reserve 3–5 for the temporary controllers. Do not leave them available
# to a broker scale-up during this procedure.
kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
annotate kafkanodepool broker \
strimzi.io/next-node-ids='[0-2,6-49]' \
--overwrite
# Select 3, 4, then 5 for the scale-up while retaining 90–99 as the
# normal future controller allocation range.
kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
annotate kafkanodepool controller \
strimzi.io/next-node-ids='[3-5,90-99]' \
--overwrite
# Add exactly three temporary controllers. Expected IDs: 3, 4, and 5.
kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
patch kafkanodepool controller --type=merge \
-p '{"spec":{"replicas":6}}'Wait until all three temporary Pods are Ready: kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
wait --for=condition=Ready pod/strimzi-controller-3 \
pod/strimzi-controller-4 \
pod/strimzi-controller-5 \
--timeout=20m
kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
get kafka strimzi \
-o jsonpath='metadata={.status.kafkaMetadataVersion}{"\\n"}registered={.status.registeredNodeIds}{"\\n"}conditions={.status.conditions}{"\\n"}'Stop if controllers Phase 2: finalize the metadata versionUpdate the GitOps Kafka manifest to: spec:
kafka:
version: 3.9.2
metadataVersion: "3.9-IV0"If an imperative update is approved for the maintenance window, apply the same kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
patch kafka strimzi --type=merge \
-p '{"spec":{"kafka":{"metadataVersion":"3.9-IV0"}}}'Ensure the GitOps manifest has the same value before its next sync. After the kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
get kafka strimzi --watchContinue only after the resource reports: Confirm that no new feature-level rejection occurs: kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
logs strimzi-controller-90 -c kafka --since=15m \
| grep -F 'Invalid update version' || truePhase 3: remove temporary controllers and restore original values# Choose only the temporary controller IDs for removal.
kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
annotate kafkanodepool controller \
strimzi.io/remove-node-ids='[3-5]' \
--overwrite
# Restore the original three-controller pool.
kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
patch kafkanodepool controller --type=merge \
-p '{"spec":{"replicas":3}}'
kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
wait --for=delete pod/strimzi-controller-3 \
pod/strimzi-controller-4 \
pod/strimzi-controller-5 \
--timeout=20mOnly after IDs kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
annotate kafkanodepool controller \
strimzi.io/next-node-ids='[90-99]' \
--overwrite
kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
annotate kafkanodepool controller \
strimzi.io/remove-node-ids-
kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
annotate kafkanodepool broker \
strimzi.io/next-node-ids='[0-49]' \
--overwriteFinal validationkubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
get kafka strimzi \
-o jsonpath='metadata={.status.kafkaMetadataVersion}{"\\n"}registered={.status.registeredNodeIds}{"\\n"}conditions={.status.conditions}{"\\n"}'
kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
get kafkanodepool broker controller \
-o custom-columns=NAME:.metadata.name,REPLICAS:.spec.replicas,NEXT:.metadata.annotations.strimzi\\.io/next-node-ids,REMOVE:.metadata.annotations.strimzi\\.io/remove-node-ids
kubectl --context bld-aks-cluster-eastus2 -n bld-kafka \
get pods -l strimzi.io/cluster=strimziExpected final state: |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
We have a Strimzi KRaft cluster on AKS that is healthy and running Kafka 3.9.2, but it cannot finalize the metadata upgrade from 3.7-IV4 to 3.9-IV0 after upgrading from Strimzi
0.42.0to0.45.2, Kafka from3.7.1to3.9.2.The controller rejects the metadata feature update because historical controller registrations remain in the metadata log:
The active cluster is healthy and reports =Ready=True= , but its metadata version remains 3.7-IV4.
Environment
Current active nodes:
Historical NodePool ID allocation
Initially, the controller NodePool did not have reserved node-ID ranges. During the ZooKeeper-to-KRaft migration, Strimzi assigned controllers IDs 3, 4, and 5, while brokers used 0, 1, and 2.
We later introduced explicit allocation ranges:
The active controller NodePool now uses IDs 90, 91, and 92. The original controllers 3, 4, and 5 are no longer Pods or quorum voters, but their registrations remain in the KRaft metadata.
Relevant historical registrations observed in controller logs:
The active controllers and brokers re-registered with support for metadata feature levels 1-21.
Reproduction / observed result
With:
Strimzi attempts the metadata feature update, but Kafka rejects it:
Current safe mitigation
We changed only the desired metadata version back to the finalized version:
This retains Kafka 3.9.2, avoids repeated failed update attempts, and the cluster is Ready=True.
The remaining status warning is expected:
Due diligence performed
Confirmed the active KRaft voters are only 90,91,92; IDs 3,4,5 are not current controller Pods or voters.
Confirmed active nodes support metadata feature level 21; the historical controller registrations cap support at 19.
Reviewed Strimzi discussion Unable to upgrade to 3.9.0: Could not upgrade metadata.version to 21 #11147, which identifies the static-controller-quorum limitation for this class of issue.
Reviewed KAFKA-17094 / KIP-1073. Kafka 4.0 adds visibility of fenced brokers, but does not remove stale controller registrations.
Reviewed Kafka PR #22191, which proposes the missing controller-unregistration capability: a new Admin#unregisterController API, kafka-cluster.sh unregister-controller, and an UnregisterControllerRecord that removes a controller from the metadata image.
However, the PR is not currently an in-place repair path for this cluster. It introduces the unregistration record behind new metadata version IBP_4_4_IV1. Our cluster is finalized at 3.7-IV4 and cannot even advance to 3.9-IV0, because the stale controller registrations 3, 4, and 5 advertise maximum metadata.version feature level 19.
Therefore, upgrading Kafka binaries to a future release containing this PR would not automatically remove the stale registrations. The cluster would still be at metadata 3.7-IV4, and the new unregister-controller operation would be unavailable because the cluster has not finalized the metadata capability required to write its new record. Advancing metadata to that capability remains blocked by the same stale controller registrations—creating a circular dependency.
We need a supported repair procedure that can remove obsolete controller registrations while the cluster remains at its existing finalized metadata version, or another supported migration path that breaks this dependency.
Request
Is there a supported Strimzi procedure for removing/pruning obsolete ControllerRegistration entries from a migrated static KRaft quorum when the old controller IDs are no longer voters or Pods?
Specifically, we need a safe way to remove controller registrations 3, 4, and 5, allowing the cluster to advance from metadata
3.7-IV4to3.9-IV0, without recreating the cluster or manually modifying__cluster_metadata.All reactions