Skip to main content

Command Palette

Search for a command to run...

OpenShift Virtualization on Azure: Bridging VMs and Containers

Published
5 min read
P

As a associate system administrator I worked on Redhat Linux servers, including user management, permissions, services, and performance monitoring Automated routine administrative tasks using Bash scripting and cron jobs, reducing manual effort by ~30% I am aws certified sysops administrator and Google Certified Cloud Engineer. Determined to transition my career into cloud architect /Cloud Support role


Virtualization has powered IT infrastructure for decades, but the emergence of cloud-native technologies and containerization has revealed the shortcomings of traditional hypervisor-based virtualization. IT teams often juggle disparate tools for managing virtual machines (VMs) and containers, resulting in inefficiencies and complexity.

OpenShift Virtualization, built on KubeVirt, solves this by enabling unified management of VMs and containers inside the same OpenShift cluster. On Microsoft Azure, this means you can run and scale both cloud-native applications and legacy VM-based workloads from one platform.

This guide covers the fundamentals of OpenShift Virtualization, its benefits, and how to deploy it on Azure Red Hat OpenShift (ARO).


Virtualization Options in Modern IT

1. Traditional Virtualization

Uses hypervisors like VMware vSphere, Microsoft Hyper-V, or KVM to abstract hardware resources into VMs. Benefits include consolidation, improved utilization, and workload isolation.

2. Cloud-Based Virtualization

Extends the concept with IaaS offerings such as Azure Virtual Machines, AWS EC2, or GCP Compute Engine. You gain elasticity, global scale, and pay-as-you-go economics.

3. OpenShift Virtualization

Adds VM lifecycle management into Kubernetes through KubeVirt. It unifies VM and container operations inside OpenShift, enabling organizations to:

  • Modernize legacy apps gradually

  • Simplify management with one toolset

  • Optimize resource usage


Benefits of OpenShift Virtualization on Azure

  • Efficiency: Manage VMs and containers in one OpenShift cluster.

  • Scalability: Leverage Kubernetes autoscaling for VM workloads.

  • Security: Built-in RBAC, network policies, and workload isolation.

  • Hybrid Cloud: Extend workloads across on-prem and Azure seamlessly.


Deploying OpenShift Virtualization on Azure

Prerequisites

  1. An Azure Red Hat OpenShift (ARO) cluster.
    Create it via Azure CLI:

     az aro create \
       --resource-group myResourceGroup \
       --name myAROCluster \
       --vnet myVnet \
       --master-subnet myMasterSubnet \
       --worker-subnet myWorkerSubnet
    

    (Cluster provisioning may take ~30 minutes.)

  2. Install oc (OpenShift CLI) and virtctl locally:

     az aro list-credentials --name myAROCluster --resource-group myResourceGroup
     oc login https://api.<cluster_name>.<region>.aroapp.io:6443 -u kubeadmin -p <password>
    
  3. Enable OpenShift Virtualization Operator in your cluster via OperatorHub (web console) or CLI:

     oc apply -f https://github.com/kubevirt/hyperconverged-cluster-operator/releases/latest/download/kubevirt-cr.yaml
    

Creating a Virtual Machine in OpenShift Virtualization

Step 1: Define the VM (YAML Manifest)

Save the following as rhel9-vm.yaml:

apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: rhel9-vm
  labels:
    app: rhel9-vm
spec:
  running: false
  dataVolumeTemplates:
    - metadata:
        name: rhel9-vm-dv
      spec:
        sourceRef:
          kind: DataSource
          name: rhel9
          namespace: openshift-virtualization-os-images
        storage:
          resources:
            requests:
              storage: 30Gi
  template:
    spec:
      domain:
        cpu:
          cores: 2
        resources:
          requests:
            memory: 8Gi
        devices:
          disks:
            - name: rootdisk
              disk:
                bus: virtio
            - name: cloudinitdisk
              disk:
                bus: virtio
          interfaces:
            - name: default
              masquerade: {}
      networks:
        - name: default
          pod: {}
      volumes:
        - name: rootdisk
          dataVolume:
            name: rhel9-vm-dv
        - name: cloudinitdisk
          cloudInitNoCloud:
            userData: |
              #cloud-config
              user: cloud-user
              password: "MySecurePass123"
              chpasswd: { expire: False }

Step 2: Deploy the VM

oc create -f rhel9-vm.yaml

Step 3: Start the VM

virtctl start rhel9-vm

Accessing the VM

  • Web Console (VNC/Serial): OpenShift Console → Virtualization → VirtualMachines → rhel9-vm → "Console".

  • virtctl (CLI):

      virtctl console rhel9-vm
      virtctl vnc rhel9-vm
    
  • SSH: If networking allows, SSH directly into the VM using the credentials defined in cloud-init.


Real-World Use Cases

  1. Application Modernization: Lift-and-shift legacy VMs to Azure OpenShift, then incrementally refactor into containers.

  2. Hybrid Cloud: Standardize operations across on-prem OpenShift clusters and Azure ARO.

  3. Dev/Test Environments: Spin up complex app stacks mixing VMs and containers in minutes.

  4. VM-Only Clusters: Deploy dedicated OpenShift clusters for VMs as a VMware alternative.


