Install the Bare Metal Provider

This document describes how to install the Infrastructure Provider for Bare Metal and the Cluster Bootstrap Provider on the global cluster, and how to prepare a global cluster installed on Bare Metal as a management cluster.

When You Need This

Complete Install the Provider Plugins after the global cluster is installed and before you create the first workload cluster on Bare Metal. It is required regardless of the IaaS platform that the global cluster itself runs on. In a DR pair, complete it on both global clusters, so that the standby can reconcile the same workload clusters after a failover.

If the global cluster was installed on Bare Metal, also complete Prepare the global Cluster as a Management Cluster. Every global cluster installed on Bare Metal needs it, whether or not you plan Bare Metal workload clusters:

  • Complete it before you decommission the bootstrap cluster.
  • After handoff, reprovisioning a global node pulls baremetal-base-image from the global Registry, which this section populates.
  • Complete it before you create Bare Metal workload clusters.

This is a separate task from the provider steps in Installing the global Cluster. Those steps upload provider packages to the temporary bootstrap cluster to create the global cluster itself.

Prerequisites

Before installing the provider, ensure you have:

  • Access to the global cluster.
  • Access to Customer Portal for downloading plugins.

Install the Provider Plugins

Download the packages

The bare-metal workflow requires two cluster plugins. Download both from the Customer Portal. For 4.5, they are listed under Common ACP Extensions; see Download.

  1. Alauda Container Platform Cluster Bootstrap Provider
  2. Alauda Container Platform Infrastructure Provider for Bare Metal (umbrella chart that ships the cluster-api-provider-baremetal-manager and elemental-operator subcharts together)

Upload the packages

Upload both packages to the platform with violet push. For the command and its parameters, refer to Upload Packages.

Install the cluster plugins

Install both cluster plugins on the global cluster. For the procedure, refer to Cluster Plugin.

If the global cluster was installed on Bare Metal, set the following values when you install the Infrastructure Provider for Bare Metal. Determine them before you install:

  • elemental.tls.caCertSecretKey: the key found in dex.tls; see Point the provider at the platform certificate that actually exists.
  • In a DR pair, elemental.systemAgent.splitAuthEnabled: true on both sides, and elemental.systemAgent.sharedAuthReadOnly: false on the active cluster and true on the standby. Each global cluster keeps its own values; DR synchronization does not copy the provider's ModuleInfo.

Install the Infrastructure Provider for Bare Metal with YAML as described in Installing via YAML, and put these values in spec.valuesOverride of its ModuleInfo; the Web Console install form has no fields for them:

apiVersion: cluster.alauda.io/v1alpha1
kind: ModuleInfo
metadata:
  labels:
    cpaas.io/cluster-name: global
    cpaas.io/module-name: cluster-api-provider-baremetal
    cpaas.io/module-type: plugin
  name: global-temporary-name
spec:
  config: {}
  version: <provider-plugin-version>
  valuesOverride:
    acp/chart-cluster-api-provider-baremetal:
      elemental:
        tls:
          caCertSecretKey: <key-found-in-dex.tls>
        systemAgent:                  # DR pair only
          splitAuthEnabled: true
          sharedAuthReadOnly: false   # true on the standby

If the plugin is already installed, add the same valuesOverride to its existing ModuleInfo: find it with kubectl get moduleinfo -l cpaas.io/cluster-name=global,cpaas.io/module-name=cluster-api-provider-baremetal, then run kubectl edit moduleinfo <name>. Do not edit the provider's AppRelease: the platform regenerates it from the ModuleInfo, so the change is lost.

The umbrella chart installs both the bare-metal provider manager and elemental-operator in one step. It also creates the elemental-image-catalog ConfigMap, but with no entries, and the package contains no Alauda OS image. Before you create a cluster, import the Bare Metal OS images into the platform registry and add every Kubernetes version you deploy to the catalog; see OS Images Imported and Image Catalog Populated.

Verify the installation

After installing the plugins, verify that the controllers and CRDs are present:

# Provider manager + elemental-operator should both be Running
kubectl -n cpaas-system get pods | grep -E 'baremetal|elemental'

# Bare-metal CRDs
kubectl get crd | grep -E '^(baremetalclusters|baremetalmachines|baremetalmachinetemplates|machineinventorypools)\.infrastructure\.cluster\.x-k8s\.io$'

