August 23, 2024·4 min read·engineeringkafkastrimzikraftoperations

Strimzi unregisters removed KRaft nodes after scale down

Strimzi 0.43 cleans up KRaft broker registrations after node removal. Its reconciliation state retains unfinished cleanup so failures can be retried without forgetting newly added nodes.

Removing a Kubernetes pod and removing a Kafka broker registration are different operations. An operator that completes only the first can leave the metadata system describing a node that its desired deployment no longer includes. Cleanup needs to reconcile the identities known before scaling with those that remain afterward.

Strimzi 0.43.0, released August 23, adds KRaft node unregistration after scale-down. The release also supports Kafka 3.8.0 and additional volumes. The unregistration implementation is a useful example of the state an operator must retain when cleanup can fail independently of the main deployment change.

Kafka's durable history is valuable to me partly because its replication model is explicit. The machinery managing that model also needs an accurate account of which brokers belong to the deployment. Pod removal alone cannot establish that the controller's registration state has been cleaned up.

Reconciliation compares node identities

PR #10442 introduces node unregistration and a registeredNodeIds status field. The field records identities used by the reconciliation logic. Its API description calls it internal and says it will be removed in the future, so it should not be treated as a permanent user configuration interface.

The released reconciler obtains the current node IDs and compares them with the previous list. When the metadata configuration is KRaft and previous IDs are absent from the current set, it constructs the list to unregister by subtraction.

That means the decision is based on identity, rather than only a change in replica count. Two lists can have the same size while containing different nodes. Conversely, adding nodes does not imply that any previous node needs removal. Set comparison expresses the actual cleanup requirement.

The logic also handles the first reconciliation without historical IDs. It records the current list rather than pretending to know which earlier registrations should be removed. The previous state supplies the evidence for this particular cleanup path.

The Admin API performs the metadata operation

The new helper uses Kafka's Admin client to unregister each selected broker ID. It creates the client using the cluster bootstrap service and the operator's authentication material. The operation therefore runs through Kafka's own administrative interface after the operator determines the removed identities.

A broker that is already unregistered is treated as successful cleanup. That is an appropriate result for a repeated request whose desired state is absence of the registration. Other failures remain failures of the cleanup operation and are logged accordingly.

The client is closed after the combined work finishes. The implementation separates selecting the identities, invoking Kafka's operation and releasing the client used for that operation. Each part has an observable result that the reconciler can use without confusing a deleted pod with completed metadata cleanup.

Failed cleanup retains both old and current identities

On success, the reconciler updates status to the current node list. On failure, it keeps the previous identities and merges in the current ones. This detail prevents retry state from discarding nodes added while an earlier removal remains unfinished.

Consider previous identities that include a removed node while the current deployment also includes a newly added one. Saving only the old list would preserve the removal retry but forget the new identity. Saving only the current list would forget the removal that still needs cleanup. The union retains both facts for another reconciliation.

The code completes the overall reconciliation promise successfully even when unregistration fails. That choice avoids making this cleanup failure stop the entire reconciliation. Retaining the identity state is what permits that choice without permanently losing the unfinished work.

I find the retry state more significant than the happy-path API call. A controller that can repeat cleanup needs evidence of what remains unfinished. Reporting overall reconciliation progress is compatible with retrying one operation only if the stored state continues to represent that operation.

Other release changes affect separate storage responsibilities

Strimzi 0.43 also allows additional volumes and mounts through custom resources. That adds control over pod inputs, while KRaft unregistration changes metadata cleanup. Neither change should be mistaken for automatic partition reassignment or proof that a removed node's storage can be discarded.

The release deprecates per-broker storage-class overrides in favor of multiple KafkaNodePool resources with different classes. It also removes support for Kafka 3.6 releases while adding 3.8.0. These are distinct configuration and compatibility changes around the same operator update.

For scale-down, the concrete improvement is reconciliation of removed node identities with Kafka registrations. The operator computes the missing IDs, requests unregistration, and preserves enough status to retry failures while tracking current nodes. That completes a metadata responsibility that deleting the Kubernetes workload cannot satisfy on its own.