Creating VirtualMachines by using virtctl

The virtctl sub command create vm allows easy creation of VirtualMachine manifests from the command line. It leverages instance types and preferences and inference by default (see Using instance types and preferences) and it provides several flags to control details of the created virtual machine.

For example there are flags to specify the name or run strategy of a virtual machine or flags to add volumes to a virtual machine. Instance types and preferences can either be specified directly or it is possible to let KubeVirt infer those from the volume used to boot the virtual machine.

For a full set of flags and their description use the following command:

  1. virtctl create vm -h

Creating VirtualMachines on a cluster

The output of virtctl create vm can be piped directly into kubectl to create a VirtualMachine on a cluster, e.g.:

  1. # Create a VM with name my-vm on the cluster
  2. virtctl create vm --name my-vm | kubectl create -f -
  3. virtualmachine.kubevirt.io/my-vm created

Using instance types and preferences

Instance types and preferences can be used with the appropriate flags. If they are not otherwise specified, instance types and preferences are inferred from the boot volume of a virtual machine by default. For more information about inference, see below.

The following example creates a VM specifying an instance type and preference by using the appropriate flags:

  1. virtctl create vm --instancetype my-instancetype --preference my-preference

The type of the instance type or preference (namespaced or cluster scope) can be controlled by prefixing the instance type or preference name with the corresponding CRD name, e.g.:

  1. # Using a cluster scoped instance type and a namespaced preference
  2. virtctl create vm \
  3. --instancetype virtualmachineclusterinstancetype/my-instancetype \
  4. --preference virtualmachinepreference/my-preference

If a prefix was not supplied the cluster scoped resources will be used by default.

Inference of instance type and/or preference

To explicitly infer instance types and/or preferences from the volume used to boot the virtual machine add the following flags:

  1. virtctl create vm --infer-instancetype --infer-preference

The implicit default is to always try to infer an instance type and preference from the boot volume. This feature makes use of the IgnoreInferFromVolumeFailure policy, which suppresses failures on inference of instance types and preferences. If one of the above switches has been explicitly specified, the RejectInferFromVolumeFailure policy is used instead. This way users are made aware of potential issues during the virtual machine creation.

To infer an instance type or preference from another volume than the volume used to boot the virtual machine, use the --infer-instancetype-from and --infer-preference-from flags to specify any of the virtual machine’s volumes.

  1. # This virtual machine will boot from volume-a, but the instance type and
  2. # preference are inferred from volume-b.
  3. virtctl create vm \
  4. --volume-import=type:pvc,src:my-ns/my-pvc-a,name:volume-a \
  5. --volume-import=type:pvc,src:my-ns/my-pvc-b,name:volume-b \
  6. --infer-instancetype-from volume-b \
  7. --infer-preference-from volume-b

Boot order of added volumes

Please note that volumes of different kinds currently have the following fixed boot order regardless of the order their flags were specified on the command line:

  1. Containerdisks
  2. Directly used PVCs
  3. DataSources
  4. Cloned PVCs
  5. Blank volumes
  6. Imported volumes (through the --volume-import flag)

If multiple volumes of the same kind were specified their order is determined by the order in which their flags were specified.

Generating cloud-init user data

To generate cloud-init user data with virtctl create vm the following flags can be used.

Note

Generating cloud-init user data is mutually exclusive with specifying custom cloud-init user data, as explained below.

--user flag

Specify the main user of the virtual machine that is created by cloud-init. It sets the user parameter in the generated cloud-init user data.

--password-file flag

Specify a file to read the password for the virtual machine’s main user from. In the generated cloud-init user data, it sets the value of the password parameter to the read in value and the value of the chpasswd parameter to { expire: False }.

--ssh-key flag

Specify one or more SSH authorized keys for the virtual machine’s main user. It sets the ssh_authorized_keys parameter in the generated cloud-init user data.

--ga-manage-ssh flag

When this flag is set, a command enabling the qemu-guest-agent to manage SSH authorized keys is added to the generated cloud-init user data. The command is added to the runcmd parameter which is required on SELinux enabled distributions that would otherwise not allow the qemu-guest-agent to manage SSH authorized keys in the home directories of users.

Example

  1. $ virtctl create vm --user myuser --access-cred=src:my-keys --ga-manage-ssh

This command will generate the following cloud-init user data:

  1. volumes:
  2. - cloudInitNoCloud:
  3. userData: |-
  4. #cloud-config
  5. user: myuser
  6. runcmd:
  7. - [ setsebool, -P, 'virt_qemu_ga_manage_ssh', 'on' ]
  8. name: cloudinitdisk

By passing the --ga-manage-ssh flag explicitly, the qemu-guest-agent is able to manage the credentials read from the Secret my-keys specified as source parameter to the --access-cred flag. Note that if --ga-manage-ssh was not explicitly set to false, this is also the default behavior.