Terraform Deployment of ARO with OpenShift Virtualization

1. Prerequisites

  • Terraform installed (>= v1.4)

  • Azure CLI logged in:

      az login
      az account set --subscription "<your_subscription_id>"
    
  • Resource group + networking prepared OR provisioned by Terraform


2. Terraform Configuration

Save the following as main.tf:

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>3.95"
    }
  }
}

provider "azurerm" {
  features {}
}

# ----------------------------
# Variables
# ----------------------------
variable "location" {
  default = "eastus"
}

variable "resource_group_name" {
  default = "aro-rg"
}

variable "cluster_name" {
  default = "aro-cluster"
}

variable "vnet_name" {
  default = "aro-vnet"
}

variable "master_subnet_name" {
  default = "aro-master-subnet"
}

variable "worker_subnet_name" {
  default = "aro-worker-subnet"
}

# ----------------------------
# Resource Group
# ----------------------------
resource "azurerm_resource_group" "aro" {
  name     = var.resource_group_name
  location = var.location
}

# ----------------------------
# Networking
# ----------------------------
resource "azurerm_virtual_network" "aro_vnet" {
  name                = var.vnet_name
  address_space       = ["10.0.0.0/16"]
  location            = var.location
  resource_group_name = azurerm_resource_group.aro.name
}

resource "azurerm_subnet" "master" {
  name                 = var.master_subnet_name
  resource_group_name  = azurerm_resource_group.aro.name
  virtual_network_name = azurerm_virtual_network.aro_vnet.name
  address_prefixes     = ["10.0.0.0/24"]
  service_endpoints    = ["Microsoft.ContainerRegistry"]
}

resource "azurerm_subnet" "worker" {
  name                 = var.worker_subnet_name
  resource_group_name  = azurerm_resource_group.aro.name
  virtual_network_name = azurerm_virtual_network.aro_vnet.name
  address_prefixes     = ["10.0.1.0/24"]
  service_endpoints    = ["Microsoft.ContainerRegistry"]
}

# ----------------------------
# Azure Red Hat OpenShift Cluster
# ----------------------------
resource "azurerm_redhat_openshift_cluster" "aro_cluster" {
  name                = var.cluster_name
  resource_group_name = azurerm_resource_group.aro.name
  location            = var.location

  cluster_profile {
    domain      = "aroexample"
    version     = "4.14.16"
    resource_group_id = azurerm_resource_group.aro.id
  }

  master_profile {
    vm_size      = "Standard_D8s_v3"
    subnet_id    = azurerm_subnet.master.id
    encryption_at_host_enabled = true
  }

  worker_profile {
    vm_size      = "Standard_D4s_v3"
    subnet_id    = azurerm_subnet.worker.id
    disk_size_gb = 128
    count        = 3
  }

  network_profile {
    pod_cidr     = "10.128.0.0/14"
    service_cidr = "172.30.0.0/16"
  }

  tags = {
    Environment = "Dev"
    Owner       = "Terraform"
  }
}

# ----------------------------
# Output login info
# ----------------------------
output "console_url" {
  value = azurerm_redhat_openshift_cluster.aro_cluster.console_profile[0].url
}

output "api_server_url" {
  value = azurerm_redhat_openshift_cluster.aro_cluster.apiserver_profile[0].url
}

3. Apply Terraform

terraform init
terraform plan
terraform apply -auto-approve

⏳ Cluster creation takes ~30–40 minutes.


4. Configure OpenShift Virtualization (Post-Provision)

Once the ARO cluster is ready:

  1. Get login credentials:

     az aro list-credentials \
       --name aro-cluster \
       --resource-group aro-rg
    
  2. Login to OpenShift:

     oc login https://api.<cluster_name>.<region>.aroapp.io:6443 \
       -u kubeadmin -p <password>
    
  3. Enable OpenShift Virtualization Operator (via CRD):

    Save as hco-cr.yaml:

     apiVersion: hco.kubevirt.io/v1beta1
     kind: HyperConverged
     metadata:
       name: kubevirt-hyperconverged
       namespace: openshift-cnv
     spec:
       infra:
         nodePlacement: {}
       workloads:
         nodePlacement: {}
    

    Apply it:

     oc create namespace openshift-cnv
     oc apply -f hco-cr.yaml
    
  4. Verify the operator installation:

     oc get pods -n openshift-cnv
    

You should see pods like virt-operator, virt-controller, and virt-handler running.


5. Deploy a VM (Optional)

You can now use the earlier RHEL9 VM manifest (rhel9-vm.yaml) and start it:

oc create -f rhel9-vm.yaml
virtctl start rhel9-vm

✅ With this setup:

  • Terraform provisions the ARO cluster on Azure.

  • OpenShift Virtualization is enabled via HyperConverged CR.

  • You can deploy and manage VMs + containers side-by-side.

Conclusion:

✅ With Azure Red Hat OpenShift + OpenShift Virtualization, enterprises can unify VM and container workloads, optimize resources, and accelerate digital transformation—without needing separate management stacks.