Skip to content

Install the provider

Installing CAPVCO means teaching clusterctl where to find it, then running clusterctl init against your management cluster. This installs Cluster API’s core + kubeadm providers and CAPVCO’s CRDs and controller.

You do this once per management cluster.

1. Register the provider with clusterctl

CAPVCO is hosted on GitLab. clusterctl consumes a GitLab provider from the project's Package Registry (not the human release page), over the gitlab.whitesky.cloud host — so add a providers: entry pointing at the release's infrastructure-components.yaml in the registry to ~/.cluster-api/clusterctl.yaml (create the file if it doesn't exist):

~/.cluster-api/clusterctl.yaml
providers:
  - name: vco
    type: InfrastructureProvider
    url: "https://gitlab.whitesky.cloud/api/v4/projects/730/packages/generic/capvco/v0.6.1/infrastructure-components.yaml"

v0.6.1 is the latest published release (filled in automatically when these docs are built). To pin a specific version, put its tag in that path segment — e.g. …/packages/generic/capvco/vX.Y.Z/infrastructure-components.yaml. metadata.yaml and the cluster templates live in the same package, so clusterctl fetches everything it needs from there.

Use a clusterctl that speaks v1beta2

CAPVCO targets the v1beta2 Cluster API contract, so you need clusterctl v1.14.x (matching the CAPI the provider is built on). An older one fails with "current version of clusterctl is only compatible with v1beta1 providers, detected v1beta2", and anything before v1.13.6 cannot bootstrap Kubernetes v1.37 at all — which CAPVCO ships node images for. See Prerequisites → tools to upgrade.

2. Provide the instance URLs

The manager reads the two instance URLs from its environment, sourced from a Kubernetes Secret named capvco-credentials in its namespace (capvco-system). Create that Secret before the manager starts:

kubectl create namespace capvco-system
kubectl -n capvco-system create secret generic capvco-credentials \
  --from-literal=portalUrl="https://<your-whitesky.cloud-portal>" \
  --from-literal=iamRefreshUrl="https://<your-iam-host>/v1/oauth/jwt/refresh"

Use your portal's actual URLs — they're arbitrary per instance (there's no fixed console./iam. prefix, and the IAM host is not derived from the portal host). A template is in config/manager/credentials-secret.example.yaml.

This Secret is instance config, not a credential

It carries only the two URLs. The manager holds no standing whitesky.cloud credential — every backend operation uses the per-cluster credential (JWT + customer id) from each cluster's own Secret (see the first-cluster step), never a manager-wide one.

Order

clusterctl init (next step) creates the capvco-system namespace and the manager itself. If you init first, the manager pod stays pending/crash-looping until this Secret exists — creating it up front (as above) avoids that.

3. Initialise

clusterctl init --infrastructure vco

This installs, into your management cluster:

  • Cluster API core, bootstrap (kubeadm) and control-plane (kubeadm) controllers
  • CAPVCO’s CRDs (vcoclusters, vcomachines, and the two *templates)
  • the CAPVCO manager in the capvco-system namespace

Expected tail of the output:

Your management cluster has been initialized successfully!

You can now create your first workload cluster by running the following:
  clusterctl generate cluster [name] --kubernetes-version [version] | kubectl apply -f -

4. Install the CNI add-on

Cluster API does not install a pod network for you — and without one, every workload node stays NotReady forever (cni plugin not initialized). CAPVCO ships the CNI as a ClusterResourceSet: apply it once to the management cluster and every cluster you create afterwards installs Calico automatically. The templates label each Cluster with cni: calico, and this ClusterResourceSet targets that label, so there's nothing to run per-cluster.

kubectl apply -f https://gitlab.whitesky.cloud/api/v4/projects/730/packages/generic/capvco/v0.6.1/cni.yaml

This creates the capvco-cni-calico ClusterResourceSet and its Calico ConfigMap in the default namespace — where your workload Cluster objects live. If you create clusters in another namespace, apply it there too with -n <namespace>.

The same CNI bundle covers geo

There's a single CNI bundle. Its Calico is tuned to the cross-site tunnel MTU (veth_mtu: 1350), so geo-redundant clusters need nothing extra — and any cluster can later expand into more locations without a CNI change. See Geo-redundant clusters.

If you changed POD_CIDR, the CNI pool must match

The bundled Calico is pinned to the templates' default POD_CIDR (10.244.0.0/16). If you override POD_CIDR when generating a cluster, the CNI pool must match — otherwise pods get addresses from the wrong range. Most users never change it.

Storage (CSI) is a separate add-on

The base template also labels clusters csi: vco. Persistent volumes need the CSI add-on, which is published in the same release as csi.yaml — but its driver image lives on your instance's (white-label) registry, so it needs one substitution at apply time. Set it up when you need PVCs — see Persistent storage. A cluster reaches Ready without it.

5. Verify

kubectl get providers -A                # installed providers + versions (infrastructure-vco)
kubectl -n capvco-system get pods       # the manager pod should be Running/Ready
kubectl get crds | grep vco             # vcoclusters / vcomachines / *templates present
kubectl get clusterresourceset          # capvco-cni-calico present (the CNI add-on from step 4)

You should see infrastructure-vco in the providers list, the manager pod 1/1 Running, the four CRDs, and the capvco-cni-calico ClusterResourceSet. (There is no clusterctl describe provider command; for a fuller view of installed providers, versions and the contract, use clusterctl upgrade plan.)

ClusterResourceSet is enabled by default

The CNI add-on relies on Cluster API's ClusterResourceSet controller, which is on by default in the clusterctl version these docs target (v1.14.x) — no feature gate to enable. If kubectl get clusterresourceset errors with the server doesn't have a resource type, you're on a build with it disabled; re-run clusterctl init with EXP_CLUSTER_RESOURCE_SET=true exported.

Developing CAPVCO itself?

Instead of installing the released image, you can run the manager out-of-cluster against your kind management cluster — see Contributing. Everything else in these docs is identical.

Upgrading later

Bump the provider url version in clusterctl.yaml, then:

clusterctl upgrade apply --infrastructure vco:vX.Y.Z

Air-gapped installs

If the management cluster has no internet egress, mirror the CAPVCO manager image and infrastructure-components.yaml (plus the core/bootstrap/control-plane images) into a private registry and point clusterctl at the mirrored components. For workload clusters with no egress, see the air-gapped guide.

Installing with GitOps instead of clusterctl

CAPVCO installs perfectly well from infrastructure-components.yaml through Flux, Argo CD, Sylva or plain Kustomize. Two things catch people out when they do, both reported from a real Sylva integration.

clusterctl move refuses to run against a GitOps-installed provider

clusterctl init registers Provider inventory records in the management cluster. Installing the same manifests through Flux or Argo does not — the inventory is a clusterctl-only concept. clusterctl move checks it and stops:

failed to check providers in target cluster:
  provider infrastructure-vco not found ... provider cluster-api not found

The controllers are running correctly; only the bookkeeping is absent. To pivot into a GitOps-installed cluster, register matching Provider records on the target first — one per provider, with the same version as the source inventory, in the namespace where each controller actually runs (CAPVCO's may not be capvco-system if your GitOps layer chose another).

Verify each deployed image tag matches the version you record. Registering an inventory that disagrees with what is deployed turns a clear refusal into a silent mismatch.

Overriding the manager image needs the post-transformation name

infrastructure-components.yaml has already had its Kustomize image transformations applied, so the container is no longer named controller — it is the full ghub.gig.tech/whitesky-oss/cluster-api-provider-vco. A Kustomize images: override written against controller matches nothing, silently leaves whatever tag was there, and surfaces only as:

ErrImagePull: ghub.gig.tech/whitesky-oss/cluster-api-provider-vco:dev not found

Match the full name and set newTag to the release you want.


Provider up and healthy? → Your first cluster.