Specifying custom cloud-init user data

To pass custom cloud-init user data to virtctl it needs to be encoded into a base64 string.

Note

Specifying custom cloud-init user data is mutually exclusive with generating cloud-init user data, as explained above.

Here is an example how to do it:

  1. # Put your cloud-init user data into a file.
  2. # This will add an authorized key to the default user.
  3. # To get the default username read the documentation for the cloud image
  4. $ cat cloud-init.txt
  5. #cloud-config
  6. ssh_authorized_keys:
  7. - ssh-rsa AAAA...
  8. # Base64 encode the contents of the file without line wraps and store it in a variable
  9. $ CLOUD_INIT_USERDATA=$(base64 -w 0 cloud-init.txt)
  10. # Show the contents of the variable
  11. $ echo $CLOUD_INIT_USERDATA
  12. I2Nsb3VkLWNvbmZpZwpzc2hfYXV0aG9yaXplZF9rZXlzOgogIC0gc3NoLXJzYSBBQUFBLi4uCg==

You can now use this variable as an argument to the --cloud-init-user-data flag:

  1. virtctl create vm --cloud-init-user-data $CLOUD_INIT_USERDATA

Adding access credentials to a virtual machine

By using the --access-cred flag, the virtctl create vm command can configure access credentials in a created virtual machine. It supports SSH authorized key and password access credentials and can configure them to be injected either through the qemu-guest-agent or through cloud-init metadata. The supported parameters of the flag depend on the chosen type and method. The flag can be passed multiple times to configure more than one access credential.

This flag interacts with the flags used to generate cloud-init user data, namely it inherits the same --user for SSH key injection, and it enables qemu-guest-agent to manage SSH authorized keys (--ga-manage-ssh), if it is not explicitly disabled by the user.

Example

  1. $ virtctl create vm --user myuser --access-cred=src:my-keys

This command will generate the following access credentials and cloud-init user data:

  1. [...]
  2. accessCredentials:
  3. - sshPublicKey:
  4. propagationMethod:
  5. qemuGuestAgent:
  6. users:
  7. - myuser
  8. source:
  9. secret:
  10. secretName: my-keys
  11. volumes:
  12. - cloudInitNoCloud:
  13. userData: |-
  14. #cloud-config
  15. user: myuser
  16. runcmd:
  17. - [ setsebool, -P, 'virt_qemu_ga_manage_ssh', 'on' ]
  18. name: cloudinitdisk

Adding a sysprep volume

A sysprep volume can be added to created virtual machines by passing the --volume-sysprep flag to the virtctl create vm command.

The flag supports adding a sysprep volume from both a ConfigMap or a Secret.

See the examples on how to do it.

Short examples

Create a manifest for a VirtualMachine with a random name:

  1. virtctl create vm

Create a manifest for a VirtualMachine with a specified name and RunStrategy Always:

  1. virtctl create vm --name=my-vm --run-strategy=Always

Create a manifest for a VirtualMachine with a specified VirtualMachineClusterInstancetype:

  1. virtctl create vm --instancetype=my-instancetype

Create a manifest for a VirtualMachine with a specified VirtualMachineInstancetype (namespaced):

  1. virtctl create vm --instancetype=virtualmachineinstancetype/my-instancetype

Create a manifest for a VirtualMachine with a specified VirtualMachineClusterPreference:

  1. virtctl create vm --preference=my-preference

Create a manifest for a VirtualMachine with a specified VirtualMachinePreference (namespaced):

  1. virtctl create vm --preference=virtualmachinepreference/my-preference

Create a manifest for a VirtualMachine with specified memory and an ephemeral containerdisk volume:

  1. virtctl create vm --memory=1Gi \
  2. --volume-containerdisk=src:my.registry/my-image:my-tag

Create a manifest for a VirtualMachine with a cloned DataSource in namespace and specified size:

  1. virtctl create vm --volume-import=type:ds,src:my-ns/my-ds,size:50Gi

Create a manifest for a VirtualMachine with a cloned DataSource and inferred instance type and preference:

  1. virtctl create vm --volume-import=type:ds,src:my-annotated-ds \
  2. --infer-instancetype --infer-preference

Create a manifest for a VirtualMachine with multiple volumes and specified boot order:

  1. virtctl create vm --volume-containerdisk=src:my.registry/my-image:my-tag \
  2. --volume-import=type:ds,src:my-ds,bootorder:1

Create a manifest for a VirtualMachine with multiple volumes and inferred instance type and preference with specified volumes:

  1. virtctl create vm --volume-import=type:ds,src:my-annotated-ds \
  2. --volume-pvc=my-annotated-pvc --infer-instancetype=my-annotated-ds \
  3. --infer-preference=my-annotated-pvc

