Introduction#

I’ve been having a lot of fun with my OpenStack cluster. If you use Kubernetes, you probably have a need for provisioning services of type LoadBalancer. On bare-metal environments (mostly the case in typical homelab setups), you would rely on a solution like MetalLB (or even a CNI like Cilium). But since Openstack already provides LoadBalancers via Octavia, we’ll use that instead. We’ll try Talos for this demonstration.

I was naive to think that I could simply install the CCM (Cloud Contoller Manager) for OpenStack after the cluster is up. While it might work, fields like ProviderID (on K8s nodes) are immutable. Installing a Talos cluster (or any other k8s distro) with the default settings will not let the OpenStack CCM do it’s thing (since the default Talos contorller manager will intefere with it). Hence, we must disable certain components before installing a cluster.

This is just a short demo meant for a quick evaluation. Production grade clusters will obviously do something like https://www.safespring.com/blogg/2025/2025-06-deploy-talos-kubernetes-on-openstack-with-cluster-api/.

Process#

Follow https://docs.siderolabs.com/talos/v1.11/platform-specific-installations/cloud-platforms/openstack

  1. Create patches and use them while invoking talosconfig (using “–config-patch-control-plane” and “–config-patch-worker”)

Contol Plane Patch:

cluster:
  controllerManager:
    extraArgs:
      cloud-provider: external
machine:
  kubelet:
    extraArgs:
      cloud-provider: external

Worker Patch:

machine:
  kubelet:
    extraArgs:
      cloud-provider: external
  1. Wait for the cluster nodes to come up. The nodes will be in NotReady state. This is expected since we disabled contoller manager.

  2. Follow instructions here: https://github.com/kubernetes/cloud-provider-openstack/tree/master/charts/openstack-cloud-controller-manager

Example secret:

cloudConfig:
  global:
    auth-url: "https://<url>:5000"
    region: "RegionOne"
    application-credential-id: "<id>"
    application-credential-secret: "<secret>"
  loadBalancer:
    floating-network-id: "<id>"
    subnet-id: "<id>"
  1. Check if ProviderID is set on nodes. Also, try creating a LoadBalancer to check whether provisioning LBs works.