Table of Contents

Installing Kubevirt

Using a Helm TGZ

# Rebuild TGZ with your new path change
helm package /Users/mcalero/working-folder/helm/kubevirt --destination /Users/mcalero/working-folder/helm
helm upgrade --install kubevirt /Users/mcalero/working-folder/helm/kubevirt-0.1.0.tgz \
  -n default \
  --create-namespace \
  --set localStorage.enabled=true \
  --set localStorage.zededaPatch.enabled=true

Install Manually

# 1. Get the latest version string
export VERSION=$(curl -s https://api.github.com/repos/kubevirt/kubevirt/releases/latest | grep tag_name | cut -d '"' -f 4)
# 2. Deploy the Operator
kubectl create -f "https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-operator.yaml"
# 3. Deploy the KubeVirt Custom Resource (this starts the actual pods)
kubectl create -f "https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-cr.yaml"
kubectl get pods -n kubevirt -w
NAME                                                              READY   STATUS    RESTARTS   AGE
kubevirt-cb56b74f311a9b7b360559903dba10b3cd6ec516-job4h7m7fpv97   1/1     Running   0          20s
virt-operator-584bd468cd-fbsxn                                    1/1     Running   0          39s
virt-operator-584bd468cd-fvprb                                    1/1     Running   0          39s

Install CDI

export VERSION=$(curl -s https://api.github.com/repos/kubevirt/containerized-data-importer/releases/latest | grep tag_name | cut -d '"' -f 4)
kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/$VERSION/cdi-operator.yaml
kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/$VERSION/cdi-cr.yaml

Local Storage Provisioner

If you are deploying on a 3-node cluster with no shared store, you need the Local Storage Provisioner:

kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml

What this does:

Configure for ZEDEDA (''/persist/'')

kubectl patch configmap local-path-config -n local-path-storage --type merge -p '{"data":{"config.json":"{\n  \"nodePathMap\": [\n    {\n      \"node\": \"DEFAULT_PATH_FOR_NON_LISTED_NODES\",\n      \"paths\": [\"/persist/local-path-storage\"]\n    }\n  ]\n}"}}'

To check if validation failed:

kubectl logs -l cdi.kubevirt.io=importer

Deploying VMs

Console Access

virtctl console ubuntu-noble -n default

Monitor VM Coming Up

kubectl get vmi -w
kubectl get dv -w
 
# 1) NetworkAttachmentDefinition exists
kubectl get net-attach-def -n default
kubectl describe net-attach-def eth1-macvlan -n default
 
# 2) VM lifecycle
kubectl get vm -n default -w
kubectl get vmi -n default -w
 
# 3) Import/storage progress
kubectl get dv -n default -w
kubectl get pvc -n default -w
 
# 4) See real-time errors/events
kubectl get events -n default --sort-by=.lastTimestamp -w

Confirm NIC/IPs Once VM Is Up

kubectl get vmi ubuntu-noble -n default -o jsonpath='{range .status.interfaces[*]}{.name}{" ip="}{.ipAddress}{"\n"}{end}'