Use OCCM and Cinder CSI in Kubernetes

Connect a Kubernetes cluster that runs on your instances to load balancers and volumes with the OpenStack cloud controller manager and Cinder CSI.

A Kubernetes cluster that runs on your instances can use the cloud's load balancers and volumes. Two upstream components do this: the OpenStack cloud controller manager (OCCM) creates a load balancer for each Service of type LoadBalancer, and the Cinder CSI driver creates volumes for persistent volume claims. Both read the same configuration file, cloud.conf, which the console generates for an application credential.

Before you begin

  • Create a service account for the cluster, with the Owner or Contributor role, or a custom role with Manage access to compute, networking, storage, and load balancers in the project. See Service accounts and API tokens.
  • Create an application credential for that service account with the Full access profile, and download cloud-config-secret.yaml. See Create an application credential.
  • You need kubectl access to the cluster and the openstack CLI. See Use the openstack CLI.

Use one service account credential per cluster. A personal credential stops working when its owner leaves your organization or loses their role in the project, and the cluster would then lose control of its load balancers and volumes. Creating load balancers needs the Keystone role load-balancer_member, which only the Full access profile includes.

Set the network for public load balancers

Find the external network that provides public addresses:

List external networks
openstack network list --external -c ID -c Name

In cloud-config-secret.yaml, uncomment the floating-network-id line in the [LoadBalancer] section, and set it to the network's ID.

You can also set the network per Service with an annotation instead. See Expose a Service through a load balancer.

Install the components

Create the Secret kube-system/cloud-config that both components read:

Create the Secret
kubectl apply -f cloud-config-secret.yaml

Install OCCM from the upstream manifests of cloud-provider-openstack, with a cluster name that's unique among the clusters in the project:

Install OCCM
BASE=https://raw.githubusercontent.com/kubernetes/cloud-provider-openstack/release-1.31/manifests
kubectl apply -f $BASE/controller-manager/cloud-controller-manager-roles.yaml
kubectl apply -f $BASE/controller-manager/cloud-controller-manager-role-bindings.yaml
curl -fsSL $BASE/controller-manager/openstack-cloud-controller-manager-ds.yaml \
  | sed 's/value: kubernetes$/value: <cluster-name>/' | kubectl apply -f -

Replace <cluster-name> with your cluster's name.

In the same shell, so that BASE is still set, install Cinder CSI:

Install Cinder CSI
for f in cinder-csi-controllerplugin-rbac cinder-csi-controllerplugin \
         cinder-csi-nodeplugin-rbac cinder-csi-nodeplugin csi-cinder-driver; do
  kubectl apply -f $BASE/cinder-csi-plugin/$f.yaml
done

The commands use the release-1.31 manifests of cloud-provider-openstack, the release that the console's guide was checked against.

The cluster name is part of the name of every load balancer that OCCM creates, so it must be unique among the clusters in the project.

Create volumes

Create a StorageClass for Cinder CSI, and request a volume with a persistent volume claim:

storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: cinder
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: cinder.csi.openstack.org
allowVolumeExpansion: true
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data
spec:
  accessModes: ["ReadWriteOnce"]
  storageClassName: cinder
  resources:
    requests:
      storage: 1Gi

The volumes appear in the project's Block Storage, and they're billed like volumes that you create in the console.

Expose a Service through a load balancer

service-lb.yaml
apiVersion: v1
kind: Service
metadata:
  name: web
  annotations:
    # Optional when floating-network-id is set in cloud.conf:
    loadbalancer.openstack.org/floating-network-id: "<external-network-id>"
spec:
  type: LoadBalancer
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080

Replace <external-network-id> with the ID of the external network, or remove the annotation if you set floating-network-id in the Secret. OCCM creates a load balancer in the project, which appears in the console like any other load balancer.

Rotate the cluster's credential

After you rotate the credential, download the new cloud-config-secret.yaml, set floating-network-id in it again, and restart the components before the overlap window ends:

Roll out the new credential
kubectl apply -f cloud-config-secret.yaml
kubectl -n kube-system rollout restart daemonset/openstack-cloud-controller-manager
kubectl -n kube-system rollout restart deployment/csi-cinder-controllerplugin daemonset/csi-cinder-nodeplugin

See Rotate and revoke credentials.

On this page