Deploy a VM application by using raw YAML

You can deploy a VM application by writing a VmApplication specification with an inline KubeVirt VirtualMachine YAML manifest. Use this method to configure advanced VM parameters beyond what the guided form exposes, or to automate VM deployments through the flightctl CLI or API.

Before you begin

  • A container disk image is pushed to an OCI-compatible registry accessible from the edge device.
  • The target edge device meets the KVM readiness requirements.
  • Pull credentials for registry.redhat.io are configured on the device at /root/.config/containers/auth.json. See Configure pull credentials on an edge device for VM applications.
  • You have the Admin or Operator role in Red Hat Edge Manager.
  • The flightctl CLI is installed and authenticated (for CLI deployments).

Procedure

  1. Create a device specification YAML file that includes a VmApplication entry in the spec.applications list.

    The following example shows a minimal VM application that boots a Fedora container disk image:

    apiVersion: flightctl.io/v1beta1
    kind: Device
    metadata:
      name: <device_name>
    spec:
      applications:
      - name: my-vm
        appType: vm
        inline:
        - path: vm.yaml
          content: |
            apiVersion: kubevirt.io/v1
            kind: VirtualMachine
            metadata:
              name: my-vm
            spec:
              running: true
              template:
                spec:
                  domain:
                    devices:
                      disks:
                      - name: rootdisk
                        disk:
                          bus: virtio
                    resources:
                      requests:
                        memory: 2048Mi
                  volumes:
                  - name: rootdisk
                    containerDisk:
                      image: quay.io/containerdisks/fedora:40
    Note

    The spec.running field in the KubeVirt manifest is ignored. Red Hat Edge Manager controls the running state of VM applications through application lifecycle actions (flightctl app start, flightctl app stop, flightctl app restart) or the equivalent UI buttons, not through the spec.running field.

    Where:

    name
    The application name. Must match the metadata.name value in the vm.yaml content.
    appType
    Must be vm.
    inline
    Must contain exactly one file named vm.yaml.
    vm.yaml content
    A complete KubeVirt VirtualMachine resource with apiVersion: kubevirt.io/v1 and kind: VirtualMachine.
  2. To add SSH access through port publishing, include the publishPorts field in the application specification:
      applications:
      - name: my-vm
        appType: vm
        publishPorts:
        - "2222:22"
        inline:
        - path: vm.yaml
          content: |
            apiVersion: kubevirt.io/v1
            kind: VirtualMachine
            metadata:
              name: my-vm
            spec:
              running: true
              template:
                spec:
                  domain:
                    devices:
                      disks:
                      - name: rootdisk
                        disk:
                          bus: virtio
                    resources:
                      requests:
                        memory: 2048Mi
                  volumes:
                  - name: rootdisk
                    containerDisk:
                      image: quay.io/containerdisks/fedora:40

    Each entry in publishPorts uses the <host_port>:<vm_port> or <host_port>:<vm_port>/<protocol> format, where protocol is tcp, udp, or sctp.

  3. Apply the device specification by using the flightctl CLI:
    $ flightctl apply -f <device_spec_file>.yaml

    Alternatively, paste the VmApplication YAML into the raw YAML editor in the Red Hat Edge Manager web console.

    Important

    Changing any field in the VM application specification after initial deployment causes the VM to reboot. Plan configuration changes accordingly to minimize disruption to running workloads.

Results

  • Check the application status by inspecting the device. The application appears in the status after the device has updated to the new spec. For VMs that require downloading large images, this might take a while. Review the device update status for troubleshooting if needed.
    $ flightctl get device/<device_name> -o yaml

    The application status transitions from Preparing to Starting to Running:

    status:
      applications:
      - name: my-vm
        status: Running
        ready: 2/4
        restarts: 0
    Note

    VM applications render as multiple Podman workloads, including the compute container and init containers generated by the vm-to-quadlet conversion. The ready field shows the ratio of healthy containers to total containers. Ratios such as 2/4 or 2/5 are normal for a running VM application and do not indicate a partial failure.

    Note

    On its first boot, a Windows VM guest might start without network connectivity. To recover, restart the VM application by using lifecycle control: run flightctl app restart device/<device_name> --name <app_name>, or stop and then start the application.

If the API returns HTTP 422, check the following validation rules:

  • The inline set must contain exactly one file named vm.yaml.
  • The vm.yaml content must have kind: VirtualMachine and apiVersion: kubevirt.io/v1.
  • The metadata.name in vm.yaml must match the name of the VmApplication.
  • Each publishPorts entry must use the <host_port>:<vm_port> or <host_port>:<vm_port>/<protocol> format.
  • Only the inline provider is supported. The image and gitRef providers are not supported for VM applications.

If the VM application does not reach Running status or you cannot open a console session, inspect the device-side service logs:

$ sudo journalctl -u '*<vm_app_name>*' --no-pager

Every container for a VM application, including the compute container and any init containers, is managed as a quadlet-generated systemd service. If an init container fails to start because of a bad image reference or a configuration error, Podman does not create a container to collect logs from. The journalctl -u command accepts glob patterns and captures logs from all systemd units associated with the application.