Chapter 9. Advanced migration options
Perform advanced migration operations, such as changing precopy snapshot intervals for warm migration, configuring AIO buffering for performance optimization, creating custom rules for validation, or adding hooks to your migration plan. For performance test data and optimization recommendations, see the "Additional resources" section.
9.2. Changing precopy intervals for warm migration Copy linkLink copied to clipboard!
You can change the snapshot interval by patching the ForkliftController custom resource (CR).
Procedure
Patch the
ForkliftControllerCR:$ oc patch forkliftcontroller/<forklift-controller> -n openshift-mtv -p '{"spec": {"controller_precopy_interval": <interval_in_minutes>}}' --type=mergewhere:
- <interval_in_minutes>`
Specifies the precopy interval in minutes. The default value is
60.You do not need to restart the
forklift-controllerpod.
9.3. About AIO buffering for cold migrations Copy linkLink copied to clipboard!
You can configure Asynchronous Input/Output (AIO) buffering to optimize Network Block Device (NBD) transport performance for cold migrations in specific scenarios.
AIO buffering adjusts the buffer size and count parameters for NBD transport network file copy (NFC) operations. This optimization is most effective when migrating multiple virtual machines (VMs) concurrently from a single ESXi host.
AIO buffering is only suitable for cold migration use cases. You must remove AIO buffer configuration before performing warm migrations.
9.3.1. Enabling and configuring AIO buffering Copy linkLink copied to clipboard!
You can enable and configure Asynchronous Input/Output (AIO) buffering for use with the Migration Toolkit for Virtualization (MTV).
Procedure
Ensure that the
forklift-controllerpod in theopenshift-mtvnamespace supports the AIO buffer values. Since the pod name prefix is dynamic, check the pod name by running the following command:oc get pods -n openshift-mtv | grep forklift-controller | awk '{print $1}'For example, the output if the pod name prefix is "forklift-controller-667f57c8f8-qllnx" would be:
forklift-controller-667f57c8f8-qllnxCheck the environment variables of the pod by running the following command:
oc get pod forklift-controller-667f57c8f8-qllnx -n openshift-mtv -o yamlCheck for the following lines in the output:
... \- name: VIRT\_V2V\_EXTRA\_ARGS \- name: VIRT\_V2V\_EXTRA\_CONF\_CONFIG\_MAP ...In the
openshift-mtvnamespace, edit theForkliftControllercustom resource (CR) by performing the following steps:Access the
ForkliftControllerCR for editing by running the following command:oc edit forkliftcontroller -n openshift-mtvAdd the following lines to the
specsection of theForkliftControllerCR:virt_v2v_extra_args: "--vddk-config /mnt/extra-v2v-conf/input.conf" virt_v2v_extra_conf_config_map: "perf"
Create the required config map
perfby running the following command:oc -n openshift-mtv create cm perfConvert the desired buffer configuration values to Base64. For example, for 16/4, run the following command:
echo -e "VixDiskLib.nfcAio.Session.BufSizeIn64KB=16\nvixDiskLib.nfcAio.Session.BufCount=4" | base64The output will be similar to the following:
Vml4RGlza0xpYi5uZmNBaW8uU2Vzc2lvbi5CdWZTaXplSW42NEtCPTE2CnZpeERpc2tMaWIubmZjQWlvLlNlc3Npb24uQnVmQ291bnQ9NAo=In the config map
perf, enter the Base64 string in thebinaryDatasection, for example:apiVersion: v1 kind: ConfigMap binaryData: input.conf: Vml4RGlza0xpYi5uZmNBaW8uU2Vzc2lvbi5CdWZTaXplSW42NEtCPTE2CnZpeERpc2tMaWIubmZjQWlvLlNlc3Npb24uQnVmQ291bnQ9NAo= metadata: name: perf namespace: openshift-mtv-
Restart the
forklift-controllerpod to apply the new configuration. -
Ensure the
VIRT_V2V_EXTRA_ARGSenvironment variable reflects the updated settings. Run a migration plan and check the logs of the migration pod. Confirm that the AIO buffer settings are passed as parameters, particularly the
--vddk-configvalue.For example, if you run the following command:
exec: /usr/bin/virt-v2v … --vddk-config /mnt/extra-v2v-conf/input.confThe logs include a section similar to the following, if
debug_level = 4:Buffer size calc for 16 value: (16 * 64 * 1024 = 1048576) nbdkit: vddk[1]: debug: [NFC VERBOSE] NfcAio_OpenSession: Opening an AIO session. nbdkit: vddk[1]: debug: [NFC INFO] NfcAioInitSession: Disabling read-ahead buffer since the AIO buffer size of 1048576 is >= the read-ahead buffer size of 65536. Explicitly setting flag '`NFC_AIO_SESSION_NO_NET_READ_AHEAD`' nbdkit: vddk[1]: debug: [NFC VERBOSE] NfcAioInitSession: AIO Buffer Size is 1048576 nbdkit: vddk[1]: debug: [NFC VERBOSE] NfcAioInitSession: AIO Buffer Count is 4Verify that the correct config map values are in the migration pod. Do this by logging into the migration pod and running the following command:
cat /mnt/extra-v2v-conf/input.confExample output is as follows:
VixDiskLib.nfcAio.Session.BufSizeIn64KB=16 vixDiskLib.nfcAio.Session.BufCount=4Optional: Enable debug logs by running the following command. The command converts the configuration to Base64, including a high log level:
echo -e "`VixDiskLib.nfcAio.Session.BufSizeIn64KB=16\nVixDiskLib.nfcAio.Session.BufCount=4\nVixDiskLib.nfc.LogLevel=4`" | base64NoteAdding a high log level reduces performance and is for debugging purposes only.
9.3.2. Removing AIO buffer configuration Copy linkLink copied to clipboard!
You can remove AIO buffer configuration for a cold migration using Migration Toolkit for Virtualization (MTV). You must remove AIO buffer configuration before performing warm migrations using MTV.
The procedure that follows assumes the AIO buffering was enabled and configured according to the procedure in Enabling and configuring AIO buffering.
Procedure
In the
openshift-mtvnamespace, edit theForkliftControllercustom resource (CR) by performing the following steps:Access the
ForkliftControllerCR for editing by running the following command:oc edit forkliftcontroller -n openshift-mtvRemove the following lines from the
specsection of theForkliftControllerCR:virt_v2v_extra_args: "`–vddk-config /mnt/extra-v2v-conf/input.conf`" virt_v2v_extra_conf_config_map: "`perf`"
Delete the config map named
perf:oc delete cm perf -n openshift-mtv-
Optional: Restart the
forklift-controllerpod to ensure that the changes took effect.
9.4. Creating custom rules for the Validation service Copy linkLink copied to clipboard!
The Validation service uses Open Policy Agent (OPA) policy rules to check the suitability of each virtual machine (VM) for migration. The Validation service generates a list of concerns for each VM, which are stored in the Provider Inventory service as VM attributes. The web console displays the concerns for each VM in the provider inventory.
You can create custom rules to extend the default ruleset of the Validation service. For example, you can create a rule that checks whether a VM has multiple disks.
9.4.1. About Rego files Copy linkLink copied to clipboard!
Validation rules are written in Rego, the Open Policy Agent (OPA) native query language. The rules are stored as .rego files in the /usr/share/opa/policies/io/konveyor/forklift/_<provider>_ directory of the Validation pod.
Each validation rule is defined in a separate .rego file and tests for a specific condition. If the condition evaluates as true, the rule adds a hash containing the category, label, and assessment keys to the concerns. The concerns content is added to the concerns key in the inventory record of the virtual machine (VM). The web console displays the content of the concerns key for each VM.
The following .rego file example checks for distributed resource scheduling enabled (has_drs_enabled) in the cluster of a VMware VM:
package io.konveyor.forklift.vmware
has_drs_enabled {
input.host.cluster.drsEnabled
}
concerns[flag] {
has_drs_enabled
flag := {
"category": "Information",
"label": "VM running in a DRS-enabled cluster",
"assessment": "Distributed resource scheduling is not currently supported by OpenShift Virtualization. The VM can be migrated but it will not have this feature in the target environment."
}
}
where:
package io.konveyor.forklift.vmware-
Is the package namespace in this example, The package namespaces are
io.konveyor.forklift.vmwarefor VMware andio.konveyor.forklift.ovirtfor Red Hat Virtualization. input.host.cluster.drsEnabled-
Is the query parameter in this example. Query parameters are based on the
inputkey of theValidationservice JSON.
9.4.2. Checking the default validation rules Copy linkLink copied to clipboard!
Before you create a custom rule, you must check the default rules of the Validation service to ensure that you do not create a rule that redefines an existing default value.
Example: If a default rule contains the line default valid_input = false and you create a custom rule that contains the line default valid_input = true, the Validation service will not start.
Procedure
Connect to the terminal of the
Validationpod:$ oc rsh <validation_pod>Go to the OPA policies directory for your provider:
$ cd /usr/share/opa/policies/io/konveyor/forklift/<provider>where:
- <provider>
-
Specifies the <provider>. Valid options:
vmwareorovirt.
Search for the default policies:
$ grep -R "default" *
9.4.3. Creating validation rules Copy linkLink copied to clipboard!
To ensure that your custom validation rules persist across pod restarts, scaling events, and Migration Toolkit for Virtualization (MTV) upgrades, deploy the rules by using a ConfigMap Custom Resource (CR). By default, the Validation service reads validation rules from a ConfigMap named forklift-validation-config in the openshift-mtv namespace. You can optionally customize the ConfigMap name by updating the forklift-controller CR.
-
If you create a rule with the same name as an existing rule, the
Validationservice performs anORoperation with the rules. -
If you create a rule that contradicts a default rule, the
Validationservice will not start.
Validation rules are based on VM attributes collected by the Provider Inventory service. The Provider Inventory service presents provider-specific VM properties as simplified attributes for the validation engine. You can then create Rego queries based on the attributes, and add the queries to the ConfigMap CR to apply validation rules across different source environments.
For example, in a validation rule that checks if a VMware VM has NUMA node affinity configured, you have these elements:
-
VMware API path:
MOR:VirtualMachine.config.extraConfig["numa.nodeAffinity"]. Provider Inventoryservice attribute with a list value:Expand Inventory Attribute Example Value numa.nodeAffinity["True"]or[](empty list if not configured)Rego query based on the attribute:
count(input.numaNodeAffinity) != 0For information about Rego files, see About Rego files.
Procedure
Create a
ConfigMapnamedforklift-validation-configin theopenshift-mtvnamespace:NoteIf you want to use a different ConfigMap name, you must also configure the
forklift-controllerCR. For more information, see step 2.Example:
$ cat << EOF | oc apply -f - apiVersion: v1 kind: ConfigMap metadata: name: forklift-validation-config namespace: openshift-mtv data: vmware_multiple_disks.rego: |- package <provider_package> has_multiple_disks { count(input.disks) > 1 } concerns[flag] { has_multiple_disks flag := { "category": "<Information>", "label": "Multiple disks detected", "assessment": "Multiple disks detected on this VM." } } EOF-
<provider_package>: The provider package name. Valid values areio.konveyor.forklift.vmwarefor VMware andio.konveyor.forklift.ovirtfor Red Hat Virtualization. -
count(input.disks): Your Rego query. -
category: Valid values areCritical,Warning, andInformation.
-
Optional: If you are using a custom ConfigMap name instead of the default
forklift-validation-config, add thevalidation_configmap_nameparameter to thespecsection of theForkliftControllerCR:spec: ... validation_configmap_name: <custom_configmap_name> ...-
Replace
<custom_configmap_name>with the name of your ConfigMap.
-
Replace
Stop the
Validationpod by scaling theforklift-validationdeployment to0:$ oc scale -n openshift-mtv --replicas=0 deployment/forklift-validationStart the
Validationpod by scaling theforklift-validationdeployment to1:$ oc scale -n openshift-mtv --replicas=1 deployment/forklift-validationCheck the
Validationpod log to verify that the pod started:$ oc logs -f <validation_pod>If the custom rule conflicts with a default rule, the
Validationpod does not start.Remove the source provider:
$ oc delete provider <provider> -n openshift-mtvAdd the source provider to apply the new rule. For information about adding a source provider, see the sections about adding a source provider in Chapters 10-14 of Planning your migration to Red Hat OpenShift Virtualization:
$ cat << EOF | oc apply -f - apiVersion: forklift.konveyor.io/v1beta1 kind: Provider metadata: name: <provider> namespace: openshift-mtv spec: type: <provider_type> url: <api_end_point> secret: name: <secret> namespace: openshift-mtv EOF-
<provider_type>: Valid values areovirt,vsphere, andopenstack. -
<api_end_point>: The API endpoint URL, for example,https://<vCenter_host>/sdkfor vSphere,https://<engine_host>/ovirt-engine/apifor RHV, orhttps://<identity_service>/v3for OpenStack. -
<secret>: The name of the providerSecretCR.
-
Next step
Update the inventory rules version after creating a custom rule so that the Provider Inventory service detects the changes and validates the VMs. For more information, see Updating the inventory rules version.
9.4.4. Updating the inventory rules version Copy linkLink copied to clipboard!
You must update the inventory rules version each time you update the rules so that the Provider Inventory service detects the changes and triggers the Validation service.
The rules version is recorded in a rules_version.rego file for each provider.
Procedure
Retrieve the current rules version:
$ GET https://forklift-validation/v1/data/io/konveyor/forklift/<provider>/rules_versionThe output looks like the following example:
{ "result": { "rules_version": 5 } }Connect to the terminal of the
Validationpod:$ oc rsh <validation_pod>-
Update the rules version in the
/usr/share/opa/policies/io/konveyor/forklift/<provider>/rules_version.regofile. -
Log out of the
Validationpod terminal. Verify the updated rules version:
$ GET https://forklift-validation/v1/data/io/konveyor/forklift/<provider>/rules_versionThe output looks like the following example:
{ "result": { "rules_version": 6 } }
9.4.5. Retrieving the Inventory service JSON Copy linkLink copied to clipboard!
You retrieve the Inventory service JSON by sending an Inventory service query to a virtual machine (VM). The output contains an "input" key, which contains the inventory attributes that are queried by the Validation service rules.
You can create a validation rule based on any attribute in the "input" key, for example, input.snapshot.kind.
Procedure
Retrieve the routes for the project:
oc get route -n openshift-mtvRetrieve the
Inventoryservice route:$ oc get route <inventory_service> -n openshift-mtvRetrieve the access token:
$ TOKEN=$(oc whoami -t)Trigger an HTTP GET request (for example, using Curl):
$ curl -H "Authorization: Bearer $TOKEN" https://<inventory_service_route>/providers -kRetrieve the
UUIDof a provider:$ curl -H "Authorization: Bearer $TOKEN" https://<inventory_service_route>/providers/<provider> -kwhere:
- <provider>
-
Specifies the type of provider. Allowed values are
vsphere,ovirt, andopenstack.
Retrieve the VMs of a provider:
$ curl -H "Authorization: Bearer $TOKEN" https://<inventory_service_route>/providers/<provider>/<UUID>/vms -kRetrieve the details of a VM:
$ curl -H "Authorization: Bearer $TOKEN" https://<inventory_service_route>/providers/<provider>/<UUID>/workloads/<vm> -kExample output
{ "input": { "selfLink": "providers/vsphere/c872d364-d62b-46f0-bd42-16799f40324e/workloads/vm-431", "id": "vm-431", "parent": { "kind": "Folder", "id": "group-v22" }, "revision": 1, "name": "iscsi-target", "revisionValidated": 1, "isTemplate": false, "networks": [ { "kind": "Network", "id": "network-31" }, { "kind": "Network", "id": "network-33" } ], "disks": [ { "key": 2000, "file": "[iSCSI_Datastore] iscsi-target/iscsi-target-000001.vmdk", "datastore": { "kind": "Datastore", "id": "datastore-63" }, "capacity": 17179869184, "shared": false, "rdm": false }, { "key": 2001, "file": "[iSCSI_Datastore] iscsi-target/iscsi-target_1-000001.vmdk", "datastore": { "kind": "Datastore", "id": "datastore-63" }, "capacity": 10737418240, "shared": false, "rdm": false } ], "concerns": [], "policyVersion": 5, "uuid": "42256329-8c3a-2a82-54fd-01d845a8bf49", "firmware": "bios", "powerState": "poweredOn", "connectionState": "connected", "snapshot": { "kind": "VirtualMachineSnapshot", "id": "snapshot-3034" }, "changeTrackingEnabled": false, "cpuAffinity": [ 0, 2 ], "cpuHotAddEnabled": true, "cpuHotRemoveEnabled": false, "memoryHotAddEnabled": false, "faultToleranceEnabled": false, "cpuCount": 2, "coresPerSocket": 1, "memoryMB": 2048, "guestName": "Red Hat Enterprise Linux 7 (64-bit)", "balloonedMemory": 0, "ipAddress": "10.19.2.96", "storageUsed": 30436770129, "numaNodeAffinity": [ "0", "1" ], "devices": [ { "kind": "RealUSBController" } ], "host": { "id": "host-29", "parent": { "kind": "Cluster", "id": "domain-c26" }, "revision": 1, "name": "IP address or host name of the vCenter host or RHV Engine host", "selfLink": "providers/vsphere/c872d364-d62b-46f0-bd42-16799f40324e/hosts/host-29", "status": "green", "inMaintenance": false, "managementServerIp": "10.19.2.96", "thumbprint": <thumbprint>, "timezone": "UTC", "cpuSockets": 2, "cpuCores": 16, "productName": "VMware ESXi", "productVersion": "6.5.0", "networking": { "pNICs": [ { "key": "key-vim.host.PhysicalNic-vmnic0", "linkSpeed": 10000 }, { "key": "key-vim.host.PhysicalNic-vmnic1", "linkSpeed": 10000 }, { "key": "key-vim.host.PhysicalNic-vmnic2", "linkSpeed": 10000 }, { "key": "key-vim.host.PhysicalNic-vmnic3", "linkSpeed": 10000 } ], "vNICs": [ { "key": "key-vim.host.VirtualNic-vmk2", "portGroup": "VM_Migration", "dPortGroup": "", "ipAddress": "192.168.79.13", "subnetMask": "255.255.255.0", "mtu": 9000 }, { "key": "key-vim.host.VirtualNic-vmk0", "portGroup": "Management Network", "dPortGroup": "", "ipAddress": "10.19.2.13", "subnetMask": "255.255.255.128", "mtu": 1500 }, { "key": "key-vim.host.VirtualNic-vmk1", "portGroup": "Storage Network", "dPortGroup": "", "ipAddress": "172.31.2.13", "subnetMask": "255.255.0.0", "mtu": 1500 }, { "key": "key-vim.host.VirtualNic-vmk3", "portGroup": "", "dPortGroup": "dvportgroup-48", "ipAddress": "192.168.61.13", "subnetMask": "255.255.255.0", "mtu": 1500 }, { "key": "key-vim.host.VirtualNic-vmk4", "portGroup": "VM_DHCP_Network", "dPortGroup": "", "ipAddress": "10.19.2.231", "subnetMask": "255.255.255.128", "mtu": 1500 } ], "portGroups": [ { "key": "key-vim.host.PortGroup-VM Network", "name": "VM Network", "vSwitch": "key-vim.host.VirtualSwitch-vSwitch0" }, { "key": "key-vim.host.PortGroup-Management Network", "name": "Management Network", "vSwitch": "key-vim.host.VirtualSwitch-vSwitch0" }, { "key": "key-vim.host.PortGroup-VM_10G_Network", "name": "VM_10G_Network", "vSwitch": "key-vim.host.VirtualSwitch-vSwitch1" }, { "key": "key-vim.host.PortGroup-VM_Storage", "name": "VM_Storage", "vSwitch": "key-vim.host.VirtualSwitch-vSwitch1" }, { "key": "key-vim.host.PortGroup-VM_DHCP_Network", "name": "VM_DHCP_Network", "vSwitch": "key-vim.host.VirtualSwitch-vSwitch1" }, { "key": "key-vim.host.PortGroup-Storage Network", "name": "Storage Network", "vSwitch": "key-vim.host.VirtualSwitch-vSwitch1" }, { "key": "key-vim.host.PortGroup-VM_Isolated_67", "name": "VM_Isolated_67", "vSwitch": "key-vim.host.VirtualSwitch-vSwitch2" }, { "key": "key-vim.host.PortGroup-VM_Migration", "name": "VM_Migration", "vSwitch": "key-vim.host.VirtualSwitch-vSwitch2" } ], "switches": [ { "key": "key-vim.host.VirtualSwitch-vSwitch0", "name": "vSwitch0", "portGroups": [ "key-vim.host.PortGroup-VM Network", "key-vim.host.PortGroup-Management Network" ], "pNICs": [ "key-vim.host.PhysicalNic-vmnic4" ] }, { "key": "key-vim.host.VirtualSwitch-vSwitch1", "name": "vSwitch1", "portGroups": [ "key-vim.host.PortGroup-VM_10G_Network", "key-vim.host.PortGroup-VM_Storage", "key-vim.host.PortGroup-VM_DHCP_Network", "key-vim.host.PortGroup-Storage Network" ], "pNICs": [ "key-vim.host.PhysicalNic-vmnic2", "key-vim.host.PhysicalNic-vmnic0" ] }, { "key": "key-vim.host.VirtualSwitch-vSwitch2", "name": "vSwitch2", "portGroups": [ "key-vim.host.PortGroup-VM_Isolated_67", "key-vim.host.PortGroup-VM_Migration" ], "pNICs": [ "key-vim.host.PhysicalNic-vmnic3", "key-vim.host.PhysicalNic-vmnic1" ] } ] }, "networks": [ { "kind": "Network", "id": "network-31" }, { "kind": "Network", "id": "network-34" }, { "kind": "Network", "id": "network-57" }, { "kind": "Network", "id": "network-33" }, { "kind": "Network", "id": "dvportgroup-47" } ], "datastores": [ { "kind": "Datastore", "id": "datastore-35" }, { "kind": "Datastore", "id": "datastore-63" } ], "vms": null, "networkAdapters": [], "cluster": { "id": "domain-c26", "parent": { "kind": "Folder", "id": "group-h23" }, "revision": 1, "name": "mycluster", "selfLink": "providers/vsphere/c872d364-d62b-46f0-bd42-16799f40324e/clusters/domain-c26", "folder": "group-h23", "networks": [ { "kind": "Network", "id": "network-31" }, { "kind": "Network", "id": "network-34" }, { "kind": "Network", "id": "network-57" }, { "kind": "Network", "id": "network-33" }, { "kind": "Network", "id": "dvportgroup-47" } ], "datastores": [ { "kind": "Datastore", "id": "datastore-35" }, { "kind": "Datastore", "id": "datastore-63" } ], "hosts": [ { "kind": "Host", "id": "host-44" }, { "kind": "Host", "id": "host-29" } ], "dasEnabled": false, "dasVms": [], "drsEnabled": true, "drsBehavior": "fullyAutomated", "drsVms": [], "datacenter": null } } } }
9.5. About hooks for MTV migration plans Copy linkLink copied to clipboard!
You can add hooks to an Migration Toolkit for Virtualization (MTV) migration plan to perform automated operations on a VM, either before or after you migrate it.
You can add hooks to Migration Toolkit for Virtualization (MTV) migration plans by using either the MTV CLI or the MTV user interface, which is located in the Red Hat OpenShift web console.
- Hook types
- Pre-migration hooks: Hooks that perform operations on a VM that is located on a provider. This prepares the VM for migration.
- Post-migration hooks: Hooks that perform operations on a VM that has migrated to OpenShift Virtualization.
- Hook configuration
-
Default hook image: The default hook image for an MTV hook is
{hook-runner-image}. The image is based on the Ansible Runner image with the addition ofpython-openshiftto provide Ansible Kubernetes resources and a recentocbinary. -
Hook execution: An Ansible Playbook that is provided as part of a migration hook is mounted into the hook container as a
ConfigMap. The hook container is run as a job on the relevant cluster in theopenshift-mtvnamespace. When you add a hook, you must specify the name of the hook and whether it is a pre-migration hook or a post-migration hook. -
Service account: You can optionally specify a service account when adding a hook. When you add a hook by using the Red Hat OpenShift web console, you can specify the service account name in the Service account field when creating or editing the migration plan. When you add a hook by using the CLI, you can specify the service account in the
HookCR. If you specify a service account, it must have the appropriate RBAC permissions to manage cluster resources and at least write access for theopenshift-mtvnamespace where hooks execute.
-
Default hook image: The default hook image for an MTV hook is
For a hook to run on a VM, the VM must be started and available using SSH.
9.5.1. Migration hook workflow Copy linkLink copied to clipboard!
The illustration that follows shows the general process of using a migration hook.
Figure 9.1. Adding a hook to a migration plan
Process:
Input your Ansible hook and credentials.
Input an Ansible hook image to the MTV controller using either the UI or the CLI.
-
In the UI, specify the
ansible-runnerand enter theplaybook.ymlthat contains the hook. - In the CLI, input the hook image, which specifies the playbook that runs the hook.
-
In the UI, specify the
If you need additional data to run the playbook inside the pod, such as SSH data, create a Secret that contains credentials for the VM. The Secret is not mounted to the pod, but is called by the playbook.
NoteThis Secret is not the same as the
SecretCR that contains the credentials of your source provider.
The MTV controller creates the
ConfigMap, which contains:-
workload.yml, which contains information about the VMs. -
playbook.yml, the raw string playbook you want to run. plan.yml, which is thePlanCR.The
ConfigMapcontains the name of the VM and instructs the playbook what to do.
-
The MTV controller creates a job that starts the user-specified image.
Mounts the
ConfigMapto the container.The Ansible hook imports the Secret that the user previously entered.
The job runs a pre-migration hook or a post-migration hook as follows:
- For a pre-migration hook, the job logs into the VMs on the source provider using SSH and runs the hook.
- For a post-migration hook, the job logs into the VMs on OpenShift Virtualization using SSH and runs the hook.
9.5.2. Adding a migration hook to a migration plan using the Red Hat OpenShift web console Copy linkLink copied to clipboard!
You can add a migration hook to an existing migration plan by using the Red Hat OpenShift web console. For example, you can create a hook to install the cloud-init service on a VM and write a file before migration. You can optionally specify a service account for the hook directly in the web console.
You can run one pre-migration hook, one post-migration hook, or one of each per migration plan.
Prerequisites
- Migration plan.
- Migration hook file, whose contents you copy and paste into the web console.
-
File containing the
Secretfor the source provider. -
(Optional) Red Hat OpenShift service account called by the hook. The service account must have at least write access for the
openshift-mtvnamespace where hooks execute. For information about creating a service account, see Understanding and creating service accounts. - SSH access for VMs you want to migrate with the public key installed on the VMs.
- VMs running on Microsoft Server only: Remote Execution enabled.
Procedure
- In the Red Hat OpenShift web console, click Migration for Virtualization > Migration plans and then click the migration plan you want to add the hook to.
- Click Hooks.
For a pre-migration hook, perform the following steps:
- In the Pre migration hook section, toggle the Enable hook switch to Enable pre migration hook.
-
Enter the Hook runner image. If you are specifying the
spec.playbook, you need to use an image that has anansible-runner. -
Optional: Enter the Service account name. The service account must have the necessary RBAC permissions to manage cluster resources and at least write access for the
openshift-mtvnamespace where hooks execute. - Paste your hook as a YAML file in the Ansible playbook text box.
For a post-migration hook, perform the following steps:
- In the Post migration hook, toggle the Enable hook switch to Enable post migration hook.
-
Enter the Hook runner image. If you are specifying the
spec.playbook, you need to use an image that has anansible-runner. -
Optional: Enter the Service account name. The service account must have the necessary RBAC permissions to manage cluster resources and at least write access for the
openshift-mtvnamespace where hooks execute. - Paste your hook as a YAML file in the Ansible playbook text box.
At the top of the tab, click Update hooks.
The following example hook ensures that the VM can be accessed using SSH, creates an SSH key, and runs two tasks: stopping the MariaDB database and generating a text file.
- name: Main hosts: localhost vars_files: - plan.yml - workload.yml tasks: - k8s_info: api_version: v1 kind: Secret name: privkey namespace: openshift-mtv register: ssh_credentials - name: Ensure SSH directory exists file: path: ~/.ssh state: directory mode: 0750 - name: Create SSH key copy: dest: ~/.ssh/id_rsa content: "{{ ssh_credentials.resources[0].data.key | b64decode }}" mode: 0600 - add_host: name: "{{ vm.ipaddress }}" # ALT "{{ vm.guestnetworks[2].ip }}" ansible_user: root groups: vms - hosts: vms vars_files: - plan.yml - workload.yml tasks: - name: Stop MariaDB service: name: mariadb state: stopped - name: Create Test File copy: dest: /premigration.txt content: "Migration from {{ provider.source.name }} of {{ vm.vm1.vm0.id }} has finished\n" mode: 0644
9.5.3. Adding a migration hook to a migration plan using the CLI Copy linkLink copied to clipboard!
You can use a Hook CR to add a pre-migration hook or a post-migration hook to an existing migration plan by using the Migration Toolkit for Virtualization (MTV) CLI. For example, you can create a Hook custom resource (CR) to install the cloud-init service on a VM and write a file before migration.
You can run one pre-migration hook, one post-migration hook, or one of each per migration plan. Each hook needs its own Hook CR, but a Plan CR contains data for all the hooks it uses. You can retrieve additional information stored in a secret or in a ConfigMap by using a k8s module.
Prerequisites
- Migration plan.
- Migration hook image or the playbook containing the hook image.
- File containing the Secret for the source provider.
-
(Optional) Red Hat OpenShift service account called by the hook. The service account must have at least write access for the
openshift-mtvnamespace where hooks execute. For information about creating a service account, see Understanding and creating service accounts. - SSH access for VMs you want to migrate with the public key installed on the VMs.
- VMs running on Microsoft Server only: Remote Execution enabled.
Procedure
If needed, create a Secret with an SSH private key for the VM.
- Choose an existing key or generate a key pair.
- Install the public key on the VM.
Encode the private key in the Secret to base64.
apiVersion: v1 data: key: VGhpcyB3YXMgZ2Vu... kind: Secret metadata: name: ssh-credentials namespace: openshift-mtv type: Opaque
Encode your playbook by concatenating a file and piping it for Base64 encoding, for example:
$ cat playbook.yml | base64 -w0Create a Hook CR:
$ cat << EOF | oc apply -f - apiVersion: forklift.konveyor.io/v1beta1 kind: Hook metadata: name: <hook> namespace: <namespace> spec: image: registry.redhat.io/rhmtc/openshift-migration-hook-runner-rhel8 serviceAccount: <service_account> playbook: | <playbook> EOFwhere:
- <service_account>
Optional: Specifies the Red Hat OpenShift service account. The
serviceAccountmust be provided if you want to manipulate any resources of the cluster.NoteYou can set the service account directly in the Red Hat OpenShift web console when creating or editing a migration plan by using the Service account field. See Adding a migration hook using the web console for the simplified UI workflow. The CLI/YAML method documented here is still supported for advanced use cases and automation.
- <playbook>
Specifies the Base64-encoded Ansible Playbook to use. For example,
LS0tCi0gbm.... If you specify a playbook, theimagemust include anansible-runner. You can use the defaulthook-runnerimage or specify a custom image. If you specify a custom image, you do not have to specify a playbook.NoteTo decode an attached playbook, retrieve the resource with custom output and pipe it to base64. For example:
$ oc get -n openshift-mtv hook playbook -o \ go-template='{{ .spec.playbook }}' | base64 -d
In the
PlanCR of the migration, for each VM, add the following section to the end of the CR:vms: - id: <vm_id> hooks: - hook: namespace: <namespace> name: <name_of_hook> step: <type_of_hook>where:
- <type_of_hook>
Specifies the type of hook. Options are
PreHook, to run the hook before the migration, andPostHook, to run the hook after the migration. In order for a PreHook to run on a VM, the VM must be started and available using SSH.The following example hook ensures that the VM can be accessed using SSH, creates an SSH key, and runs two tasks: stopping the MariaDB database and generating a text file.
- name: Main hosts: localhost vars_files: - plan.yml - workload.yml tasks: - k8s_info: api_version: v1 kind: Secret name: privkey namespace: openshift-mtv register: ssh_credentials - name: Ensure SSH directory exists file: path: ~/.ssh state: directory mode: 0750 - name: Create SSH key copy: dest: ~/.ssh/id_rsa content: "{{ ssh_credentials.resources[0].data.key | b64decode }}" mode: 0600 - add_host: name: "{{ vm.ipaddress }}" # ALT "{{ vm.guestnetworks[2].ip }}" ansible_user: root groups: vms - hosts: vms vars_files: - plan.yml - workload.yml tasks: - name: Stop MariaDB service: name: mariadb state: stopped - name: Create Test File copy: dest: /premigration.txt content: "Migration from {{ provider.source.name }} of {{ vm.vm1.vm0.id }} has finished\n" mode: 0644
9.6. About user defined networks Copy linkLink copied to clipboard!
Beginning with Migration Toolkit for Virtualization 2.10, you can use a user-defined network (UDN) as your default network for migrations from all source providers, except when the source provider is also OpenShift Virtualization. UDNs are not supported for OpenShift-to-OpenShift migrations because the network configuration is preserved from the source cluster. This flexibility allows you to migrate virtual machines (VMs) to OpenShift Virtualization more consistently.
MTV has been redesigned to make it easy for you to migrate VMs to UDN namespaces. Once you configure your UDN in OpenShift Virtualization, you can specify it as your default network in the migration plan mapping. MTV is now able to distinguish a UDN from a conventional pod network.
You can use this feature for creating migration plans by using the Red Hat OpenShift web console or by using the MTV command-line interface. The procedures for creating migration plans have been updated to include the new feature.
9.7. Scheduling target VMs Copy linkLink copied to clipboard!
By default, OpenShift Virtualization assigns the destination nodes of virtual machines (VMs) during migration. However, you can use the scheduling target VMs feature to define the destination nodes and apply specific conditions to schedule when the VMs are switched from pending to on.
9.7.1. About scheduling target VMs Copy linkLink copied to clipboard!
Starting with Migration Toolkit for Virtualization (MTV) 2.10, you can use the target VM scheduling feature to direct MTV to migrate virtual machines (VMs) to specific nodes of OpenShift Virtualization as well as to schedule when to power on the VMs. Using the feature, you can design and enforce rules that you set using either the UI or command-line interface.
Previously, when you migrated VMs to OpenShift Virtualization, OpenShift Virtualization automatically determined the node the VMs would be migrated to. Although this served many customers' needs, there are certain situations in which it is useful to be able to specify the target node of a VM or the conditions under which the VM is powered on, regardless of the type of migration involved.
9.7.2. Target VM scheduling prerequisites Copy linkLink copied to clipboard!
Migrations that use target VM scheduling require the following prerequisites, in addition to the prerequisites for your source provider:
- Migration Toolkit for Virtualization (MTV) 2.10 or later.
- Version of OpenShift Virtualization that is compatible with your version of MTV. For MTV 2.10, the compatible versions of OpenShift Virtualization are 4.18, 4.19, and 4.20 only.
-
cluster-adminor equivalent security privileges that allow managingVirtualMachineInstanceobjects and associated Kubernetes scheduling primitives.
9.7.3. Target VM scheduling options Copy linkLink copied to clipboard!
You can use the following options to schedule when your target VMs are powered on:
-
Node Selector rule: This is the simplest rule. You define a set of mandatory exact match key-value label pairs that the target node must possess. If no node on the cluster has all the labels specified, the VM is not scheduled and it remains in a
Pendingstate until there is space on a node that fits the key-value label pairs. Affinity and Anti-Affinity rules: Node Affinity rules let you schedule VMs to run on selected nodes or workloads (pods). Node Anti-affinity rules let you prevent VMs from being scheduled to run on selected workloads (pods).
Node Affinity and Node Anti-Affinity rules offer more flexible placement control than rigid Node Selector rules, because they support conditionals such as
In,NotIn.Additionally, Affinity rules and Anti-Affinity rules allow you to include both hard and soft conditions in the same rule. A hard condition is a requirement, and a soft condition is a preference.
Affinity rules are supported by MTV at both the node and the workload (pod) levels, but Anti-Affinity rules are supported at the workload (pod) level only.
-
Custom Scheduler Name: If your OpenShift Virtualization environment uses a secondary or specialized scheduler, in addition to the default
kube-scheduler, to handle specific workload types, you can instruct MTV to apply this custom scheduler name to the target VM’s manifest. This directs the VM to use the specialized logic designed for that workload. This feature is implemented by using the VM target label feature.
By integrating any of these three types of controls into your migration plan, you ensure that the complex scheduling logic required for modern applications is defined upfront, preventing post-migration performance degradation or unexpected scheduling errors.
Any scheduling rule applied in a migration plan applies to all VMs in it.
9.7.4. Scheduling target VMs from the command-line interface Copy linkLink copied to clipboard!
You can use the command-line interface (CLI) to tell Migration Toolkit for Virtualization (MTV) to migrate virtual machines (VMs) to specific nodes or workloads (pods) of OpenShift Virtualization as well as to schedule when the VMs are powered on.
The MTV CLI supports the following scheduling-related labels, all of which are added to the Plan CR:
-
targetAffinity: Implements placement policies such as co-locating related workloads or, for disaster recovery, ensuring that specific VMs are migrated to different nodes. This type of label uses hard (requirements) and soft (preferences) conditions combined with logical operators, such asand,or,andnot, to provide greater flexibility than thetargetLabelSelectorlabel discussed following. -
targetLabels: Applies organizational or operational labels to migrated VMs for identification and management. -
targetNodeSelector: Ensures VMs are scheduled on nodes that are an exact match for key-value pairs you create. This type of label is often used for nodes with special capabilities, such as GPU nodes or storage nodes.
System-managed labels, such as migration, plan, VM ID, or application labels, override any user-defined labels.
Prerequisites
Migrations that use target VM scheduling require the following prerequisites, in addition to the prerequisites for your source provider:
- Migration Toolkit for Virtualization (MTV) 2.10 or later.
- Version of OpenShift Virtualization that is compatible with your version of MTV. For MTV 2.10, the compatible versions of OpenShift Virtualization are 4.18, 4.19, and 4.20 only.
-
cluster-adminor equivalent security privileges that allow managingVirtualMachineInstanceobjects and associated Kubernetes scheduling primitives.
Procedure
- Create custom resources (CR)s for the migration according to the procedure for the provider.
In the
PlanCR, add the following labels beforespec:targetNamespace. All are optional.... targetAffinity: <affinity rule, which can be quite complex, is entered in lines following this label. See example that follows> targetLabels: label: <label> targetNodeSelector: <key>:<value> targetNamespace:<target_namespace> ...Example:
The following scheduling rule migrates the VMs in the plan to different nodes for disaster recovery:
targetLabels:
label: test1
targetAffinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: label
operator: In
values:
- test1
topologyKey: kubernetes.io/hostname
Result
As a result of the preceding rule, the VMs are migrated accordingly to the resulting spec:
spec:
runStrategy: Always
template:
metadata:
creationTimestamp: null
labels:
app: mtv-rhel8-sanity-ceph-rbd
label: test1
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: label
operator: In
values:
- test1
topologyKey: kubernetes.io/hostname
9.7.5. Scheduling target VMs from the user interface Copy linkLink copied to clipboard!
You can use the Migration Toolkit for Virtualization (MTV) user interface, which is located in the Red Hat OpenShift web console, to tell Migration Toolkit for Virtualization (MTV) to migrate virtual machines (VMs) to specific nodes or workloads (pods) of OpenShift Virtualization as well as to schedule when the VMs are powered on.
The Virtualization section of the Red Hat OpenShift web console supports the following options for scheduling target VMs:
- VM target node selector: Ensures VMs are scheduled on nodes that are an exact match for key-value pairs you create. This type of label is often used for nodes with special capabilities, such as GPU nodes or storage nodes.
- VM target labels: Applies organizational or operational labels to migrated VMs for identification and management.
VM target affinity rules: Implements placement policies such as co-locating related workloads or, for disaster recovery, ensuring that specific VMs are migrated to different nodes. This type of rule uses hard (requirements) and soft (preferences) conditions combined with logical operators, such as
ExistsorDoesNotExistinstead of using the rigid key-value pairs used by a VM target node selector. As a result, target affinity rules are more flexible than target node selector rules.The MTV UI supports the following affinity rules:
- Node affinity rules
- Workload (pod) affinity and anti-affinity rules
You configure target VM scheduling options on the Plan details page of the relevant migration plan. The options apply to all VMs that are included in that migration.