# 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](../user_workloads/instancetypes.md) and inference by default (see [Using instance types and preferences](#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: ```shell 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.: ```shell # Create a VM with name my-vm on the cluster virtctl create vm --name my-vm | kubectl create -f - 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](#inference-of-instance-type-andor-preference). The following example creates a VM specifying an instance type and preference by using the appropriate flags: ```shell 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.: ```shell # Using a cluster scoped instance type and a namespaced preference virtctl create vm \ --instancetype virtualmachineclusterinstancetype/my-instancetype \ --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](../user_workloads/instancetypes.md#inferFromVolume) from the volume used to boot the virtual machine add the following flags: ```shell 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. ```shell # This virtual machine will boot from volume-a, but the instance type and # preference are inferred from volume-b. virtctl create vm \ --volume-import=type:pvc,src:my-ns/my-pvc-a,name:volume-a \ --volume-import=type:pvc,src:my-ns/my-pvc-b,name:volume-b \ --infer-instancetype-from volume-b \ --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](#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 ```shell $ virtctl create vm --user myuser --access-cred=src:my-keys --ga-manage-ssh ``` This command will generate the following cloud-init user data: ```yaml volumes: - cloudInitNoCloud: userData: |- #cloud-config user: myuser runcmd: - [ setsebool, -P, 'virt_qemu_ga_manage_ssh', 'on' ] 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](#generating-cloud-init-user-data), as explained above. Here is an example how to do it: ```shell # Put your cloud-init user data into a file. # This will add an authorized key to the default user. # To get the default username read the documentation for the cloud image $ cat cloud-init.txt #cloud-config ssh_authorized_keys: - ssh-rsa AAAA... # Base64 encode the contents of the file without line wraps and store it in a variable $ CLOUD_INIT_USERDATA=$(base64 -w 0 cloud-init.txt) # Show the contents of the variable $ echo $CLOUD_INIT_USERDATA I2Nsb3VkLWNvbmZpZwpzc2hfYXV0aG9yaXplZF9rZXlzOgogIC0gc3NoLXJzYSBBQUFBLi4uCg== ``` You can now use this variable as an argument to the `--cloud-init-user-data` flag: ```shell 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](./accessing_virtual_machines.md#dynamic-ssh-public-key-injection-via-qemu-guest-agent) 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](#generating-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 ```shell $ virtctl create vm --user myuser --access-cred=src:my-keys ``` This command will generate the following access credentials and cloud-init user data: ``` [...] accessCredentials: - sshPublicKey: propagationMethod: qemuGuestAgent: users: - myuser source: secret: secretName: my-keys volumes: - cloudInitNoCloud: userData: |- #cloud-config user: myuser runcmd: - [ setsebool, -P, 'virt_qemu_ga_manage_ssh', 'on' ] name: cloudinitdisk ``` ## Adding a sysprep volume A [sysprep volume](startup_scripts.md#sysprep-examples) 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: ```shell virtctl create vm ``` Create a manifest for a VirtualMachine with a specified name and RunStrategy Always: ```shell virtctl create vm --name=my-vm --run-strategy=Always ``` Create a manifest for a VirtualMachine with a specified VirtualMachineClusterInstancetype: ```shell virtctl create vm --instancetype=my-instancetype ``` Create a manifest for a VirtualMachine with a specified VirtualMachineInstancetype (namespaced): ```shell virtctl create vm --instancetype=virtualmachineinstancetype/my-instancetype ``` Create a manifest for a VirtualMachine with a specified VirtualMachineClusterPreference: ```shell virtctl create vm --preference=my-preference ``` Create a manifest for a VirtualMachine with a specified VirtualMachinePreference (namespaced): ```shell virtctl create vm --preference=virtualmachinepreference/my-preference ``` Create a manifest for a VirtualMachine with specified memory and an ephemeral containerdisk volume: ```shell virtctl create vm --memory=1Gi \ --volume-containerdisk=src:my.registry/my-image:my-tag ``` Create a manifest for a VirtualMachine with a cloned DataSource in namespace and specified size: ```shell 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: ```shell virtctl create vm --volume-import=type:ds,src:my-annotated-ds \ --infer-instancetype --infer-preference ``` Create a manifest for a VirtualMachine with multiple volumes and specified boot order: ```shell virtctl create vm --volume-containerdisk=src:my.registry/my-image:my-tag \ --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: ```shell virtctl create vm --volume-import=type:ds,src:my-annotated-ds \ --volume-pvc=my-annotated-pvc --infer-instancetype=my-annotated-ds \ --infer-preference=my-annotated-pvc ``` Create a manifest for a VirtualMachine with a cloned PVC: ```shell virtctl create vm --volume-import=type:pvc,src:my-ns/my-pvc ``` Create a manifest for a VirtualMachine using a PVC without cloning it: ```shell virtctl create vm --volume-pvc=src:my-pvc ``` Create a manifest for a VirtualMachine with a clone DataSource and a blank volume: ```shell virtctl create vm --volume-import=type:ds,src:my-ns/my-ds \ --volume-import=type:blank,size:50Gi ``` Create a manifest for a VirtualMachine with a specified VirtualMachineCluster{Instancetype,Preference} and cloned DataSource: ```shell virtctl create vm --instancetype=my-instancetype --preference=my-preference \ --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): ```shell virtctl create vm --instancetype=my-instancetype --preference=my-preference \ --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: ```shell virtctl create vm --instancetype=my-instancetype --preference=my-preference \ --volume-pvc=my-pvc ``` Create a manifest for a VirtualMachine with a specified DataVolumeTemplate: ```shell virtctl create vm \ --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: ```shell 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: ```shell 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: ```shell 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: ```shell 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: ```shell 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): ```shell virtctl create vm --memory=1Gi \ --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 ```shell virtctl create vm --run-strategy=Manual --termination-grace-period=123 \ --instancetype=u1.small --preference=fedora \ --volume-containerdisk=src:quay.io/containerdisks/fedora \ --volume-import=type:blank,size:1Gi \ --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 ```shell # First create the secret with the public key: kubectl create secret generic my-keys --from-file=$HOME/.ssh/id_ed25519.pub # Then create the VM on the cluster virtctl create vm --name my-vm --instancetype=u1.small --preference=fedora \ --volume-containerdisk=src:quay.io/containerdisks/fedora \ --volume-import=type:blank,size:1Gi --user=myuser \ --access-cred=src:my-keys | kubectl create -f - # Login via SSH once the VM is ready virtctl ssh -i $HOME/.ssh/id_ed25519 myuser@my-vm ```