Introduction

Oracle Cloud Infrastructure (OCI) offers a robust and flexible platform for provisioning virtual machines (VMs) with customized configurations, including CPU, memory, operating system, network, and security settings. This is made possible by the powerful technology of nested virtualization, which enables bare metal machines to run multiple isolated environments, allowing for efficient resource utilization and shared access for services and users.

Nested virtualization opens up a wide range of possibilities for innovative use cases, such as:

  • Testing and validating configurations before deploying them to production environments, ensuring seamless transitions from development to staging to production VMs.
  • Creating isolated environments for sensitive workloads, such as secure data processing or compliance testing.
  • Developing and testing complex applications that require multiple, interconnected VMs.

In this blog, we will provision a VM (Guest VM) inside an OCI VM (Host VM) using Oracle Linux 9.5. This will demonstrate the flexibility and power of nested virtualization, and provide a foundation for further experimentation and innovation.

KVM Nested Virtualization in OCI Architecture

Requirements

Already provisioned virtual machine (Host) in OCI with:

  • Operating System:
    • Image: Oracle Linux 9
    • Image build: 2025.02.28-0 (This build was available at the time this blog was written, choose the latest one available).
  • Shape: AMD: VM.Standard.E5.Flex or Intel: VM.Standard3.Flex (Ampere VMs (ARM/aarch64) did not support nested virtualization)
    • CPU: 12 OCPUs
    • Memory: 18 GBs
    • Disk space: Boot volume with 100 GBs
  • Network:
    • Virtual Cloud Network (VCN)
    • Subnet
  • Your SSH public key added to the host VM.

The specs above will satisfy Oracle Linux 9 requirements and it will allow to create additional VMs and/or increase/decrease VMs specs if needed:

  • CPU: 2 logical CPUs minimum
  • Memory: 1.5 GB minimum, 1.5 GB per logical CPU recommended
  • Disk space: 10 GB minimum, 20 GB recommended

