Provider Onboarding Tutorial¶
This page walks you through bringing a Provider CR online end-to-end on a VirtRigaud v0.3.8 cluster. It uses the vSphere provider as the running example because that is the most common starting point; the same shape applies to libvirt and Proxmox with provider-type-specific tweaks called out inline.
If you are looking to build a new provider (a fresh hypervisor like Firecracker, Cloud-Hypervisor, or KubeVirt), that material lives in the developer-facing provider development guide — this page is for operators wiring up an existing provider against a real hypervisor.
Prerequisites¶
- A Kubernetes cluster with VirtRigaud v0.3.8 installed. If you do not have one yet, follow the Helm-only install guide.
kubectlconfigured against the cluster.- Cluster admin (or namespace admin in
virtrigaud-system) — you need to createSecrets,Providers, and at least oneVirtualMachine. - Access to the hypervisor you are wiring up (vCenter / libvirt host / PVE cluster) with credentials of an account that can lifecycle VMs.
Step 1 — Install VirtRigaud (skip if already installed)¶
helm repo add virtrigaud https://projectbeskar.github.io/virtrigaud
helm repo update
helm install virtrigaud virtrigaud/virtrigaud \
--version 0.3.11 \
--namespace virtrigaud-system \
--create-namespace
Verify the manager is healthy:
kubectl get pods -n virtrigaud-system
# NAME READY STATUS RESTARTS AGE
# virtrigaud-manager-7d4b8c9d5b-xyz12 1/1 Running 0 1m
/metrics should already expose the v0.3.8 baseline. Port-forward and confirm:
kubectl port-forward -n virtrigaud-system svc/virtrigaud-manager 8081:8081 &
curl -s http://localhost:8081/metrics | grep ^virtrigaud_build_info
# virtrigaud_build_info{component="manager", ...version="v0.3.8"} 1
If you see virtrigaud_build_info{version="v0.3.8"} 1, the manager is up and the metric surface is wired. See Observability for the full metric catalog.
Step 2 — Create the credentials Secret¶
Each hypervisor has a different set of Secret keys. The keys are read as files mounted at /etc/virtrigaud/credentials inside the provider pod, so the key names matter.
Apply the Secret:
Step 3 — Create the Provider CR¶
The Provider CR tells VirtRigaud how to launch the provider pod and how to reach the hypervisor.
apiVersion: infra.virtrigaud.io/v1beta1
kind: Provider
metadata:
name: vsphere-lab
namespace: virtrigaud-system
spec:
type: vsphere
endpoint: https://vcenter.example.com/sdk
credentialSecretRef:
name: vsphere-credentials
insecureSkipVerify: false # set true ONLY in dev
runtime:
mode: Remote
image: "ghcr.io/projectbeskar/virtrigaud/provider-vsphere:v0.3.11"
service:
port: 9443
apiVersion: infra.virtrigaud.io/v1beta1
kind: Provider
metadata:
name: libvirt-lab
namespace: virtrigaud-system
spec:
type: libvirt
endpoint: "qemu+ssh://virtrigaud@libvirt-host.example.com/system"
credentialSecretRef:
name: libvirt-credentials
runtime:
mode: Remote
image: "ghcr.io/projectbeskar/virtrigaud/provider-libvirt:v0.3.11"
service:
port: 9090
apiVersion: infra.virtrigaud.io/v1beta1
kind: Provider
metadata:
name: proxmox-cluster
namespace: virtrigaud-system
spec:
type: proxmox
endpoint: "https://pve.example.com:8006"
credentialSecretRef:
name: proxmox-credentials
insecureSkipVerify: false
runtime:
mode: Remote
image: "ghcr.io/projectbeskar/virtrigaud/provider-proxmox:v0.3.11"
service:
port: 9443
Apply:
Watch the provider pod come up:
A successful state looks like:
Verify the Provider CR status:
kubectl get provider vsphere-lab -n virtrigaud-system -o jsonpath='{.status.conditions[?(@.type=="Ready")]}'
Expect status: "True", reason Connected.
Step 4 — Verify on /metrics¶
This is the part the v0.3.6 observability surface unlocks. After the provider pod has come up and the manager has dialed it, several metric families should populate immediately:
curl -s http://localhost:8081/metrics | grep -E '^(virtrigaud_circuit_breaker_state|virtrigaud_provider_tasks_inflight|virtrigaud_build_info)' | head
Expected (your provider name will differ):
virtrigaud_build_info{component="manager", ...version="v0.3.8"} 1
virtrigaud_circuit_breaker_state{provider_type="vsphere", provider="vsphere-lab"} 0
virtrigaud_provider_tasks_inflight{provider_type="vsphere", provider="vsphere-lab"} 0
What each tells you:
| Metric | Meaning |
|---|---|
virtrigaud_build_info | Manager booted and registered metrics. |
virtrigaud_circuit_breaker_state{provider="..."} 0 | The G6 CircuitBreaker around this Provider's gRPC is Closed (healthy). A value of 2 (Open) means the manager has fast-failed enough RPCs to stop talking to this provider — that is the signal to investigate the hypervisor side. |
virtrigaud_provider_tasks_inflight 0 | No async tasks in flight. Will rise above 0 as soon as you start creating VMs that require server-side task completion. |
The _total counter families (virtrigaud_provider_rpc_requests_total, virtrigaud_vm_operations_total, virtrigaud_circuit_breaker_failures_total) appear after the first relevant event — RPC, VM operation, or breaker trip. See Observability for the full catalog.
Breaker open on first dial?
If virtrigaud_circuit_breaker_state is 2 immediately after install, the manager could not reach the provider pod / the provider pod could not reach the hypervisor. Check the provider pod's logs (kubectl logs -n virtrigaud-system <provider-pod>) and the Provider CR's status.conditions. The libvirt provider in particular is sensitive to SSH-host hygiene — see libvirt troubleshooting.
Step 5 — Create a minimal VMClass and VMImage¶
Both CRs are referenced by every VirtualMachine. Define them once per common workload shape.
apiVersion: infra.virtrigaud.io/v1beta1
kind: VMClass
metadata:
name: small
namespace: virtrigaud-system
spec:
cpu: 2
memory: "4Gi"
firmware: UEFI
diskDefaults:
type: thin # use qcow2 for libvirt/proxmox
size: "20Gi"
---
apiVersion: infra.virtrigaud.io/v1beta1
kind: VMImage
metadata:
name: ubuntu-22-04
namespace: virtrigaud-system
spec:
source:
template: "ubuntu-22.04-template" # vSphere template name
guestOS: "ubuntu64Guest"
(For libvirt / proxmox the source block looks different — see the respective provider pages.)
Step 6 — Create your first VirtualMachine¶
apiVersion: infra.virtrigaud.io/v1beta1
kind: VMNetworkAttachment
metadata:
name: lan
namespace: virtrigaud-system
spec:
network:
vsphere:
portgroup: "VM Network"
ipAllocation:
type: DHCP
---
apiVersion: infra.virtrigaud.io/v1beta1
kind: VirtualMachine
metadata:
name: hello-world
namespace: virtrigaud-system
spec:
providerRef:
name: vsphere-lab
classRef:
name: small
imageRef:
name: ubuntu-22-04
powerState: On
networks:
- name: lan
networkRef:
name: lan
userData:
cloudInit:
inline: |
#cloud-config
hostname: hello-world
users:
- name: ubuntu
sudo: ALL=(ALL) NOPASSWD:ALL
ssh_authorized_keys:
- "ssh-ed25519 AAAA..."
packages:
- open-vm-tools # use qemu-guest-agent on libvirt/proxmox
runcmd:
- systemctl enable --now open-vm-tools
Apply and watch:
Expected progression:
NAME PHASE AGE POWER IP
hello-world Pending 5s
hello-world Creating 10s
hello-world Running 45s On 192.168.100.50
Step 7 — Confirm everything end-to-end¶
After the VM lands in Running, several things should now be observable:
# 1. The VM has an IP (via cloud-init or guest tools)
kubectl get vm hello-world -n virtrigaud-system -o jsonpath='{.status.ips}'
# 2. The console URL is populated
kubectl get vm hello-world -n virtrigaud-system -o jsonpath='{.status.consoleURL}'
# 3. The Provider's CircuitBreaker is still closed
curl -s http://localhost:8081/metrics | grep 'circuit_breaker_state.*vsphere-lab'
# virtrigaud_circuit_breaker_state{provider_type="vsphere", provider="vsphere-lab"} 0
# 4. RPC counter shows real traffic
curl -s http://localhost:8081/metrics | grep virtrigaud_provider_rpc_requests_total | head
# virtrigaud_provider_rpc_requests_total{method="Create", provider="vsphere-lab", ...} 1
# virtrigaud_provider_rpc_requests_total{method="Describe", provider="vsphere-lab", ...} 12
# 5. VM operations counter populated (G7.1)
curl -s http://localhost:8081/metrics | grep virtrigaud_vm_operations_total | head
# virtrigaud_vm_operations_total{operation="create", provider="vsphere-lab"} 1
# virtrigaud_vm_operations_total{operation="describe", provider="vsphere-lab"} 12
# 6. IP-discovery histogram populated (G7.2)
curl -s http://localhost:8081/metrics | grep virtrigaud_ip_discovery_duration_seconds_count
# virtrigaud_ip_discovery_duration_seconds_count{provider="vsphere-lab"} 1
SSH into the guest with the IP from step 1 to verify the cloud-init applied:
Step 8 — Clean up¶
kubectl delete vm hello-world -n virtrigaud-system
kubectl delete vmnetworkattachment lan -n virtrigaud-system
kubectl delete vmimage ubuntu-22-04 -n virtrigaud-system
kubectl delete vmclass small -n virtrigaud-system
kubectl delete provider vsphere-lab -n virtrigaud-system
kubectl delete secret vsphere-credentials -n virtrigaud-system
The provider pod is deleted by the controller when the Provider CR is removed (it is an owned resource).
What to read next¶
- The capability matrix — what each provider can and cannot do, including the v0.3.8 capability-negotiation surfacing (
Provider.status.reportedCapabilities) and the corrected libvirt clone / image-import cells. - The deep-dive pages for the provider you are operating:
- vSphere — guestinfo cloud-init, SCSI controller specs, StoragePod selection.
- Libvirt — virsh-over-SSH internals, disk export, why clone/image-import are Unimplemented, the I1 / SSH-host narrative.
- Proxmox — token vs password auth, memory snapshots, ConsoleURL nuance.
- Operations — Resilience — the v0.3.6 CircuitBreaker, including how to read the metrics.
- Operations — Observability — the full metric catalog and example Prometheus alerts.
- Generated CRD reference — every field on every CRD.
Building a new provider (SDK path)¶
If you want to add a hypervisor that does not exist in the tree yet (KubeVirt, Firecracker, Cloud-Hypervisor, direct QEMU, ...) the workflow is different:
- Read the provider development guide and the provider gRPC contract.
- Use the in-tree mock provider (
internal/providers/mock/) as the minimum-implementation reference. - Scaffold a new provider with
vrtg-provider init <name>(or copy the proxmox layout, which has the cleanest separation between the gRPC server and the REST client). - Register the new capability set via the SDK builder (
sdk/provider/capabilities/). - Run the conformance suite (
go test ./test/conformance/...) against your provider pod.
That work is outside the scope of this operator onboarding page; see the developer documentation referenced above.