Theoretical Foundation: Create a Virtual Machine
1. Initial Intuitionβ
Imagine you need a server to run an application. In the physical world, you would buy hardware, install the operating system, configure the network, and wait days or weeks until everything is ready. In Azure, you describe the server you want (how many CPU cores, how much memory, which operating system, which region of the world) and in minutes it's available.
A Virtual Machine (VM) in Azure is a complete computer running on Microsoft's shared hardware, isolated from other customers through virtualization technology. From the operating system and application perspective, the VM looks like a dedicated physical server. You have complete control: install software, configure services, access the terminal.
The fundamental difference compared to managed services like App Service or Azure Functions is that with VMs you manage the operating system: you're responsible for patches, security updates, and internal configuration.
2. Contextβ
2.1 VMs in the IaaS modelβ
Azure offers different levels of abstraction. VMs are at the IaaS (Infrastructure as a Service) level: you manage from the operating system up; Microsoft manages the physical hardware, physical network, and hypervisor.
2.2 Use cases that require VMsβ
VMs are the right choice when:
- The application wasn't developed for cloud and can't be easily refactored
- You need complete control over the operating system (specific patches, kernel configurations)
- The software requires traditional installation (agents, legacy middleware)
- You're migrating on-premises workloads via lift-and-shift
- The workload requires specific hardware (GPU, HPC)
3. Building the Conceptsβ
3.1 Resources created along with the VMβ
When you create a VM in Azure, the portal automatically creates a set of related resources. Understanding each one is essential for properly managing VMs:
Virtual Machine: The main resource. Represents the compute configuration (CPU, memory, size).
Disk (OS Disk): Every VM has at least one managed disk that contains the operating system. Created automatically.
Network Interface (NIC): The VM's "virtual network card". Connects the VM to the VNet. Has a private IP and optionally a public IP.
Virtual Network (VNet) and Subnet: The private network where the VM lives. Can be created automatically or use an existing VNet.
Network Security Group (NSG): Virtual firewall associated with the NIC or subnet. Controls inbound and outbound traffic.
Public IP Address (optional): Public IP for direct access via internet. Can be static or dynamic.
3.2 VM family and sizeβ
The VM size defines CPU, memory, temporary disk, and network capacity. Sizes are organized in series (families), each optimized for a type of workload:
| Family | Prefix | Optimized for |
|---|---|---|
| General Purpose | B, D, Dv5, Dav5 | Balanced workloads (web, dev, test) |
| Compute Optimized | F, Fx | High CPU/memory ratio (data processing) |
| Memory Optimized | E, Ev5, M | In-memory databases, SAP HANA |
| Storage Optimized | Lsv3 | High disk I/O databases |
| GPU | NC, ND, NV | Machine Learning, 3D rendering |
| High Performance Compute | H | Scientific simulations, CFD |
| Burstable | B | Workloads with variable CPU usage |
The size naming follows a pattern:
Standard_D4s_v5
β β β
β β βββ version (v5 = fifth generation)
β ββββββ s = Premium SSD support
ββββββββ number of vCPUs
3.3 Images: the operating systemβ
An image is the disk template used to create the VM. Azure Marketplace offers thousands of images, including:
First-party images (Microsoft):
- Windows Server 2022, 2019, 2016
- Windows 11 Enterprise (for VDI)
Third-party images (certified):
- Ubuntu 22.04, 20.04, 18.04
- Red Hat Enterprise Linux 8, 9
- CentOS, Debian, SUSE
- SQL Server on Windows/Linux
- Oracle Database
Custom images: You can create your own image from a configured VM (via Azure Compute Gallery).
3.4 Disks: types and performanceβ
Azure offers different types of managed disks with different performance and cost characteristics:
| Type | Use | Max IOPS | Latency | Cost |
|---|---|---|---|---|
| Ultra Disk | Critical databases | Up to 400,000 | Sub-millisecond | Highest |
| Premium SSD v2 | I/O intensive workloads | Up to 80,000 | ~1ms | High |
| Premium SSD | General production | Up to 20,000 | ~1-2ms | Medium-high |
| Standard SSD | Web servers, dev | Up to 6,000 | ~2-10ms | Medium |
| Standard HDD | Backup, files | Up to 2,000 | ~5-50ms | Low |
Temporary Disk: In addition to managed disks, VMs have a temporary disk (D: on Windows, /dev/sdb on Linux) that doesn't persist after deallocation or resizing. Never store permanent data on it.
3.5 Availability optionsβ
VM availability depends on how you organize them. Azure offers three mechanisms:
Availability Set:
- Distributes VMs across Fault Domains (different physical racks) and Update Domains (sequential update groups)
- Protects against hardware failures and Azure maintenance
- 99.95% SLA for two or more VMs in the same Availability Set
Availability Zone:
- Distributes VMs across physically separate datacenters within a region
- Protects against entire datacenter failure
- 99.99% SLA for two or more VMs in different zones
Virtual Machine Scale Sets:
- Creation and management of multiple identical VMs (horizontal scale)
- Auto-scaling based on metrics
- Covered in separate AZ-104 objectives
Isolated VM (no option):
- 99.9% SLA (only for VMs with Premium SSD)
- Suitable only for development and testing
3.6 Licensing and cost optionsβ
Pay-as-you-go: Pay per hour of use. More expensive per hour, but no commitment.
Reserved Instances (RI): 1 or 3-year commitment in exchange for up to 72% discount. For predictable workloads.
Azure Hybrid Benefit: If you have Windows Server or SQL Server licenses with active Software Assurance, you can bring those licenses to Azure, saving the license cost in the VM price.
Spot VMs: Azure's excess capacity at very low prices (up to 90% discount), but the VM can be removed with 30 seconds notice when Azure needs the capacity. Suitable for interruption-tolerant workloads (batch processing, rendering).
4. Structural Viewβ
Critical behavior: Stopping the VM from the operating system ("shutdown" within the OS) puts the VM in Stopped state, but doesn't deallocate. You continue paying for compute allocation. To stop compute billing, use Deallocate through portal, CLI, or PowerShell.
5. Practical Operationβ
5.1 Information needed to create a VMβ
Before creating, you need to decide:
| Decision | Options | Impact |
|---|---|---|
| Region | eastus, westeurope, brazilsouth, etc. | Latency, data compliance, size availability |
| Operating system | Windows Server, Linux (Ubuntu, RHEL, etc.) | License cost, management |
| Size (SKU) | Standard_D2s_v5, Standard_B2ms, etc. | Performance and cost |
| Authentication | Password or SSH key (Linux) | Security |
| VNet/Subnet | New or existing | Connectivity |
| Public IP | None, dynamic or static | Remote access |
| OS disk | Premium SSD, Standard SSD, Standard HDD | Performance and cost |
| Availability | Zone, Availability Set, none | Resilience |
5.2 Cloud-init and Custom Script Extensionβ
To configure the VM automatically during creation without manual interaction, Azure supports:
cloud-init (Linux): YAML or bash script executed on first boot. Ideal for installing packages, configuring services, and running commands.
#cloud-config
package_upgrade: true
packages:
- nginx
- docker.io
runcmd:
- systemctl enable nginx
- systemctl start nginx
Custom Script Extension (Windows and Linux): Script executed after the VM is ready. Can be PowerShell (Windows) or bash (Linux). Can be referenced from a Storage Account or provided inline.
6. Implementation Methodsβ
6.1 Azure Portalβ
When to use: Single creation, learning, when visual exploration of options is necessary.
In portal: Virtual Machines > + Create > Azure Virtual Machine
The portal guides through tabs: Basics, Disks, Networking, Management, Monitoring, Advanced, Tags.
Advantages: Immediate visualization of all parameters, real-time validation, option to see generated ARM template.
Limitation: Not consistently reproducible; slow for multiple VMs.
6.2 Azure CLIβ
Basic Linux VM creation:
az vm create \
--resource-group myRG \
--name myLinuxVM \
--image Ubuntu2204 \
--size Standard_D2s_v5 \
--location eastus \
--admin-username azureuser \
--generate-ssh-keys \
--vnet-name myVNet \
--subnet mySubnet \
--public-ip-sku Standard \
--nsg-rule SSH
Windows VM creation:
az vm create \
--resource-group myRG \
--name myWindowsVM \
--image Win2022Datacenter \
--size Standard_D4s_v5 \
--location eastus \
--admin-username adminuser \
--admin-password "MySecureP@ss123!" \
--nsg-rule RDP \
--public-ip-sku Standard
Creation with Availability Zone:
az vm create \
--resource-group myRG \
--name myVM-Zone1 \
--image Ubuntu2204 \
--size Standard_D2s_v5 \
--zone 1 \
--admin-username azureuser \
--generate-ssh-keys
Creation with cloud-init:
az vm create \
--resource-group myRG \
--name myWebServer \
--image Ubuntu2204 \
--size Standard_D2s_v5 \
--admin-username azureuser \
--generate-ssh-keys \
--custom-data @cloud-init.yaml
Lifecycle operations:
# Stop and deallocate (stops compute billing)
az vm deallocate --resource-group myRG --name myVM
# Start
az vm start --resource-group myRG --name myVM
# Restart
az vm restart --resource-group myRG --name myVM
# Resize (change SKU)
az vm resize --resource-group myRG --name myVM --size Standard_D4s_v5
# View current state
az vm show --resource-group myRG --name myVM --show-details --query powerState
6.3 Azure PowerShellβ
# Create complete VM
$vmConfig = New-AzVMConfig `
-VMName "myVM" `
-VMSize "Standard_D2s_v5"
# Configure OS
$vmConfig = Set-AzVMOperatingSystem `
-VM $vmConfig `
-Linux `
-ComputerName "myVM" `
-Credential (Get-Credential)
# Specify image
$vmConfig = Set-AzVMSourceImage `
-VM $vmConfig `
-PublisherName "Canonical" `
-Offer "0001-com-ubuntu-server-jammy" `
-Skus "22_04-lts-gen2" `
-Version "latest"
# Add NIC
$nic = Get-AzNetworkInterface -Name "myNIC" -ResourceGroupName "myRG"
$vmConfig = Add-AzVMNetworkInterface -VM $vmConfig -Id $nic.Id
# Create the VM
New-AzVM `
-ResourceGroupName "myRG" `
-Location "eastus" `
-VM $vmConfig
6.4 Bicepβ
// Linux VM with all components
resource vm 'Microsoft.Compute/virtualMachines@2023-07-01' = {
name: 'myLinuxVM'
location: location
properties: {
hardwareProfile: {
vmSize: 'Standard_D2s_v5'
}
storageProfile: {
imageReference: {
publisher: 'Canonical'
offer: '0001-com-ubuntu-server-jammy'
sku: '22_04-lts-gen2'
version: 'latest'
}
osDisk: {
createOption: 'FromImage'
managedDisk: {
storageAccountType: 'Premium_LRS'
}
deleteOption: 'Delete'
}
}
osProfile: {
computerName: 'myLinuxVM'
adminUsername: 'azureuser'
linuxConfiguration: {
disablePasswordAuthentication: true
ssh: {
publicKeys: [
{
path: '/home/azureuser/.ssh/authorized_keys'
keyData: sshPublicKey
}
]
}
}
}
networkProfile: {
networkInterfaces: [
{
id: nic.id
properties: {
deleteOption: 'Delete'
}
}
]
}
availabilitySet: {
id: availabilitySet.id
}
}
zones: ['1']
}
deleteOption: The
deleteOption: 'Delete'property on disks and NICs ensures that when the VM is deleted, associated resources are also deleted automatically. Without this, "orphaned" disks and NICs continue to exist and be charged.
7. Control and Securityβ
7.1 Authentication: SSH Keys vs Passwordβ
For Linux VMs: Always use SSH keys in production. Passwords are more vulnerable to brute force attacks.
# Generate SSH key pair locally
ssh-keygen -t rsa -b 4096 -f ~/.ssh/myVM_key
# Public key goes to VM; private key stays on local machine
# Connect via SSH
ssh -i ~/.ssh/myVM_key azureuser@<public-ip>
For Windows VMs: Use strong passwords with:
- Minimum 12 characters
- Uppercase, lowercase, numbers, and symbols
- Don't use common passwords
Azure Key Vault: Store SSH keys and administrator passwords in Azure Key Vault. Avoid storing them in code or repositories.
7.2 RBAC permissions for VMsβ
| Role | Permissions | Use |
|---|---|---|
| Virtual Machine Contributor | Manage VMs but not VNets and storage accounts | Compute administrators |
| Virtual Machine Administrator Login | Login to VM as admin via Azure AD | Privileged access |
| Virtual Machine User Login | Login to VM as standard user via Azure AD | User access |
| Reader | View configurations | Monitoring |
Azure AD Login for VMs: With the AADSSHLoginForLinux or AADLoginForWindows extension, users can login to the VM with their Azure AD credentials, without managing local users.
7.3 JIT (Just-in-Time) VM Accessβ
Microsoft Defender for Cloud offers JIT: management ports (22, 3389) remain closed by default and are opened temporarily only when requested, for the specific requester's IP, for the determined time.
# Enable JIT via CLI
az security jit-policy create \
--resource-group myRG \
--vm-ids <vm-resource-id> \
--name "default" \
--ports '[{"number":22,"protocol":"TCP","allowedSourceAddressPrefix":"*","maxRequestAccessDuration":"PT3H"}]'
8. Decision Makingβ
8.1 Which VM size to chooseβ
| Workload | Recommended Family | Example |
|---|---|---|
| Web server, dev/test | General Purpose | Standard_D2s_v5 |
| Database server | Memory Optimized | Standard_E4s_v5 |
| Data processing, analytics | Compute Optimized | Standard_F4s_v2 |
| High I/O database | Storage Optimized | Standard_L8s_v3 |
| ML training | GPU | Standard_NC6s_v3 |
| Variable workloads (dev, CI/CD) | Burstable | Standard_B2ms |
8.2 Which disk type to chooseβ
| Situation | Disk type | Reason |
|---|---|---|
| Production database | Premium SSD v2 or Ultra Disk | High IOPS, minimal latency |
| Production web server | Premium SSD | Good performance, adequate SLA |
| Development server | Standard SSD | Reduced cost, SSD |
| Backup, archive | Standard HDD | Lowest cost |
| Temporary disk for processing | Temporary Disk (careful!) | Free, but not persistent |
8.3 Static vs dynamic public IPβ
| Situation | Choice | Reason |
|---|---|---|
| DNS pointing to VM | Static public IP | IP doesn't change after reboot |
| VM with Bastion (no direct access) | No public IP | Access via Bastion, no exposure |
| Temporary development environment | Dynamic public IP | Lower cost |
| Production server with external access | Static public IP + Azure Firewall or LB | Stability and protection |
8.4 Availability Set vs Availability Zoneβ
| Requirement | Choice | SLA |
|---|---|---|
| No HA requirement | None | 99.9% |
| HA within single datacenter | Availability Set | 99.95% |
| HA across region datacenters | Availability Zone | 99.99% |
| Maximum resilience | VMs in multiple regions + Traffic Manager | > 99.99% |
9. Best Practicesβ
- Use
deleteOption: Deletefor disks and NICs when creating VMs via IaC. This prevents orphaned resources when the VM is deleted. - Never open SSH/RDP directly from the internet. Use Azure Bastion, JIT, or VPN.
- Use SSH keys for Linux VMs in production, never passwords.
- Enable Azure AD Login to eliminate local user management and leverage MFA and Conditional Access.
- Use Managed Disks (current standard) instead of unmanaged disks (legacy).
- Specify availability zone for production VMs in regions that support Availability Zones.
- Use Reserved Instances for workloads that will run for 1 year or more.
- Enable Azure Monitor and configure CPU, memory, and disk alerts from the start.
- Use tags to identify environment (prod, dev, test), application, responsible team, and cost center.
- Don't store data on temporary disk. Use managed data disks for persistent data.
- Use Azure Hybrid Benefit if you have active Windows Server or SQL Server licenses.
10. Common Errorsβ
| Error | Why it happens | How to avoid |
|---|---|---|
| VM "stopped" but still charging | Stopped by OS, not deallocated | Use az vm deallocate or portal to deallocate |
| Orphaned disk and NIC after deleting VM | deleteOption not configured | Set deleteOption: Delete on creation or delete manually |
| Can't connect via SSH/RDP | NSG blocking port 22/3389 | Check NSG inbound rules |
| Public IP changes after reboot | Dynamic IP used where static was needed | Convert to static public IP |
| Wrong VM size chosen | Didn't consider workload requirements | Size based on expected CPU, memory, and IOPS |
| Admin password forgotten (Windows) | Not documented or stored | Use Azure AD Login or reset via Run Command |
| VM without monitoring configured | Forgot to enable during creation | Enable Azure Monitor Agent after creation |
| Spot VM removed without sufficient warning | Workload not tolerant to interruption on Spot | Use Spot only for tolerant workloads (batch, render) |
11. Operation and Maintenanceβ
11.1 VM Monitoringβ
Azure Monitor VM Insights: Collects CPU, memory, disk, and network metrics with ready-made visualizations.
# Enable Azure Monitor Agent on VM
az vm extension set \
--resource-group myRG \
--vm-name myVM \
--name AzureMonitorLinuxAgent \
--publisher Microsoft.Azure.Monitor \
--version 1.0
Important metrics:
| Metric | Alert threshold | What it indicates |
|---|---|---|
| CPU Percentage | > 80% for 5 min | Need for resize or optimization |
| Available Memory Bytes | < 10% | Memory pressure |
| OS Disk Queue Depth | > 10 | Disk bottleneck |
| Network In/Out | Abnormal spike | Suspicious traffic or saturation |
11.2 VM Resizingβ
# List available sizes in region for resizing
az vm list-vm-resize-options \
--resource-group myRG \
--name myVM \
--output table
# Resize (requires stop and restart)
az vm resize \
--resource-group myRG \
--name myVM \
--size Standard_D4s_v5
Resizing requires VM restart (downtime). Plan maintenance windows.
11.3 Run Command: execute scripts without SSH/RDPβ
If you lost SSH/RDP access, Run Command allows executing scripts on the VM via portal or CLI:
# Execute bash script on Linux VM
az vm run-command invoke \
--resource-group myRG \
--name myVM \
--command-id RunShellScript \
--scripts "echo 'Hello World' && systemctl status nginx"
# Reset admin password (Windows)
az vm user reset-ssh \
--resource-group myRG \
--name myVM
11.4 Important limitsβ
| Resource | Default limit |
|---|---|
| VMs per region per subscription | 10,000 vCPUs (increasable) |
| Data disks per VM | Depends on size (D2s_v5: up to 4; D64s_v5: up to 32) |
| NICs per VM | Depends on size |
| Private IPs per NIC | Up to 30 |
| VMs in Availability Set | Up to 200 |
| Fault Domains per Availability Set | 2 or 3 (region dependent) |
12. Integration and Automationβ
12.1 VM Extensionsβ
Extensions are agents installed on the VM that execute automated tasks:
# Install Custom Script extension (run script after creation)
az vm extension set \
--resource-group myRG \
--vm-name myVM \
--name CustomScript \
--publisher Microsoft.Azure.Extensions \
--settings '{"commandToExecute":"apt-get install -y nginx"}'
# List installed extensions
az vm extension list \
--resource-group myRG \
--vm-name myVM \
--output table
Common extensions:
| Extension | Function |
|---|---|
| CustomScript | Executes custom scripts |
| AzureMonitorLinuxAgent | Collects metrics and logs |
| DependencyAgent | Maps network dependencies (VM Insights) |
| AADSSHLoginForLinux | Azure AD login on Linux |
| AADLoginForWindows | Azure AD login on Windows |
| MicrosoftAntiMalware | Antimalware protection (Windows) |
12.2 Azure Automation with VMsβ
To automatically shutdown VMs outside business hours:
# Configure auto-shutdown via CLI
az vm auto-shutdown \
--resource-group myRG \
--name myVM \
--time 2200 \
--email "admin@company.com"
For more complex automation (start VMs before hours, process multiple VMs), use Azure Automation Runbooks or Azure Functions with schedule trigger.
12.3 Azure Policy for VM complianceβ
# Ensure all VMs use mandatory tags
az policy assignment create \
--name "vm-require-tags" \
--policy "96670d01-0a4d-4649-9c89-2d3abc0a5025" \
--scope "/subscriptions/<sub-id>"
# Audit VMs without Azure Monitor Agent
az policy assignment create \
--name "vm-require-monitoring" \
--policy "5641f9d1-f911-4988-abf4-92c8e0f2af0a" \
--scope "/subscriptions/<sub-id>"
13. Final Summaryβ
Essential concepts:
- An Azure VM is a complete virtual computer (IaaS) where you control the operating system and everything above it.
- When creating a VM, Azure automatically creates: OS disk, NIC, and optionally public IP, NSG, VNet and subnet.
- The size defines CPU, memory and disk capacity. Choose based on workload: General Purpose, Memory Optimized, Compute Optimized, GPU, etc.
- The Stopped state β Deallocated: only Deallocated stops compute billing.
Critical differences:
- Stopped vs Deallocated: Stopped = OS shut down but hardware still allocated (charges compute). Deallocated = hardware released (charges only storage).
- Availability Set vs Availability Zone: Set distributes across racks in same datacenter (99.95%). Zone distributes across datacenters (99.99%).
- Dynamic vs static IP: Dynamic changes when deallocated. Static remains. Use static when DNS or firewall depends on IP.
- Temporary disk vs data disk: Temporary doesn't persist after deallocation. Managed data disk always persists.
What needs to be remembered:
- Use
deleteOption: Deletefor disks and NICs to avoid orphaned resources. - Never open SSH/RDP ports directly from internet. Use Bastion or JIT.
- The temporary disk is on
D:on Windows and/dev/sdbor/mnton Linux, and doesn't persist data after deallocation. - Azure Hybrid Benefit can significantly reduce Windows and SQL Server VM costs.
- Use Reserved Instances for workloads that will run for 1 year or more; savings can reach 72%.
- Spot VMs are economical but can be removed anytime with 30 seconds notice.
- Run Command allows executing scripts on VM without direct SSH/RDP access, useful for access recovery.