Uploading a Local Image and Creating a Virtual Machine
Use this procedure when you already have a virtual machine disk image on your local
machine (for example a qcow2, raw, or img file downloaded from an OS vendor) and want
to run a virtual machine from it, rather than importing the image from a remote HTTP, registry,
or S3 source.
On Alauda Container Platform this is a command-line workflow built on the KubeVirt
virtctl client and the CDI upload proxy — the web console does not yet offer a local-upload
source. The uploaded image is stored as a DataSource (a bootable volume) that virtual
machines can boot from and that can be reused by many virtual machines.
Tip: If instead you want to install an operating system from an ISO, see Creating Linux Images Based on ISO and Creating Windows Images Based on ISO.
Prerequisites
- The
virtctlcommand-line client is installed and matches the cluster's KubeVirt version.virtctlis the standard KubeVirt CLI; download the binary that matches your cluster from the KubeVirt releases and place it on yourPATH. - The
kubectlcommand-line tool is installed and configured to access the cluster. - A local disk image in
qcow2,raw, orimgformat. To speed up the upload, compress the image first withvirt-sparsify,xz, orgzip. - A
StorageClassthat supports theReadWriteOnce(RWO) access mode. - The
cdi-uploadproxyService (in thekubevirtnamespace) is reachable from where you runvirtctl— see Step 1.
Procedure
Expose the CDI upload proxy outside the cluster
virtctl image-upload streams the image to the cdi-uploadproxy Service, which is an internal
ClusterIP Service in the kubevirt namespace. You must make it reachable from where you run
virtctl.
Note: On OpenShift, CDI automatically discovers an OpenShift
Routetocdi-uploadproxyand fills in the upload URL for you. Alauda Container Platform runs on upstream Kubernetes, which has noRouteresource, so you expose the Service yourself (this step) and set the upload URL explicitly (Step 2).
Use TLS passthrough so that virtctl negotiates TLS directly with cdi-uploadproxy (the
proxy serves a self-signed certificate, so clients pass --insecure). For every method below the
backend is the cdi-uploadproxy Service on port 443 in the kubevirt namespace; note the
resulting external URL for Step 2.
-
Gateway API (Envoy Gateway) — recommended. Add a
TLSlistener inPassthroughmode to aGateway, then create aTLSRoutewhose backend is thecdi-uploadproxyService on port443. The Gateway's external address — aLoadBalancerIP or aNodePort, set by the gateway's Service Type — becomes the upload URL. See Configure GatewayAPI Gateway and Configure GatewayAPI Route for the full procedure, and Envoy Gateway Operator to install the controller. -
Ingress (ingress-nginx). Expose
cdi-uploadproxywith an SSL-passthroughIngress. See Configure Ingresses and Ingress Nginx Operator. The legacy ALB ingress (cpaas.io/alb2) is deprecated. -
LoadBalancer or NodePort Service. Without an ingress controller, expose the Service directly — a
LoadBalancerwhere MetalLB is configured, or aNodePort, which always works:Reach the proxy at
https://<node-ip>:<nodePort>.
After exposing the Service, verify it answers through the new endpoint (the certificate is
self-signed, so use -k):
Point virtctl at the upload proxy URL
virtctl image-upload needs to know the external URL from Step 1. Choose one of the following.
Configure it once (persistent). Set CDIConfig.spec.uploadProxyURLOverride so that every
virtctl image-upload discovers the URL automatically. Because the CDI configuration is managed
by the HyperConverged (HCO) operator — which reconciles direct edits away and does not expose
this field — set it through HCO's jsonpatch annotation:
Warning: HCO documents jsonpatch annotations as an advanced, unsupported mechanism — an incorrect patch can destabilize the virtualization stack. Use it deliberately, and remove the annotation (
kubectl annotate hyperconverged kubevirt-hyperconverged -n kubevirt containerizeddataimporter.kubevirt.io/jsonpatch-) to revert.
Or pass it per command. Skip the cluster configuration and give the URL on each upload with
--uploadproxy-url (shown in Step 3).
Upload the local image
Run virtctl image-upload. The --datasource flag also creates a DataSource that points at
the uploaded volume, making it selectable as a bootable volume:
Notes:
--sizemust be larger than the image's virtual disk size (not the file size). For example, if your image has a 24 GiB virtual disk, request at least a 30 GiB volume. CDI rejects a volume smaller than the uncompressed disk.- Use
--no-create(and omit--size) to upload into aDataVolumethat already exists. --insecureskips verification of the proxy's self-signed certificate.
Wait for the upload and import to finish:
Note: A
DataSourcecreated byvirtctl --datasourcedoes not carry thevirtualization.cpaas.io/*labels used to mark a bootable volume. The image is fully usable through the API (bysourceRef, as in the next step); to also apply that label contract, see Bootable Volumes.
Create a virtual machine from the uploaded image
Reference the DataSource from a dataVolumeTemplates entry via sourceRef. KubeVirt clones
the uploaded volume into a fresh disk for the new virtual machine:
Confirm the operating system boots by opening the serial console; a login prompt indicates a successful boot:
Tip: The uploaded image can also be referenced as a bootable volume when creating a virtual machine, once it carries the required labels — see Creating Virtual Machines and Bootable Volumes.
Creating a Windows virtual machine
For Windows, upload the image to a volume and then clone it when you create the virtual machine,
applying an autounattend.xml answer file during first boot. The upload step is identical to
the procedure above (use a qcow2/raw/img Windows disk image); for the ISO-based install
flow and the VirtIO driver requirements, see
Creating Windows Images Based on ISO.