Create a manifest for a VirtualMachine with a cloned PVC:

  1. virtctl create vm --volume-import=type:pvc,src:my-ns/my-pvc

Create a manifest for a VirtualMachine using a PVC without cloning it:

  1. virtctl create vm --volume-pvc=src:my-pvc

Create a manifest for a VirtualMachine with a clone DataSource and a blank volume:

  1. virtctl create vm --volume-import=type:ds,src:my-ns/my-ds \
  2. --volume-import=type:blank,size:50Gi

Create a manifest for a VirtualMachine with a specified VirtualMachineCluster{Instancetype,Preference} and cloned DataSource:

  1. virtctl create vm --instancetype=my-instancetype --preference=my-preference \
  2. --volume-import=type:ds,src:my-ds

Create a manifest for a VirtualMachine with a specified VirtualMachineCluster{Instancetype,Preference} and two cloned DataSources (flag can be provided multiple times):

  1. virtctl create vm --instancetype=my-instancetype --preference=my-preference \
  2. --volume-import=type:ds,src:my-ds1 --volume-import=type:ds,src:my-ds2

Create a manifest for a VirtualMachine with a specified VirtualMachineCluster{Instancetype,Preference} and directly used PVC:

  1. virtctl create vm --instancetype=my-instancetype --preference=my-preference \
  2. --volume-pvc=my-pvc

Create a manifest for a VirtualMachine with a specified DataVolumeTemplate:

  1. virtctl create vm \
  2. --volume-import=type:pvc,name:my-pvc,namespace:default,size:256Mi

Create a manifest for a VirtualMachine with a generated cloud-init config setting the user and adding an ssh authorized key:

  1. virtctl create vm --user=cloud-user --ssh-key="ssh-ed25519 AAAA...."

Create a manifest for a VirtualMachine with a generated cloud-init config setting the user and setting the password from a file:

  1. virtctl create vm --user=cloud-user --password-file=/path/to/file

Create a manifest for a VirtualMachine with SSH public keys injected into the VM from a secret called my-keys to the user also specified in the cloud-init config:

  1. virtctl create vm --user=cloud-user --access-cred=type:ssh,src:my-keys

Create a manifest for a VirtualMachine with SSH public keys injected into the VM from a secret called my-keys to a user specified as param:

  1. virtctl create vm --access-cred=type:ssh,src:my-keys,user:myuser

Create a manifest for a VirtualMachine with password injected into the VM from a secret called my-pws:

  1. virtctl create vm --access-cred=type:password,src:my-pws

Create a manifest for a VirtualMachine with a Containerdisk and a Sysprep volume (source ConfigMap needs to exist):

  1. virtctl create vm --memory=1Gi \
  2. --volume-containerdisk=src:my.registry/my-image:my-tag --sysprep=src:my-cm

Complex examples

These examples show how virtctl create vm can be used in more complex scenarios.

First example

Creating a VirtualMachine with the following settings:

  • Run strategy: Manual
  • Termination grace period: 123 seconds
  • Instancetype: u1.small
  • Prefernce: fedora
  • Using the quay.io/containerdisks/fedora containerdisk as first volume
  • Adding a second blank volume with a size of 1Gi
  • The main user is named myuser
  • Logins with the main user are possible with the specified authorized key
  1. virtctl create vm --run-strategy=Manual --termination-grace-period=123 \
  2. --instancetype=u1.small --preference=fedora \
  3. --volume-containerdisk=src:quay.io/containerdisks/fedora \
  4. --volume-import=type:blank,size:1Gi \
  5. --user=myuser --ssh-key='ssh-ed25519 AAAA...'

Second example

Creating a VirtualMachine with the following settings and using a secret for configuring access credentials:

  • Instancetype: u1.small
  • Prefernce: fedora
  • Using the quay.io/containerdisks/fedora containerdisk as first volume
  • Adding a second blank volume with a size of 1Gi
  • The main user is named myuser
  • Logins with the main user are possible with the specified authorized key in the access credentials
  1. # First create the secret with the public key:
  2. kubectl create secret generic my-keys --from-file=$HOME/.ssh/id_ed25519.pub
  3. # Then create the VM on the cluster
  4. virtctl create vm --name my-vm --instancetype=u1.small --preference=fedora \
  5. --volume-containerdisk=src:quay.io/containerdisks/fedora \
  6. --volume-import=type:blank,size:1Gi --user=myuser \
  7. --access-cred=src:my-keys | kubectl create -f -
  8. # Login via SSH once the VM is ready
  9. virtctl ssh -i $HOME/.ssh/id_ed25519 myuser@my-vm