|
| 1 | +# VirtualMachineStuckInUnhealthyState |
| 2 | + |
| 3 | +## Meaning |
| 4 | + |
| 5 | +This alert fires when a VirtualMachine has been stuck in an unhealthy state |
| 6 | +for more than 10 minutes and does not have an associated VMI |
| 7 | +(VirtualMachineInstance). |
| 8 | + |
| 9 | +The alert indicates that a VirtualMachine is experiencing early-stage |
| 10 | +lifecycle issues before a VMI can be successfully created. |
| 11 | +This typically occurs during the initial phases of VM startup when KubeVirt |
| 12 | +is trying to provision resources, pull images, or schedule the workload. |
| 13 | + |
| 14 | +**Affected States:** |
| 15 | +- `Provisioning` - Resources (DataVolumes, PVCs) are being prepared |
| 16 | +- `Starting` - VM is attempting to start but no VMI exists yet |
| 17 | +- `Terminating` - VM is being deleted but without an active VMI |
| 18 | +- `Error` states - Various scheduling, image, or resource allocation errors |
| 19 | + |
| 20 | +## Impact |
| 21 | + |
| 22 | +- **Severity:** Warning |
| 23 | +- **User Impact:** VMs cannot start or are stuck in error states |
| 24 | +- **Business Impact:** Workloads cannot be deployed, affecting application |
| 25 | + availability |
| 26 | + |
| 27 | +## Possible Causes |
| 28 | + |
| 29 | +### Resource-Related Issues |
| 30 | +- **Insufficient cluster resources** (CPU, memory, storage) |
| 31 | +- **Missing or misconfigured storage classes** |
| 32 | +- **PVC provisioning failures** |
| 33 | +- **DataVolume creation/import failures** |
| 34 | + |
| 35 | +### Image and Registry Issues |
| 36 | +- **Container image pull failures** for containerDisk volumes |
| 37 | +- **Registry authentication problems** |
| 38 | +- **Network connectivity issues to image registries** |
| 39 | +- **Missing or corrupted VM disk images** |
| 40 | + |
| 41 | +### Scheduling and Node Issues |
| 42 | +- **No schedulable nodes available** (all nodes cordoned/unschedulable) |
| 43 | +- **Insufficient resources** like KVM/GPU on available nodes or a |
| 44 | + mismatch between requested and available CPU models |
| 45 | +- **Node selector constraints** cannot be satisfied |
| 46 | +- **Taints and tolerations** preventing scheduling |
| 47 | + |
| 48 | +### Configuration Issues |
| 49 | +- **Invalid VM specifications** (malformed YAML, unsupported |
| 50 | + features) |
| 51 | +- **Missing required Secrets or ConfigMaps** |
| 52 | +- **Incorrect resource requests/limits** |
| 53 | +- **Network configuration errors** |
| 54 | + |
| 55 | +## Diagnosis |
| 56 | + |
| 57 | +### 1. Check VM Status and Events |
| 58 | +```bash |
| 59 | +# Get VM details and status |
| 60 | +kubectl get vm <vm-name> -n <namespace> -o yaml |
| 61 | + |
| 62 | +# Check VM events for error messages |
| 63 | +kubectl describe vm <vm-name> -n <namespace> |
| 64 | + |
| 65 | +# Look for related events in the namespace |
| 66 | +kubectl get events -n <namespace> --sort-by='.lastTimestamp' |
| 67 | +``` |
| 68 | + |
| 69 | +### 2. Verify Resource Availability |
| 70 | +```bash |
| 71 | +# Check node resources and schedulability |
| 72 | +kubectl get nodes -o wide |
| 73 | +kubectl describe nodes |
| 74 | + |
| 75 | +# Check storage classes and provisioners |
| 76 | +kubectl get storageclass |
| 77 | +kubectl get pv,pvc -n <namespace> |
| 78 | + |
| 79 | +# For DataVolumes (if using) |
| 80 | +kubectl get datavolume -n <namespace> |
| 81 | +kubectl describe datavolume <dv-name> -n <namespace> |
| 82 | +``` |
| 83 | + |
| 84 | +### 3. Check Image Availability (for containerDisk) |
| 85 | +```bash |
| 86 | +# If using containerDisk, verify image accessibility from the affected node |
| 87 | +# Start a debug session on the node hosting the VM (or a representative node) |
| 88 | +kubectl debug node/<node-name> -it --image=busybox |
| 89 | + |
| 90 | +# Inside the debug pod, check which container runtime is used |
| 91 | +ps aux | grep -E "(containerd|dockerd|crio)" |
| 92 | + |
| 93 | +# For CRI-O/containerd clusters use crictl to pull the image |
| 94 | +crictl pull <vm-disk-image> |
| 95 | + |
| 96 | +# For Docker-based clusters (less common) |
| 97 | +docker pull <vm-disk-image> |
| 98 | + |
| 99 | +# Exit the debug session when done |
| 100 | +exit |
| 101 | + |
| 102 | +# Check image pull secrets if required |
| 103 | +kubectl get secrets -n <namespace> |
| 104 | +``` |
| 105 | + |
| 106 | +### 4. Verify KubeVirt Configuration |
| 107 | +```bash |
| 108 | +# Discover the KubeVirt installation namespace |
| 109 | +export NAMESPACE="$(kubectl get kubevirt -A -o custom-columns="":.metadata.namespace)" |
| 110 | + |
| 111 | +# Check KubeVirt CR conditions (expect Available=True) |
| 112 | +kubectl get kubevirt -n "$NAMESPACE" \ |
| 113 | + -o jsonpath='{range .items[*].status.conditions[*]}{.type}={.status}{"\n"}{end}' |
| 114 | + |
| 115 | +# Or check a single CR named 'kubevirt' |
| 116 | +kubectl get kubevirt kubevirt -n "$NAMESPACE" \ |
| 117 | + -o jsonpath='{.status.conditions[?(@.type=="Available")].status}' |
| 118 | + |
| 119 | +# Verify virt-controller is running |
| 120 | +kubectl get pods -n "$NAMESPACE" \ |
| 121 | + -l kubevirt.io=virt-controller |
| 122 | + |
| 123 | +# Check virt-controller logs for errors |
| 124 | +# Replace <virt-controller-pod> with a pod name from the list above |
| 125 | +kubectl logs -n "$NAMESPACE" <virt-controller-pod> |
| 126 | + |
| 127 | +# Verify virt-handler is running |
| 128 | +kubectl get pods -n "$NAMESPACE" \ |
| 129 | + -l kubevirt.io=virt-handler -o wide |
| 130 | + |
| 131 | +# Check virt-handler logs for errors (daemonset uses per-node pods) |
| 132 | +# Replace <virt-handler-pod> with a pod name from the list above |
| 133 | +kubectl logs -n "$NAMESPACE" <virt-handler-pod> |
| 134 | +``` |
| 135 | + |
| 136 | +### 5. Review VM Specification |
| 137 | +Inspect the following details in the VM's spec to catch common |
| 138 | +misconfigurations: |
| 139 | + |
| 140 | +- Disks and volumes (in spec.template.spec.domain.devices and volumes): |
| 141 | + - A bootable disk is defined using bootOrder: 1 |
| 142 | + - Each disk name matches a volume name |
| 143 | + - Volume sources are valid: PVC, DataVolume, containerDisk, secret, or |
| 144 | + configMap |
| 145 | + |
| 146 | +- Resources (in spec.template.spec.domain.resources): |
| 147 | + - Resource requests and limits are set and do not exceed node capacity |
| 148 | + |
| 149 | +- Scheduling (in spec.template.spec): |
| 150 | + - nodeSelector, affinity, and tolerations are not overly restrictive |
| 151 | + |
| 152 | +- Image pull configuration (in spec.template.spec.imagePullSecrets): |
| 153 | + - imagePullSecrets are configured if using a private image registry |
| 154 | + |
| 155 | +- Power strategy (in spec.runStrategy or spec.running): |
| 156 | + - Only one of spec.runStrategy or spec.running is set, and it matches the |
| 157 | + desired behavior |
| 158 | + |
| 159 | +## Mitigation |
| 160 | + |
| 161 | +### Resource Issues |
| 162 | +1. **Scale cluster** if insufficient resources |
| 163 | +2. **Create missing storage classes** or configure default storage |
| 164 | +3. **Resolve PVC/DataVolume failures**: |
| 165 | + ```bash |
| 166 | + kubectl get pvc -n <namespace> |
| 167 | + kubectl describe pvc <pvc-name> -n <namespace> |
| 168 | + ``` |
| 169 | + |
| 170 | +### Image Issues |
| 171 | +1. **Verify image accessibility**: |
| 172 | + ```bash |
| 173 | + # Validate from the node |
| 174 | + kubectl debug node/<node-name> -it --image=busybox |
| 175 | + |
| 176 | + # Inside the debug pod, detect runtime and pull |
| 177 | + ps aux | grep -E "(containerd|dockerd|crio)" |
| 178 | + |
| 179 | + # For CRI-O/containerd clusters: |
| 180 | + crictl pull <image-name> |
| 181 | + |
| 182 | + # For Docker-based clusters (less common): |
| 183 | + docker pull <image-name> |
| 184 | + |
| 185 | + exit |
| 186 | + ``` |
| 187 | +2. **Configure image pull secrets** if needed: |
| 188 | + ```bash |
| 189 | + kubectl create secret docker-registry <secret-name> \ |
| 190 | + --docker-server=<registry-url> \ |
| 191 | + --docker-username=<username> \ |
| 192 | + --docker-password=<password> |
| 193 | + ``` |
| 194 | + |
| 195 | +### Scheduling Issues |
| 196 | +1. **Review VM scheduling constraints** and relax if too restrictive: |
| 197 | + - nodeSelector, affinity, and tolerations |
| 198 | + - Required CPU model, host devices, or features |
| 199 | + |
| 200 | +2. **Verify node taints and tolerations** allow scheduling: |
| 201 | + - Ensure the VM tolerates node taints that apply to target nodes |
| 202 | + |
| 203 | +3. **Ensure nodes have required capabilities**: |
| 204 | + - KVM availability, CPU features, GPU, SR-IOV, or storage access |
| 205 | + |
| 206 | +4. If nodes were intentionally cordoned for maintenance, **uncordon** when |
| 207 | + appropriate: |
| 208 | + ```bash |
| 209 | + kubectl uncordon <node-name> |
| 210 | + ``` |
| 211 | + |
| 212 | +### Configuration Issues Resolution |
| 213 | +1. **Fix VM specification errors** based on kubectl describe output: |
| 214 | + ```bash |
| 215 | + # Edit VM specification directly |
| 216 | + kubectl edit vm <vm-name> -n <namespace> |
| 217 | + |
| 218 | + # Or patch specific fields |
| 219 | + kubectl patch vm <vm-name> -n <namespace> --type='merge' \ |
| 220 | + -p='{"spec":{"template":{"spec":{"domain":{"resources": \ |
| 221 | + {"requests":{"memory":"2Gi"}}}}}}}' |
| 222 | + ``` |
| 223 | +2. **Create missing secrets/configmaps**: |
| 224 | + ```bash |
| 225 | + kubectl create secret generic <secret-name> \ |
| 226 | + --from-literal=key=value |
| 227 | + ``` |
| 228 | +3. **Adjust resource requests** if they exceed node capacity |
| 229 | + |
| 230 | +### Emergency Workarounds |
| 231 | +- **Restart the VM** to apply specification changes: |
| 232 | + ```bash |
| 233 | + # Restart the VM to pick up spec changes |
| 234 | + virtctl restart <vm-name> -n <namespace> |
| 235 | + ``` |
| 236 | +- **Scale down non-critical workloads** temporarily if resource |
| 237 | + constraints exist |
| 238 | +- **Change storage class** if PVC provisioning fails: |
| 239 | + ```bash |
| 240 | + # Check current storage class status |
| 241 | + kubectl get storageclass |
| 242 | + kubectl describe storageclass <current-storage-class> |
| 243 | + |
| 244 | + # Look for PVC provisioning errors |
| 245 | + kubectl describe pvc <pvc-name> -n <namespace> |
| 246 | + |
| 247 | + # If seeing "no volume provisioner" or similar errors, |
| 248 | + # specify a working storage class in VM spec: |
| 249 | + # spec.dataVolumeTemplates[].spec.pvc.storageClassName: |
| 250 | + # <working-class> |
| 251 | + ``` |
| 252 | + |
| 253 | +## Prevention |
| 254 | + |
| 255 | +1. **Resource Planning:** |
| 256 | + - Monitor cluster resource utilization |
| 257 | + - Set appropriate VM guest resources in the VM domain guest spec. |
| 258 | + - Plan storage capacity and provisioning |
| 259 | + |
| 260 | +2. **Image Management:** |
| 261 | + - Use local image registries where possible to reduce |
| 262 | + latency |
| 263 | + - Configure DataVolume import methods appropriately: |
| 264 | + * **Pod import method**: Images pulled to temporary pods (default) |
| 265 | + * **Node import method**: Images pulled directly to nodes |
| 266 | + (requires pre-pulling) |
| 267 | + - Pre-pull critical containerDisk images to nodes only if |
| 268 | + using node import method |
| 269 | + |
| 270 | +3. **Monitoring:** |
| 271 | + - Set up alerts for cluster resource exhaustion |
| 272 | + - Monitor storage provisioner health |
| 273 | + - Track VM startup success rates |
| 274 | + |
| 275 | +4. **Testing:** |
| 276 | + - Validate VM templates in development environments |
| 277 | + - Test VM deployments after cluster changes |
| 278 | + - Regularly verify image accessibility |
| 279 | + |
| 280 | +## Escalation |
| 281 | + |
| 282 | +Escalate to the cluster administrator if: |
| 283 | +- Multiple VMs affected simultaneously (possible cluster-wide |
| 284 | + issue) |
| 285 | +- Issue persists after following resolution steps |
| 286 | +- Suspected KubeVirt component malfunction |
| 287 | +- Unable to access system logs for further diagnosis |
| 288 | +- You don't have enough permissions to run the diagnosis and/or |
| 289 | + mitigation steps. |
| 290 | + |
| 291 | +## Related Alerts |
| 292 | + |
| 293 | +- `VirtControllerDown` - May indicate controller issues preventing |
| 294 | + VM processing |
| 295 | +- `LowKVMNodesCount` - Related to insufficient KVM-capable nodes |
| 296 | +- `KubeVirtNoAvailableNodesToRunVMs` - Indicates no nodes available |
| 297 | + for VM scheduling |
| 298 | + |
| 299 | +<!--DS: If you cannot resolve the issue, log in to the |
| 300 | +link:https://access.redhat.com[Customer Portal] and open a support |
| 301 | +case, attaching the artifacts gathered during the diagnosis |
| 302 | +procedure.--> |
| 303 | +<!--USstart--> |
| 304 | +If you cannot resolve the issue, see the following resources: |
| 305 | + |
| 306 | +- [OKD Help](https://okd.io/docs/community/help/) |
| 307 | +- [#virtualization Slack channel]( |
| 308 | + https://kubernetes.slack.com/channels/virtualization) |
| 309 | +<!--USend--> |
0 commit comments