This is unreleased documentation for SUSE® Virtualization v1.9 (Dev).

Harvester Cloud Provider

You can provision RKE2 clusters in Rancher using the built-in Harvester Node Driver. SUSE Virtualization provides load balancer and storage passthrough support to the guest Kubernetes cluster.

Backward Compatibility Notice

Please note a known backward compatibility issue if you’re using the Harvester Cloud Provider version v0.2.2 or higher. If your SUSE Virtualization version is below v1.2.0 and you intend to use newer RKE2 versions (i.e., >= v1.26.6+rke2r1, v1.25.11+rke2r1, v1.24.15+rke2r1), it is essential to upgrade your cluster to v1.2.0 or a higher version before proceeding with the upgrade of the guest Kubernetes cluster or Harvester Cloud Provider.

For more informmation, see the Harvester CCM & CSI Driver with RKE2 Releases section of the Support Matrix.

Deploying

Prerequisites

  • The Kubernetes cluster is built on top of SUSE Virtualization virtual machines.

  • The SUSE Virtualization virtual machines run as guest Kubernetes nodes are in the same namespace.

  • The SUSE Virtualization virtual machine guests' hostnames match their corresponding SUSE Virtualization virtual machine names. Guest cluster SUSE Virtualization VMs can’t have different hostnames than their SUSE Virtualization VM names when using the Harvester CSI Driver. We hope to remove this limitation in a future release.

Each SUSE Virtualization VM must have the macvlan kernel module, which is required for the LoadBalancer services of the DHCP IPAM mode.

To check if the kernel module is available, access the VM and run the following commands:

lsmod | grep macvlan
sudo modprobe macvlan

The kernel module is likely to be missing if the following occur:

  • $ lsmod | grep macvlan does not produce output.

  • $ sudo modprobe macvlan displays an error message similar to modprobe: FATAL: Module macvlan not found in directory /lib/modules/5.14.21-150400.22-default.

By default, the macvlan kernel module is not included in SUSE Linux Enterprise 15 Service Pack 4/5/6 minimal cloud images (see Issue #6418). Those images contain the kernel-default-base package, which includes only the base modules. However, the macvlan kernel driver becomes available when you install the kernel-default package.

To eliminate the need for manual intervention after the guest cluster is provisioned, build your own cloud images using the openSUSE Build Service (OBS). You must remove the kernel-default-base package and add the kernel-default package in the Minimal.kiwi file to ensure that the resulting cloud image includes the macvlan kernel module. For more information, see Custom SUSE VM Images.

Deploying to the RKE2 Cluster with Harvester Node Driver

When spinning up an RKE2 cluster using the Harvester Node Driver, select the Harvester cloud provider. The node driver will then help deploy both the CSI driver and CCM automatically.

rke2 cloud provider

Starting with Rancher v2.9.0, you can configure a specific folder for cloud config data using the Data directory configuration path field.

rke2 cloud provider custom data dir

Manually deploying to the RKE2 cluster

  1. Generate the cloud-config for the Harvester Cloud Provider.

  2. On the RKE2 cluster creation page, go to the Cluster Configuration screen and set the value of Cloud Provider to External.

    external harvester cloud provider
  3. Copy and paste the cloud-init user data content to Machine Pools > Show Advanced > User Data.

    cloud config userdata
  4. Add the HelmChart CRD for harvester-cloud-provider to Cluster Configuration > Add-On Config > Additional Manifest.

    You must replace <cluster-name> with the name of your cluster.

     apiVersion: helm.cattle.io/v1
     kind: HelmChart
     metadata:
       name: harvester-cloud-provider
       namespace: kube-system
     spec:
       targetNamespace: kube-system
       bootstrap: true
       repo: https://raw.githubusercontent.com/rancher/charts/dev-v2.9
       chart: harvester-cloud-provider
       version:  104.0.2+up0.2.6
       helmVersion: v3
       valuesContent: |-
         global:
           cattle:
             clusterName: <cluster-name>
    external cloud provider addon
  5. To create the load balancer, add the annotation cloudprovider.harvesterhci.io/ipam: <dhcp|pool>.

    harvester cloud provider loadbalancer annotation

Deploying to the RKE2 custom cluster (experimental)

custom
  1. Generate the cloud-config for the SUSE Virtualization Cloud Provider.

  2. Create a VM in the SUSE Virtualization cluster with the following settings:

    • Basics tab: The minimum requirements are 2 CPUs and 4 GiB of RAM. The required disk space depends on the VM image.

      custom cluster vm cpu and ram
    • Networks tab: Specify a network name with the format nic-<number>.

      custom cluster vm network
    • Advanced Options tab: Copy and paste the content of the Cloud Config User Data screen.

      custom cluster vm user data
  3. On the Basics tab of the Cluster Configuration screen, select Harvester as the Cloud Provider and then select Create to spin up the cluster.

    create custom rke2
  4. On the Registration tab, perform the steps required to run the RKE2 registration command on the VM.

    custom cluster registration

Deploying to the K3s cluster with Harvester Node Driver (experimental)

  1. Generate the cloud-config for the Harvester Cloud Provider.

  2. Copy and paste the cloud-init user data content to Machine Pools > Show Advanced > User Data.

    cloud config userdata

  3. Add the following HelmChart yaml of harvester-cloud-provider to Cluster Configuration > Add-On Config > Additional Manifest.

     apiVersion: helm.cattle.io/v1
     kind: HelmChart
     metadata:
       name: harvester-cloud-provider
       namespace: kube-system
     spec:
       targetNamespace: kube-system
       bootstrap: true
       repo: https://charts.harvesterhci.io/
       chart: harvester-cloud-provider
       version: 0.2.2
       helmVersion: v3
    external cloud provider addon
  4. Disable the in-tree cloud provider in the following ways:

    • Click the Edit as YAML button.

      edit k3s cluster yaml
    • Disable servicelb and set disable-cloud-controller: true to disable the default K3s cloud controller.

        machineGlobalConfig:
          disable:
            - servicelb
          disable-cloud-controller: true
    • Add cloud-provider=external to use the Harvester Cloud Provider.

        machineSelectorConfig:
          - config:
              kubelet-arg:
              - cloud-provider=external
              protect-kernel-defaults: false
    k3s cluster yaml content for harvester cloud provider

With these settings in place a K3s cluster should provision successfully while using the external cloud provider.

Generating the cloud-config for the Harvester Cloud Provider

The Harvester Cloud Provider requires a cloud-config file to connect to the remote SUSE Virtualization cluster (for example, to query virtual machine information or allocate load balancers). You can generate this file using either the API endpoint or a bash script.

Support for the bash script method will be deprecated in a future release. Use the API endpoint to ensure long-term compatibility.

  • API

  • Bash Script

You can send POST and GET requests to the SUSE Virtualization API endpoint /v1/harvester/kubeconfig using an admin bearer token.

==== Request parameters

Parameter Type Description Example

namespace

String

Target Kubernetes namespace

gc-test

serviceAccountName

String

Service account name

gc4

clusterRoleName

String

ClusterRole to bind to the service account (optional)

harvesterhci.io:cloudprovider (only supported value)

outputFormat

String

Output format

yaml (only supported value)

  • clusterRoleName: SUSE Virtualization uses harvesterhci.io:cloudprovider by default if this field is left empty.

  • outputFormat: Setting this to yaml retrieves the cloud-init user data. Specifying any other value or leaving the field empty returns the raw kubeconfig file.

==== POST request

Add -k/--insecure to the curl command only if your SUSE Virtualization endpoint uses a self-signed certificate.

 curl -X POST \
  -H "Authorization: Bearer token-abcde:..." \
  -H "Content-Type: application/json" \
  -d '{"namespace": "gc-test", "serviceAccountName": "gc4", "outputFormat": "yaml"}' \
  "https://<vip>/v1/harvester/kubeconfig"

==== POST response

########## cloud-init user data ############
write_files:
- encoding: b64
  content: <BASE64_CONTENT>
  owner: root:root
  path: /etc/kubernetes/cloud-config
  permissions: '0644'
- encoding: b64
  content: <BASE64_CONTENT>
  owner: root:root
  path: /var/lib/rancher/rke2/etc/config-files/cloud-provider-config
  permissions: '0644'

==== GET request

Use a single ampersand (&) to separate query parameters.

curl -X GET \
  -H "Authorization: Bearer token-abcde:..." \
  "https://<vip>/v1/harvester/kubeconfig?namespace=gc-test&serviceAccountName=gc4&outputFormat=yaml"

==== GET response

The API response automatically includes cloud-init configurations for both legacy and new paths. Before applying this configuration, remove the block that does not apply to your environment.

########## cloud-init user data ############
write_files:
- encoding: b64
  content: <BASE64_CONTENT>
  owner: root:root
  path: /etc/kubernetes/cloud-config
  permissions: '0644'
- encoding: b64
  content: <BASE64_CONTENT>
  owner: root:root
  path: /var/lib/rancher/rke2/etc/config-files/cloud-provider-config
  permissions: '0644'

The script requires kubectl and jq to interact with the SUSE Virtualization cluster, and functions only when given access to the cluster’s kubeconfig file.

  1. Generate the cloud-config data using the generate_addon.sh script.

    curl -sfL https://raw.githubusercontent.com/harvester/cloud-provider-harvester/master/deploy/generate_addon.sh | bash -s <serviceaccount name> <namespace>
  2. Copy the generated data to every node.

    • Legacy path: /etc/kubernetes/cloud-config

    • RKE2 default path (v1.9.0 and later): /var/lib/rancher/rke2/etc/config-files/cloud-provider-config

You can find the kubeconfig file on any SUSE Virtualization management node at the following path: /etc/rancher/rke2/rke2.yaml. Before using the kubeconfig file, you must replace the IP address in the server: field with your cluster’s VIP address.

Example of content:

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: <redacted>
    server: https://127.0.0.1:6443
  name: default
# ...

You must specify the namespace in which the guest cluster will be created.

Example of output:

########## cloud config ############
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: <CACERT>
    server: https://HARVESTER-ENDPOINT/k8s/clusters/local
  name: local
contexts:
- context:
    cluster: local
    namespace: default
    user: harvester-cloud-provider-default-local
  name: harvester-cloud-provider-default-local
current-context: harvester-cloud-provider-default-local
kind: Config
preferences: {}
users:
- name: harvester-cloud-provider-default-local
  user:
    token: <TOKEN>

########## cloud-init user data ############
write_files:
- encoding: b64
  content: <CONTENT>
  owner: root:root
  path: /etc/kubernetes/cloud-config
  permissions: '0644'

In newer RKE2 versions (such as v1.33.11), the default cloud-config path is /var/lib/rancher/rke2/etc/config-files/cloud-provider-config. You must ensure that the cloudConfigPath value matches the exact file location you write to.

Depending on your setup, choose one of the following approaches:

  • Use the RKE2 default path: In the write_files entry in your cloud-init configuration, change the value of path to /var/lib/rancher/rke2/etc/config-files/cloud-provider-config.

  • Keep the legacy path: In the Rancher UI, set .spec.rkeConfig.chartValues.harvester-cloud-provider.cloudConfigPath to /etc/kubernetes/cloud-config.

Upgrade Cloud Provider

Upgrade RKE2

The cloud provider can be upgraded by upgrading the RKE2 version. You can upgrade the RKE2 cluster via the Rancher UI as follows:

  1. Click ☰ > Cluster Management.

  2. Find the guest cluster that you want to upgrade and select ⋮ > Edit Config.

  3. Select Kubernetes Version.

  4. Click Save.

Upgrade K3s

K3s upgrade cloud provider via the Rancher UI, as follows:

  1. Click ☰ > K3s Cluster > Apps > Installed Apps.

  2. Find the cloud provider chart and select ⋮ > Edit/Upgrade.

  3. Select Version.

  4. Click Next > Update.

The upgrade process for a single-node guest cluster may stall when the new harvester-cloud-provider pod is stuck in the Pending state. This issue is caused by a section in the harvester-cloud-provider deployment that describes the rolling update strategy. Specifically, the default value conflicts with the podAntiAffinity configuration in single-node clusters.

For more information, see this GitHub issue comment. To address the issue, manually delete the old harvester-cloud-provider pod. You might need to do this multiple times until the new pod can be successfully scheduled.

Load balancer support

Once you’ve deployed the Harvester Cloud Provider, you can leverage the Kubernetes LoadBalancer service to expose a microservice within the guest cluster to the external world. Creating a Kubernetes LoadBalancer service assigns a dedicated SUSE Virtualization load balancer to the service, and you can make adjustments through the Add-on Config within the Rancher UI.

lb svc

IPAM

SUSE Virtualization’s built-in load balancer offers both DHCP and Pool modes, and you can configure it by adding the annotation cloudprovider.harvesterhci.io/ipam: $mode to its corresponding service. Starting from Harvester Cloud Provider >= v0.2.0, it also introduces a unique Share IP mode. A service shares its load balancer IP with other services in this mode.

  • DHCP: A DHCP server is required. The SUSE Virtualization load balancer will request an IP address from the DHCP server.

  • Pool: You must first create an IP pool using either the SUSE Virtualization UI or the Rancher UI (see Best practices for information about the differences between the two methods). The SUSE Virtualization load balancer controller will allocate an IP for the load balancer service following the IP pool selection policy.

  • Share IP: When creating a new load balancer service, you can re-utilize an existing load balancer service IP. The new service is referred to as a secondary service, while the currently chosen service is the primary one. To specify the primary service in the secondary service, you can add the annotation cloudprovider.harvesterhci.io/primary-service: $primary-service-name. However, there are two known limitations:

    • Services that share the same IP address can’t use the same port.

    • Secondary services cannot share their IP with additional services.

Modifying the IPAM mode isn’t allowed. You must create a new service if you intend to change the IPAM mode.

Health checks

Beginning with Harvester Cloud Provider v0.2.0, additional health checks of the LoadBalancer service within the guest Kubernetes cluster are no longer necessary. Instead, you can configure liveness and readiness probes for your workloads. Consequently, any unavailable pods will be automatically removed from the load balancer endpoints to achieve the same desired outcome.

Automatic cleanup

When you delete a guest cluster that has the Harvester Cloud Provider enabled, SUSE Virtualization automatically cleans up all associated LoadBalancer resources. This offers the following key benefits:

  • Resource management: Automatic cleanup prevents orphaned load balancers from consuming IP addresses after the guest cluster is deleted.

  • Zero manual intervention: The lifecycle of the load balancer is tied directly to the lifecycle of the guest cluster.

Stale cloud credentials after cluster registration

If you remove a SUSE Virtualization cluster from Rancher and later re-register the same cluster, Rancher may retain stale cloud credentials that reference the previous management cluster ID. This mismatch causes provisioning of guest clusters (such as RKE2 and K3s clusters) to fail.

When this issue occurs, the system logs an error similar to the following:

clusters.management.cattle.io "<old-cluster-id>" not found

The failure occurs because the existing cloud credential still points to the original SUSE Virtualization cluster ID, which no longer exists after the re-registration process.

To mitigate the issue, perform the following workaround:

  1. On the Rancher UI, go to ☰ → Cluster Management → Cloud Credentials.

  2. Delete the stale cloud credential associated with the removed SUSE Virtualization cluster.

  3. Create a new cloud credential using the updated SUSE Virtualization cluster details.

  4. Provision the guest cluster again.

Related issue: #53642