April 17, 2019·4 min read·engineeringkubernetescontrollerscloud

Cloud provider extraction changes who owns cluster integration

SIG Cloud Provider wants infrastructure integrations released independently of Kubernetes. The cloud controller manager makes that possible, but node initialization shows why moving these controllers requires a careful migration.

A cloud-specific bug fix should not have to wait for the release of an entire orchestration system. That is one of the maintenance problems behind SIG Cloud Provider's April 17 account of its work. Andrew Sy Kim, Mike Crute and Walter Fender describe a project whose infrastructure integrations have become too closely coupled to Kubernetes core. Their goal is to develop and maintain those integrations as extensions or add-ons, with providers able to release independently.

This is a change in ownership of essential control-plane behavior. Discovering node addresses and zones, creating service load balancers, and maintaining cloud routes all depend on provider knowledge. The Kubernetes API can express the requested object, but some component must translate that request into operations against the infrastructure. Extraction moves that responsibility into separately deployed software while retaining the cluster's resource model.

I consider the API and its controllers the strongest part of Kubernetes. Keeping provider implementation details behind a controller boundary fits that design. It also makes the extra controller an operational dependency that must be understood, especially while a cluster changes between integration models.

What the existing coupling costs

The SIG's article explains that in-tree providers are developed and released in the main Kubernetes repository. Their dependencies enter Kubernetes components, increasing binary size and the set of potentially vulnerable dependencies. Provider-specific changes also consume more of the release notes. These costs affect users even when the changes concern infrastructure they do not use.

The coupling extends beyond the main controller manager. The article says core components other than the scheduler and kube-proxy expose a cloud-provider flag. Kubelet can use provider metadata to discover information about its own node. Removing vendor code therefore requires preserving interactions spread across different parts of the system. It is not enough to move a directory and rebuild one executable.

An out-of-tree provider can build and release independently. Its cloud-controller-manager runs cloud-specific controllers previously handled by kube-controller-manager. This creates a separate place to operate and update the provider implementation. Kubernetes core can retain general-purpose behavior while the provider supplies its infrastructure-specific integration.

The article dates the out-of-tree approach to late 2017 and says it has become the usual route for new infrastructure providers. Existing installations are a different problem. Most clusters still use in-tree providers according to the SIG, so completing the architectural change requires migrating an installed population. New integrations can adopt the boundary from their first deployment. Existing clusters must preserve behavior while responsibility changes.

Node initialization exposes the coordination problem

The cloud node controller in Kubernetes 1.14 shows the kind of coordination involved. Its node-add handler looks for a cloud taint before initializing a new node. A node without that taint does not enter this initialization path. The marker lets an asynchronous controller recognize the work it is responsible for completing.

Initialization then obtains information from the cloud provider. The code tries to populate an empty provider ID, obtains node addresses and checks a user-provided node IP against those addresses. It also adds the instance-type label when the provider supplies one. Where a zone interface exists, it obtains zone information and populates the corresponding labels. These are concrete operations that must survive extraction.

There is an instructive distinction in the error paths. Failure to obtain a provider ID is logged but can allow the code to proceed because address lookup can fall back to the node name. Failure to validate a supplied node IP returns an error. The controller therefore treats metadata according to its actual role in initialization rather than considering all provider calls interchangeable.

The same file keeps periodic address updates separate from initial processing. It skips updates for nodes still carrying the cloud taint and checks whether a node exists according to its provider ID before updating its address. This is evidence of an ongoing integration, not a one-time exchange during installation. The external controller needs to continue reconciling information after registration.

That mechanism explains the migration risk more precisely than a general warning about upgrades. A node can exist as a Kubernetes object while provider initialization remains unfinished. Separating the processes means their handoff must remain meaningful. Metadata lookup and removal of the initialization marker must stay associated with the controller that can complete the work.

The address lookup also tries the provider ID before falling back to the node name. Those alternatives show how the controller accommodates information that may be incomplete during initialization.

Independent releases retain operational obligations

The SIG says a safe and easy migration path is its highest priority for upcoming releases. That wording describes work ahead, so the April announcement should not be read as removal of existing providers or a universal instruction to switch immediately. Its stated destination is a Kubernetes core without native cloud integrations, with minimal disruption to users during the transition.

Other integration mechanisms are part of that destination. The article mentions CSI and the image credential provider as extension points being worked on for Kubernetes 1.15. This matters because cloud integration includes more than the controllers that create load balancers or routes. Different operations need suitable extension mechanisms, and moving the cloud controller alone cannot establish that every vendor dependency has left core.

I support independent provider releases because they make the component responsible for a fix easier to identify. They also create another installed version that the cluster operator has to manage. A separately released controller still needs to understand the Kubernetes objects it watches and the infrastructure API it calls. Independence removes a release dependency without removing those functional relationships.

The practical result is a clearer division of maintenance. Provider authors can update their own integration without putting every change through the Kubernetes core release. Operators gain a separately deployable component whose behavior includes node metadata and cloud resource management. During migration, that component must take responsibility for the same work that the in-tree integration previously performed, including initialization that determines when a node's provider information is usable.