# Elemental CRDs (shipped by the elemental subchart)
kubectl get crd | grep -E '^(machineinventories|machineregistrations|seedimages)\.elemental\.cattle\.io$'

# Image catalog ConfigMap
kubectl -n cpaas-system get configmap elemental-image-catalog

Expected output includes:

  • baremetalclusters.infrastructure.cluster.x-k8s.io
  • baremetalmachines.infrastructure.cluster.x-k8s.io
  • baremetalmachinetemplates.infrastructure.cluster.x-k8s.io
  • machineinventorypools.infrastructure.cluster.x-k8s.io
  • machineinventories.elemental.cattle.io
  • machineregistrations.elemental.cattle.io
  • seedimages.elemental.cattle.io

Right after installation elemental-image-catalog has no data entries. After you add the Kubernetes versions you intend to deploy, confirm them:

kubectl -n cpaas-system get configmap elemental-image-catalog -o yaml

Every Machine.spec.version used by a cluster — both at creation time and at upgrade time — must appear as a key in this ConfigMap. A missing key leaves the BaremetalMachine in Failed with Reason=ImageCatalogMiss.

Prepare the global Cluster as a Management Cluster

Bare Metal only

This section applies to a global cluster installed on Bare Metal.

Installing the global Cluster creates the global cluster itself. Creating Bare Metal workload clusters afterwards is a separate concern: the global cluster then acts as the Cluster API management cluster, and it needs provider components and artifacts that the bootstrap preparation did not put there. Complete this section on both global clusters of a DR pair — after a failover the standby becomes the active management cluster and must be able to reconcile the same workload clusters.

Importing the Cluster API resources during installation only creates the CRDs. It does not install the Bare Metal provider or the Cluster Bootstrap Provider on the global cluster.

Set the values this section uses. Run it once per global cluster, with GLOBAL_KUBECONFIG pointing at the cluster you are preparing. OS_IMAGE_TAG and K8S_VERSION are the values used in Step 3 and Step 1 of the global installation.

export GLOBAL_KUBECONFIG="<path-to-this-global-kubeconfig>"
# Tag of the Bare Metal Alauda OS images imported in Step 3 of the global installation.
export OS_IMAGE_TAG="<os-image-tag>"
# K8S_VERSION from Step 1 of the global installation.
export K8S_VERSION="<target-kubernetes-version>"

Read the Registry address and password of the cluster you are preparing from its own ProductBase and cpaas-system/registry-admin Secret:

GLOBAL_REGISTRY_ADDRESS="$(kubectl --kubeconfig "${GLOBAL_KUBECONFIG}" \
  get productbase.product.alauda.io base -o jsonpath='{.spec.registry.address}')"
GLOBAL_REGISTRY_PASSWORD="$(kubectl --kubeconfig "${GLOBAL_KUBECONFIG}" -n cpaas-system \
  get secret registry-admin -o jsonpath='{.data.password}' | base64 -d)"

Point the provider at the platform certificate that actually exists

The Bare Metal provider mounts a CA bundle for platformUrl from elemental.tls.caCertSecretName / caCertSecretKey, which default to dex.tls and ca.crt. Those defaults assume a cert-manager-issued dex.tls. On the global cluster dex.tls comes from the installer's console.cert flow instead, and a thirdParty certificate produces a Secret with only tls.crt and tls.key. With the default key the operator never starts:

MountVolume.SetUp failed for volume "elemental-ca-cert":
  references non-existent secret key: ca.crt

Check which keys the Secret actually has and set caCertSecretKey accordingly in the provider's ModuleInfo, as described in Install the cluster plugins. For a self-signed platform certificate the certificate is its own CA, so tls.crt is the correct key:

kubectl --kubeconfig "${GLOBAL_KUBECONFIG}" -n cpaas-system \
  get secret dex.tls -o jsonpath='{.data}' | jq -r 'keys | join(",")'

Install the Cluster API providers on the global cluster

Upload the same Bare Metal and Cluster Bootstrap Provider packages you used for the bootstrap cluster to this global cluster, then install both plugins as described in Install the Provider Plugins. For the standby global cluster of a DR pair, upload the packages to the standby as described in Upload Packages.