Guest VM Provisioning

  1. Access the host VM (Example name: lab) using its IP address and your private SSH key:

    [YOUR-USERNAME@YOUR-PERSONAL-COMPUTER ~]$ ssh -i ~/.ssh/id_rsa opc@<OCI_VM_IP_ADDRESS>
    
    The authenticity of host '<OCI_VM_IP_ADDRESS> (<OCI_VM_IP_ADDRESS>)'
    
    ...
    
    Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
    Warning: Permanently added '<OCI_VM_IP_ADDRESS>' (ED25519) to the list of known hosts.
    
    [opc@lab ~]$
  2. Verify which operating system and kernel the VM has:

    [opc@lab ~]$ cat /etc/os-release
    
    NAME="Oracle Linux Server"
    VERSION="9.5"
    ID="ol"
    ID_LIKE="fedora"
    VARIANT="Server"
    VARIANT_ID="server"
    VERSION_ID="9.5"
    PLATFORM_ID="platform:el9"
    PRETTY_NAME="Oracle Linux Server 9.5"
    ANSI_COLOR="0;31"
    CPE_NAME="cpe:/o:oracle:linux:9:5:server"
    HOME_URL="https://linux.oracle.com/"
    BUG_REPORT_URL="https://github.com/oracle/oracle-linux"
    
    ORACLE_BUGZILLA_PRODUCT="Oracle Linux 9"
    ORACLE_BUGZILLA_PRODUCT_VERSION=9.5
    ORACLE_SUPPORT_PRODUCT="Oracle Linux"
    ORACLE_SUPPORT_PRODUCT_VERSION=9.5
    [opc@lab ~]$ uname -r
    
    5.15.0-305.176.4.el9uek.x86_64
  3. Check the host VM disk size (The sda3/ocivolume-root is our boot volume, but it still has the default boot volume size):

    [opc@lab ~]$ lsblk
    
    NAME               MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
    sda                  8:0    0  100G  0 disk
    ├─sda1               8:1    0  100M  0 part /boot/efi
    ├─sda2               8:2    0    2G  0 part /boot
    └─sda3               8:3    0 44.5G  0 part
      ├─ocivolume-root 252:0    0 29.5G  0 lvm  /
      └─ocivolume-oled 252:1    0   15G  0 lvm  /var/oled
    [opc@lab ~]$ df -h
    
    Filesystem                  Size  Used Avail Use% Mounted on
    devtmpfs                    4.0M     0  4.0M   0% /dev
    tmpfs                       8.6G     0  8.6G   0% /dev/shm
    tmpfs                       3.5G  8.8M  3.5G   1% /run
    /dev/mapper/ocivolume-root   30G  9.0G   21G  31% /
    /dev/mapper/ocivolume-oled   15G  156M   15G   2% /var/oled
    /dev/sda2                   2.0G  384M  1.6G  20% /boot
    /dev/sda1                   100M  6.3M   94M   7% /boot/efi
    tmpfs                       1.8G     0  1.8G   0% /run/user/1000
  4. Rescan the VM disks:

    [opc@lab ~]$ sudo dd iflag=direct if=/dev/oracleoci/oraclevda of=/dev/null count=1
        echo "1" | sudo tee /sys/class/block/`readlink /dev/oracleoci/oraclevda | cut -d'/' -f 2`/device/rescan
    
    1+0 records in
    1+0 records out
    512 bytes copied, 0.000365637 s, 1.4 MB/s
    1
  5. Extend the partition of the disk (The available space in the filesystem will increase from 21 GBs to 74 GBs, which is enough to download the Oracle Linux 9.5 ISO, and provide the recommended disk space to the nested virtual machine):

    [opc@lab ~]$ sudo /usr/libexec/oci-growfs -y
    
    Volume Group: ocivolume
    Volume Path: /dev/ocivolume/root
    Mountpoint Data
    ---------------
            mountpoint: /
                source: /dev/mapper/ocivolume-root
        filesystem type: xfs
            source size: 29.4G
                    type: lvm
                    size: 29.5G
        physical devices: ['/dev/sda3']
        physical volumes: ['/dev/sda', '/dev/sda']
        partition number: ['3']
    volume group name: ocivolume
    volume group path: /dev/ocivolume/root
    
    Partition dry run expansion "/dev/sda3" succeeded.
    CHANGE: partition=3 start=4401152 old: size=93325312 end=97726463 new: size=205314015 end=209715166
    
    Expanding partition /dev/sda3: Confirm?  Partition expand expansion "/dev/sda3" succeeded.
    update-partition set to true
    FLOCK: try exec open fd 9, on failure exec exits this program
    FLOCK: /dev/sda: obtained exclusive lock
    resizing 3 on /dev/sda using resize_sfdisk_gpt
    209715200 sectors of 512. total size=107374182400 bytes
    ## sfdisk --unit=S --dump /dev/sda
    label: gpt
    label-id: 93B50681-37AC-4C1A-A734-F34CF87629B1
    device: /dev/sda
    unit: sectors
    first-lba: 34
    last-lba: 97727250
    sector-size: 512
    
    /dev/sda1 : start=        2048, size=      204800, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=2A2320B9-AA64-48A8-8375-FEB666CACB28, name="EFI System Partition"
    /dev/sda2 : start=      206848, size=     4194304, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=3303D07F-1DA0-43A0-B5BE-C899DCBFFF84
    /dev/sda3 : start=     4401152, size=    93325312, type=E6D6D379-F507-44C2-A23C-238F2A3DF928, uuid=89ED5A37-947F-4AA3-A865-7252EE54350A
    padding 33 sectors for gpt secondary header
    max_end=209715166 tot=209715200 pt_end=97726463 pt_start=4401152 pt_size=93325312
    resize of /dev/sda returned 0.
    FLOCK: /dev/sda: releasing exclusive lock
    
    CHANGED: partition=3 start=4401152 old: size=93325312 end=97726463 new: size=205314015 end=209715166
    
    Extending /dev/sda3 succeeded.
    Device /dev/sda3 extended successfully.
    Logical volume /dev/ocivolume/root extended successfully.
    [opc@lab ~]$ lsblk
    
    NAME               MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
    sda                  8:0    0  100G  0 disk
    ├─sda1               8:1    0  100M  0 part /boot/efi
    ├─sda2               8:2    0    2G  0 part /boot
    └─sda3               8:3    0 97.9G  0 part
      ├─ocivolume-root 252:0    0 82.9G  0 lvm  /
      └─ocivolume-oled 252:1    0   15G  0 lvm  /var/oled
    [opc@lab ~]$ df -h
    
    Filesystem                  Size  Used Avail Use% Mounted on
    devtmpfs                    4.0M     0  4.0M   0% /dev
    tmpfs                       8.6G     0  8.6G   0% /dev/shm
    tmpfs                       3.5G  8.8M  3.5G   1% /run
    /dev/mapper/ocivolume-root   83G  9.4G   74G  12% /
    /dev/mapper/ocivolume-oled   15G  172M   15G   2% /var/oled
    /dev/sda2                   2.0G  384M  1.6G  20% /boot
    /dev/sda1                   100M  6.3M   94M   7% /boot/efi
    tmpfs                       1.8G     0  1.8G   0% /run/user/1000
  6. Upgrade the packages in the system to get the latest features and fixes for the current installed packages:

    [opc@lab ~]$ sudo dnf upgrade -y
    
    Ksplice for Oracle Linux 9 (x86_64)                                                                        1.4 MB/s | 3.4 MB     00:02
    Oracle Linux 9 OCI Included Packages (x86_64)                                                               39 MB/s | 141 MB     00:03
    Oracle Linux 9 BaseOS Latest (x86_64)                                                                       22 MB/s |  50 MB     00:02
    Oracle Linux 9 Application Stream Packages (x86_64)                                                         68 MB/s |  50 MB     00:00
    Oracle Linux 9 Addons (x86_64)                                                                             2.0 MB/s | 559 kB     00:00
    Oracle Linux 9 UEK Release 7 (x86_64)                                                                       30 MB/s |  58 MB     00:01
    ...
    ===========================================================================================================================================
    Package                                  Architecture     Version                                       Repository                   Size
    ===========================================================================================================================================
    Installing:
    ...
    Upgrading:
    ...
    
    Complete!
  7. Enable the Oracle Linux 9 KVM utils repository with dnf config-manager:

    [opc@lab ~]$ sudo dnf config-manager --enable ol9_kvm_utils
    [opc@lab ~]$ sudo dnf repolist enabled
    
    repo id                     repo name
    ol9_UEKR7                   Oracle Linux 9 UEK Release 7 (x86_64)
    ol9_addons                  Oracle Linux 9 Addons (x86_64)
    ol9_appstream               Oracle Linux 9 Application Stream Packages (x86_64)
    ol9_baseos_latest           Oracle Linux 9 BaseOS Latest (x86_64)
    ol9_ksplice                 Ksplice for Oracle Linux 9 (x86_64)
    ol9_kvm_utils               Oracle Linux 9 KVM Utilities (x86_64)
    ol9_oci_included            Oracle Linux 9 OCI Included Packages (x86_64)
  8. Install the virtualization packages:

    For x86_64:

    [opc@lab ~]$ sudo dnf group install -y "Virtualization Host" # Only available for x86_64
    [opc@lab ~]$ sudo dnf install -y virt-install virt-viewer

    For aarch64/arm (In case you are using a host that supports virtualization):

    [opc@lab ~]$ sudo dnf install -y qemu-kvm libvirt virt-install virt-viewer
  9. Check which package versions were installed:

    [opc@lab ~]$ sudo dnf list installed qemu-kvm libvirt virt-install virt-viewer
    
    Installed Packages
    libvirt.x86_64                  30:9.0.0-10.el9             @ol9_kvm_utils
    qemu-kvm.x86_64                 30:7.2.0-18.el9             @ol9_kvm_utils
    virt-install.noarch             4.1.0-5.el9                 @ol9_appstream
    virt-viewer.x86_64              11.0-1.el9                  @ol9_appstream
  10. Validate that the host supports virtualization:

    [opc@lab ~]$ sudo virt-host-validate
    
    QEMU: Checking for hardware virtualization                                 : PASS
    QEMU: Checking if device /dev/kvm exists                                   : PASS
    QEMU: Checking if device /dev/kvm is accessible                            : PASS
    QEMU: Checking if device /dev/vhost-net exists                             : PASS
    QEMU: Checking if device /dev/net/tun exists                               : PASS
    QEMU: Checking for cgroup 'cpu' controller support                         : PASS
    QEMU: Checking for cgroup 'cpuacct' controller support                     : PASS
    QEMU: Checking for cgroup 'cpuset' controller support                      : PASS
    QEMU: Checking for cgroup 'memory' controller support                      : PASS
    QEMU: Checking for cgroup 'devices' controller support                     : PASS
    QEMU: Checking for cgroup 'blkio' controller support                       : PASS
    QEMU: Checking for device assignment IOMMU support                         : WARN (No ACPI DMAR table found, IOMMU either disabled in BIOS or not supported by this hardware platform)
    QEMU: Checking for secure guest support                                    : WARN (Unknown if this platform has Secure Guest support)
  11. Start the libvirtd service with full virtualization:

    [opc@lab ~]$ for drv in qemu network nodedev nwfilter secret storage interface;
    do
     sudo systemctl enable virt${drv}d.service
     sudo systemctl enable virt${drv}d{,-ro,-admin}.socket;
     sudo systemctl start virt${drv}d{,-ro,-admin}.socket;
    done
    
    Created symlink /etc/systemd/system/multi-user.target.wants/virtnetworkd.service → /usr/lib/systemd/system/virtnetworkd.service.
    Created symlink /etc/systemd/system/sockets.target.wants/virtnetworkd-ro.socket → /usr/lib/systemd/system/virtnetworkd-ro.socket.
    Created symlink /etc/systemd/system/sockets.target.wants/virtnetworkd-admin.socket → /usr/lib/systemd/system/virtnetworkd-admin.socket.
    Created symlink /etc/systemd/system/multi-user.target.wants/virtnodedevd.service → /usr/lib/systemd/system/virtnodedevd.service.
    Created symlink /etc/systemd/system/sockets.target.wants/virtnodedevd-ro.socket → /usr/lib/systemd/system/virtnodedevd-ro.socket.
    Created symlink /etc/systemd/system/sockets.target.wants/virtnodedevd-admin.socket → /usr/lib/systemd/system/virtnodedevd-admin.socket.
    Created symlink /etc/systemd/system/multi-user.target.wants/virtnwfilterd.service → /usr/lib/systemd/system/virtnwfilterd.service.
    Created symlink /etc/systemd/system/sockets.target.wants/virtnwfilterd-ro.socket → /usr/lib/systemd/system/virtnwfilterd-ro.socket.
    Created symlink /etc/systemd/system/sockets.target.wants/virtnwfilterd-admin.socket → /usr/lib/systemd/system/virtnwfilterd-admin.socket.
    Created symlink /etc/systemd/system/multi-user.target.wants/virtsecretd.service → /usr/lib/systemd/system/virtsecretd.service.
    Created symlink /etc/systemd/system/sockets.target.wants/virtsecretd-ro.socket → /usr/lib/systemd/system/virtsecretd-ro.socket.
    Created symlink /etc/systemd/system/sockets.target.wants/virtsecretd-admin.socket → /usr/lib/systemd/system/virtsecretd-admin.socket.
    Created symlink /etc/systemd/system/multi-user.target.wants/virtstoraged.service → /usr/lib/systemd/system/virtstoraged.service.
    Created symlink /etc/systemd/system/sockets.target.wants/virtstoraged-ro.socket → /usr/lib/systemd/system/virtstoraged-ro.socket.
    Created symlink /etc/systemd/system/sockets.target.wants/virtstoraged-admin.socket → /usr/lib/systemd/system/virtstoraged-admin.socket.
    Created symlink /etc/systemd/system/multi-user.target.wants/virtinterfaced.service → /usr/lib/systemd/system/virtinterfaced.service.
    Created symlink /etc/systemd/system/sockets.target.wants/virtinterfaced-ro.socket → /usr/lib/systemd/system/virtinterfaced-ro.socket.
    Created symlink /etc/systemd/system/sockets.target.wants/virtinterfaced-admin.socket → /usr/lib/systemd/system/virtinterfaced-admin.socket.
  12. Check libvirtd service status:

    [opc@lab ~]$ sudo systemctl list-units --type=socket virt*
    
      UNIT                        LOAD   ACTIVE SUB       DESCRIPTION
      virtinterfaced-admin.socket loaded active listening Libvirt interface admin socket
      virtinterfaced-ro.socket    loaded active listening Libvirt interface local read-only socket
      virtinterfaced.socket       loaded active listening Libvirt interface local socket
      virtnetworkd-admin.socket   loaded active listening Libvirt network admin socket
      virtnetworkd-ro.socket      loaded active listening Libvirt network local read-only socket
      virtnetworkd.socket         loaded active listening Libvirt network local socket
      virtnodedevd-admin.socket   loaded active listening Libvirt nodedev admin socket
      virtnodedevd-ro.socket      loaded active listening Libvirt nodedev local read-only socket
      virtnodedevd.socket         loaded active listening Libvirt nodedev local socket
      virtnwfilterd-admin.socket  loaded active listening Libvirt nwfilter admin socket
      virtnwfilterd-ro.socket     loaded active listening Libvirt nwfilter local read-only socket
      virtnwfilterd.socket        loaded active listening Libvirt nwfilter local socket
      virtqemud-admin.socket      loaded active listening Libvirt qemu admin socket
      virtqemud-ro.socket         loaded active listening Libvirt qemu local read-only socket
      virtqemud.socket            loaded active listening Libvirt qemu local socket
      virtsecretd-admin.socket    loaded active listening Libvirt secret admin socket
      virtsecretd-ro.socket       loaded active listening Libvirt secret local read-only socket
      virtsecretd.socket          loaded active listening Libvirt secret local socket
      virtstoraged-admin.socket   loaded active listening Libvirt storage admin socket
      virtstoraged-ro.socket      loaded active listening Libvirt storage local read-only socket
      virtstoraged.socket         loaded active listening Libvirt storage local socket
    
    LOAD   = Reflects whether the unit definition was properly loaded.
    ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
    SUB    = The low-level unit activation state, values depend on unit type.
    21 loaded units listed. Pass --all to see loaded but inactive units, too.
    To show all installed unit files use 'systemctl list-unit-files'.
  13. Download Oracle Linux 9.5 x86_64 ISO (~12 GB):

    [opc@lab ~]$ mkdir -p isos
    [opc@lab ~]$ wget -P isos https://yum.oracle.com/ISOS/OracleLinux/OL9/u5/x86_64/OracleLinux-R9-U5-x86_64-dvd.iso
    
    --2025-03-13 19:55:42--  https://yum.oracle.com/ISOS/OracleLinux/OL9/u5/x86_64/OracleLinux-R9-U5-x86_64-dvd.iso
    Resolving yum.oracle.com (yum.oracle.com)... 23.62.177.78
    Connecting to yum.oracle.com (yum.oracle.com)|23.62.177.78|:443... connected.
    HTTP request sent, awaiting response... 200 OK
    Length: 12600737792 (12G) [application/octet-stream]
    Saving to: ‘isos/OracleLinux-R9-U5-x86_64-dvd.iso’
    
    OracleLinux-R9-U5-x86_64-dvd.iso             86%[=======================>    ]  10.16G  48.8MB/s    eta 25s
  14. Create the virtual disk for the VM:

    [opc@lab ~]$ mkdir -p disks
    [opc@lab ~]$ qemu-img create -f qcow2 disks/vm1.qcow2 20G
    
    Formatting 'disks/vm1.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=21474836480 lazy_refcounts=off refcount_bits=16

    Note: For this simpified KVM virtualization hands-on, the guest VM will be running in the same block volume as the host OS. This means that they will share the physical disk resources (Block volume performance (VPU) which indicates the amount of performance related resources, such as IOPS/GB and throughput/GB, that a block volume has). If both (Host VM and Guest VM) perform disk-intensive operations concurrently, this sharing can potentially lead to I/O contention.

     

    Target Volume Performance
    VPU
    IOPS
    Throughput (MB/s)
    Balanced/Default (Min)
    10
    3000
    24
    Ultra High Performance (Max)
    120
    11250
    90

     

    For scenarios with more demanding I/O requirements, create and attach new block volumes to the host VM using Logical Volume Manager (LVM) to store the guest VM’s disks.

  15. Install the VM:

    Important flags:

    • --network default: Allows the nested VM to communicate using the host VM preconfigured libvirt default network to communicate with other hosts in the same network, and networks connected to the VM host.
    • --extra-args "console=tty0 console=ttyS0,115200N8": Directs kernel messages to the primary virtual console (tty0). ttyS0 with a baud rate of 115200 bits per second allows you to interact with the VM using a serial console (Very helpful to debug and manage a VM without a graphical interface).
    [opc@lab ~]$ virt-install --name vm1 \
        --memory 2048 \
        --vcpus 2 \
        --location /home/opc/isos/OracleLinux-R9-U5-x86_64-dvd.iso \
        --disk path=/home/opc/disks/vm1.img,size=20 \
        --os-variant ol9.5 \
        --arch x86_64 \
        --virt-type kvm \
        --graphics none \
        --network default \
        --extra-args "console=tty0 console=ttyS0,115200N8" \
        --debug
    
    ...
    
    [    5.782466] systemd[1]: Detected virtualization kvm.
    [    5.782712] systemd[1]: Detected architecture x86-64.
    [    5.782954] systemd[1]: Running in initrd.
    
    Welcome to Oracle Linux Server 9.5 dracut-057-70.git20240819.0.1.el9 (Initramfs)!
    
    [    5.803070] systemd[1]: No hostname configured, using default hostname.
    [    5.803327] systemd[1]: Hostname set to <localhost>.
    [    5.803604] systemd[1]: Initializing machine ID from VM UUID.
    
    ...
    
    Starting installer, one moment...
    anaconda 34.25.5.9-1.0.3.el9 for Oracle Linux 9.5 started.
    * installation log files are stored in /tmp during the installation
    * shell is available on TTY2
    * if the graphical installation interface fails to start, try again with the
    inst.text bootoption to start text installation
    * when reporting a bug add logs from /tmp as separate text/plain attachments
    ================================================================================
    ================================================================================
    Text mode provides a limited set of installation options. It does not offer
    custom partitioning for full control over the disk layout. Would you like to use
    VNC mode instead?
    
    1) Start VNC
    2) Use text mode
    
    Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to
    refresh]:
  16. Press number 2, and press enter (Use text mode):

    Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to
    refresh]: 2
    ================================================================================
    ================================================================================
    Installation
    
    1) [x] Language settings                 2) [x] Time settings
        (English (United States))                (America/New_York timezone)
    3) [!] Installation source               4) [!] Software selection
        (Processing...)                          (Processing...)
    5) [!] Installation Destination          6) [x] Kdump
        (Processing...)                          (Kdump is enabled)
    7) [x] Network configuration             8) [!] Root password
        (Connected: enp1s0)                      (Root account is disabled)
    9) [!] User creation
        (No user will be created)
    
    Please make a selection from the above ['b' to begin installation, 'q' to quit,
    'r' to refresh]:
  17. Press letter r to refresh the text if you still see (Processing...) in any of the numbered options.

  18. Once all options have been processed, press the number of any of the options that have a [!] (You will need to configure these until all numbered options have a [x] after that press the letter b to start the installation):

    Installation
    
    1) [x] Language settings                 2) [x] Time settings
        (English (United States))                (America/New_York timezone)
    3) [x] Installation source               4) [x] Software selection
        (Local media)                            (Server with GUI)
    5) [!] Installation Destination          6) [x] Kdump
        (Automatic partitioning                  (Kdump is enabled)
        selected)
    7) [x] Network configuration             8) [!] Root password
        (Connected: enp1s0)                      (Root account is disabled)
    9) [!] User creation
        (No user will be created)
    
    Please make a selection from the above ['b' to begin installation, 'q' to quit,
    'r' to refresh]: 5
  19. After you have pressed the installation, the OS will start to install the packages:

    Please make a selection from the above ['b' to begin installation, 'q' to quit,
    'r' to refresh]: b
    ================================================================================
    ================================================================================
    Progress
    
    .
    Setting up the installation environment
    Configuring storage
    Creating disklabel on /dev/vda
    Creating xfs on /dev/vda1
    Creating lvmpv on /dev/vda2
    Creating swap on /dev/mapper/ol-swap
    Creating xfs on /dev/mapper/ol-root
    ...
    Running pre-installation scripts
    .
    Running pre-installation tasks
    ....
    Installing.
    Starting package installation process
    Downloading packages
    Preparing transaction from installation source
    Installing libgcc.x86_64 (1/1209)
    Installing fonts-filesystem.noarch (2/1209)
    Installing linux-firmware-whence.noarch (3/1209)
    
    ...
    
    Installation complete
    
    Use of this product is subject to the license agreement found at:
    /usr/share/oraclelinux-release/EULA
    
    Installation complete. Press ENTER to quit:
  20. Press enter, and wait until you see the following text in the terminal:

    ...
    
    Oracle Linux Server 9.5
    Kernel 5.15.0-302.167.6.el9uek.x86_64 on an x86_64
    
    Activate the web console with: systemctl enable --now cockpit.socket
    
    localhost login:
  21. Enter the username, and password that you configured:

    Oracle Linux Server 9.5
    Kernel 5.15.0-302.167.6.el9uek.x86_64 on an x86_64
    
    Activate the web console with: systemctl enable --now cockpit.socket
    
    localhost login: <YOUR_USERNAME>
    Password: <YOUR_PASSWORD>
    [<YOUR_USERNAME>@localhost ~]$
  22. To get out of the nested VM, you can press: Ctrl + Alt gr + +

    [<YOUR_USERNAME>@localhost ~]$ ('Ctrl' + 'Alt gr' + '+')
    [opc@lab ~]$
  23. To list the VMs running use:

    [opc@lab ~]$ virsh list --all
    Id   Name   State
    ----------------------
    1    vm1    running
  24. To get inside of the VM again use (Important: Press enter after the message Escape character is ^] (Ctrl + ]) gets printed in the console):

    [opc@lab ~]$ virsh console vm1 --safe
    
    Connected to domain 'vm1'
    Escape character is ^] (Ctrl + ])
    
    # PRESS ENTER HERE
    
    [<YOUR_USERNAME>@localhost ~]$
  25. From the host VM you can manage this nested VM using virsh:

    • virsh shutdown <VM_NAME>
    • virsh start <VM_NAME>
    • virsh suspend <VM_NAME>
    • virsh resume <VM_NAME>
    • virsh edit <VM_NAME>

    And many other options that can be found in the virsh libvirt documentation.

  26. To install more VMs, first create additional disks by replacing <VM_DISK>:

    [opc@lab ~]$ qemu-img create -f qcow2 disks/<VM_DISK>.qcow2 20G
  27. And finally replace <VM_NAME> and <VM_DISK>:

    [opc@lab ~]$ virt-install --name <VM_NAME> \
        --memory 2048 \
        --vcpus 2 \
        --location /home/opc/isos/OracleLinux-R9-U5-x86_64-dvd.iso \ # Reusing ISO
        --disk path=/home/opc/disks/<VM_DISK>.img,size=20 \
        --os-variant ol9.5 \
        --arch x86_64 \
        --virt-type kvm \
        --graphics none \
        --network default \
        --extra-args "console=tty0 console=ttyS0,115200N8" \
        --debug

Once you have finished with this demo, you can destroy the VMs:

[opc@lab ~]$ virsh destroy <VM_NAME>

Domain '<VM_NAME>' destroyed

Undefine the VMs:

[opc@lab ~]$ virsh undefine <VM_NAME>

Domain '<VM_NAME>' has been undefined

And remove the qcow2 and ISO files:

[opc@lab ~]$ rm -rf /home/opc/{disks,isos}

Conclusion

Provisioning a VM inside another VM in OCI by using nested virtualization is just the beginning of unlocking more complex scenario for building and testing. By leveraging the power of code and automation, you can create, scale, and orchestrate clusters of VMs with ease, allowing you to run and test a wide range of programs in isolated environments. This virtual separation ensures that each VM operates independently, without affecting the others, making it an ideal solution for testing, development, and deployment of applications. Depending on your requirements, you may change the amount of CPU, memory, storage, etc. that the host machine or VM has configured to provision more nested VMs.

For more information