When you install the Bare Metal provider, set caCertSecretKey to the key you found in the previous step. In a DR pair, also set the DR fields to the same values as on that side's bootstrap release: elemental.systemAgent.splitAuthEnabled: true on both sides, sharedAuthReadOnly: false on the active cluster and true on the standby. Set only these values, in spec.valuesOverride of the provider's ModuleInfo, as described in Install the cluster plugins. This global cluster does not inherit the bootstrap release values; do not copy the other bootstrap values, such as handoffHook.*.

Verify that the manager and elemental-operator are running on this global cluster before continuing:

kubectl --kubeconfig "${GLOBAL_KUBECONFIG}" -n cpaas-system get deploy \
  cluster-api-provider-baremetal-manager elemental-operator

Upload the base image to the global Registry

Workload SeedImage builds run on the global cluster and pull the base ISO from the Registry recorded in ProductBase.spec.registry.address. After handoff, reprovisioning a global node also pulls baremetal-base-image from that Registry, because the installer rewrites the global cluster's cpaas.io/registry-address annotation to it. The images imported in Step 3 live in the bootstrap Registry only, so the ISO build fails with MANIFEST_UNKNOWN until you push both of them to the global Registry. On the bootstrap node, push them from the bare-metal-os containerd namespace. --skip-verify requires --local:

for repo in baremetal-base-image baremetal-base-image-iso; do
  ctr -n bare-metal-os images push --local --skip-verify \
    -u "admin:${GLOBAL_REGISTRY_PASSWORD}" \
    "${GLOBAL_REGISTRY_ADDRESS}/tkestack/${repo}:${OS_IMAGE_TAG}" "${repo}:${OS_IMAGE_TAG}"
  curl -sk -u "admin:${GLOBAL_REGISTRY_PASSWORD}" \
    "https://${GLOBAL_REGISTRY_ADDRESS}/v2/tkestack/${repo}/tags/list"
done

Each response must list ${OS_IMAGE_TAG}. After that, remove the local copies with ctr -n bare-metal-os images rm "baremetal-base-image:${OS_IMAGE_TAG}" "baremetal-base-image-iso:${OS_IMAGE_TAG}". If the images are no longer on the bootstrap node, import them from the OS archive instead, as described in OS Images Imported and Image Catalog Populated.

Create the elemental image catalog

The provider maps a Kubernetes version to an elemental upgrade image through a ConfigMap located by --image-catalog-namespace and --image-catalog-name, which default to cpaas-system and elemental-image-catalog. The provider chart creates this ConfigMap with no version entries, and the global cluster does not inherit the entry you set on the bootstrap release. Until you add an entry, the first BaremetalMachine of a workload cluster fails immediately:

ImageResolved=False  ImageCatalogMiss:
  no elemental upgrade image mapped for Kubernetes version "<version>"

Add one entry per Kubernetes version that this global cluster manages, including ${K8S_VERSION} for its own nodes. Patch the existing ConfigMap rather than replacing it, so that entries added earlier are kept:

kubectl --kubeconfig "${GLOBAL_KUBECONFIG}" -n cpaas-system \
  patch configmap elemental-image-catalog --type merge \
  -p "{\"data\":{\"${K8S_VERSION}\":\"${GLOBAL_REGISTRY_ADDRESS}/tkestack/baremetal-base-image:${OS_IMAGE_TAG}\"}}"

kubectl --kubeconfig "${GLOBAL_KUBECONFIG}" -n cpaas-system \
  get configmap elemental-image-catalog -o jsonpath='{.data}'
ImageCatalogMiss does not recover on its own

A BaremetalMachine that hit ImageCatalogMiss stays Failed after you fix the catalog. Re-reconciling the object and restarting the provider both leave it unchanged; the reconciler deliberately treats a missing mapping as terminal rather than falling back to a default image. Delete the Machine so that its owner, KubeadmControlPlane or the MachineSet, recreates it. Populate the catalog before you apply the first workload cluster manifest to avoid this entirely.

Workload registrations use the platform domain

A workload MachineRegistration must not carry the baremetal.cluster.io/system-agent-auth-scope: global annotation. Its registration URL resolves to https://<platform-domain>/..., and the resulting MachineInventory is annotated with system-agent-auth-scope: shared. That shared identity, together with the shared ServiceAccount signing key, is what lets a workload host keep reporting through the platform domain after a failover.

Next Steps

After installing the provider, you can proceed to: