CAFfe Zeit

Alles rund um das Microsoft Cloud Adoption Framework.
de en

Cost Management - Azure RI vs. Saving Plans

2023-10-05 Niels Ophey

Immer wieder gibt es die Diskussion sind die Azure Reserved Instances (RI) oder der Azure Saving Plan (SP) die bessere Option für den Betrieb einer Applikation auf Basis von IaaS in Azure. Es gibt nicht die eine Antwort auf diese Frage. Im folgenden werden die beiden Optionen Reserved Instance und Saving Plan gegen übergestellt und anhand von Szenarien bewertet.

Kurze Begriffsklärung:

Azure Reserved Instance

Bei einer Reserved Instance handelt es sich im ein Commitment für einer Bestimmte VM in einer bestimmten Region für eine bestimmte Zeit. Also z.B. eine D8s_v5 VM in Westeuropa für drei Jahre. Diese Reservierung kann dann monatlich über 3 Jahre gezahlt werden und bietet ein Rabat von bis zu 72%. In diesem konkreten Beispiel liegt der Preisvorteil bei ~62% Rabatt. Wichtig dabei ist, die Reservierung muss bezahlt werden, egal ob Sie genutzt wird oder nicht. Auf MS Learn findet mal unter folgendem Link eine detaillierte Dokumentation zu dem Thema: Kostensparen mit reservierten Azure-VM-Instanzen

Azure Saving Plan

Bei einem Savin Plan wird im Gegensatz zu einer Reserved Instance nicht eine konkrete VM in einer konkreten Region reserviert, sondern nur eine Summe EUR an Compute. Dies kann dann flexibel für unterschiedliche VMs oder auch andere Compute Services genutzt werden. Die reservierte Summe wird dann monatlich abgerechnet, egal ob Sie vollständig genutzt wurde oder nicht. Sollte man mehr verbrauchen, als man committet hat, wird zum Pay-as-you-go Preis abgerechnet. Zu den Saving Plans ist die Dokumentation an folgender Stelle: Was sind Azure-Sparpläne für Compute?

Szenarios

Um eine mögliche gute Vergleichbarkeit zu bekommen, gehen wir von folgenden Szenarien aus und bewerten die Kosten der jeweiligen Lösung. Stellen wir uns vor wir haben ein Zeiterfassungssystem. Dieses System wird primär in den Zeiten zwischen 6:00 Uhr und 18:00 Uhr benötigt.

  • Szenario A: Der Workload läuft 12 Stunden am Tag und könnte theoretisch komplett abgeschaltet werden in den anderen 12 Stunden
  • Szenario B: Der Workload läuft 12 Stunden am Tag, muss aber in den anderen 12 Stunden weiterhin verfügbar sein, gern aber mit weniger Leistung.
  • Szenario C: Der Workload läuft nur 21 Werktage 12 Stunden und könnte in der restlichen Zeit durch eine leistungsschwächere VM ersetzt werden.
Annahme Wert Einheit
Kalkulatorische Stunden pro Monat 730 Stunden
30 Tage 6:00 - 18:00 Uhr 360 Stunden
21 Arbeitstage 6:00 - 18:00 Uhr 252 Stunden

Als Basis für die VM-Preise wurden die Daten aus dem Azure Preiskalkulator genommen (Region “westeurope”):

VM Type Pay-as-you-go (PAYG) RI SP
D8s_v5 0,438 EUR/h 0,166 EUR/h 0,240 EUR/h
D4s_v5 0,213 EUR/h 0,083 EUR/h 0,0120 EUR/h
B4s_v2 0,183 EUR/h 0,069 EUR/h 0,097 EUR/h

Alle Preise sind nur der Compute-Preis, also ohne Betriebssystemkosten. Preisrechner vom 10/05/2023.

Szenario A

Wenn das Zeiterfassungssystem wirklich komplett ausgeschaltet werden könnte in den Zeiten, wo es nicht genutzt wird, ergeben sich folgende Preise in einem Monat für die VM:

Konstellation Preis
VM D8s_v5 als RI 121,18 EUR/Monat
VM D8s_v5 30 Tage 12 Stunden/Tag (PAYG) 157,68 EUR/Monat
VM D8s_v5 21 Tage 12 Stunden/Tag (PAYG) 110,38 EUR/Monat

Damit wird klar, dass es sich nur dann lohnen würde, den Pay-as-you-go Preis zu nehmen, wenn wir in den Bereich von 21 Tagen 12h am Tag kommen. Der RI-Rabatt von 62% auf den Pay-as-you-go Preis der VM zahlt sich ab ~350 Stunden Betriebszeit der VM aus.

Szenario B

Der Workload läuft 12 Stunden am Tag, muss aber in den anderen 12 Stunden weiterhin verfügbar sein, gern aber mit weniger Leistung.

Wenn alles im PAYG-Preis abgebildet wird und 12 Stunde eine D8s_v5 und 12 Stunden eine D4s_v5 genutzt werden:

VM-Größe Preis
D8s_v5 157,68 EUR/Monat
D4s_v5 81,03 EUR/Monat
Summe Workload 238,71 EUR/Monat
Differenz zur RI + 97%

Wenn alle Preise über einen Saving Plan abgedeckt werden:

VM-Größe Preis
D8s_v5 86,40 EUR/Monat
D4s_v5 44,40 EUR/Monat
Summe Workload 130,80 EUR/Monat
Differenz zur RI + 8%

Wenn alle Preise über einen Saving Plan abgedeckt werden und als Downsizing VM kann eine B-Series verwendet werden:

VM Größe Preis
D8s_v5 86,40 EUR/Monat
B4s_v2 35,89 EUR/Monat
Summe Workload 122,29 EUR/Monat
Differenz zur RI + 0,92%

Damit sind wir schon fast auf dem Preis einer RI.

Szenario C

Der Workload läuft nur 21 Werktage 12 Stunden und könnte in der restlichen Zeit durch eine leistungsschwächere VM ersetzt werden.

Wenn alles im PAYG-Preis abgebildet wird und 21 Arbeitstage für 12 Stunde eine D8s_v5 genutzt wird. In den restlichen Stunden wird dann auf eine D4s_v5 verändert:

VM-Größe Preis
D8s_v5 110,37 EUR/Monat
D4s_v5 104,68 EUR/Monat
Summe Workload 215,05 EUR/Monat
Differenz zur RI + 77%

Wenn alle Preise über einen Saving Plan abgedeckt werden:

VM-Größe Preis
D8s_v5 60,48 EUR/Monat
D4s_v5 57,36 EUR/Monat
Summe Workload 117,84 EUR/Monat
Differenz zur RI - 2,8%

Dann noch erweitert um eine B-Serie VM anstatt der D4s_v5 im Saving Plan:

VM-Größe Preis
D8s_v5 60,48 EUR/Monat
B4s_v2 46,37 EUR/Monat
Summe Workload 106,85 EUR/Monat
Differenz zur RI - 11,8%

Die letzten beiden Konstellationen erzeugen eine Ersparnis gegenüber der reinen RI für eine VM Größe.

Wenn man die Betrachtung nicht nur mit dem reinen Compute macht, sondern auch die Windows Lizenzen mit einkalkuliert verändert sich das Bild deutlich. Dann wird schon PAYG 30 Tage 12 Stunden in Benutzung ansonsten aus mit der gleichen VM-Größe günstiger als eine RI der gleichen VM Größe.

Konstellation Hochrechnung
RI D8s_v5 376,68 EUR/Monat
PAYG 30 Tage 12 Stunden 291,56 EUR/Monat
PAYG 21 Tage 12 Stunden 198,58 EUR/Monat

Inkl. Betriebssystem und ausgeschaltet, wenn nicht benötigt.

Konstellation Szenario B Szenario C
D8s_v5 + D4s_v5 PAYG 429,46 EUR/Monat 386,91 EUR/Monat
D8s_v5 + D4s_v5 SP 321,55 EUR/Monat 289,69 EUR/Monat
D8s_v5 + B4s_v2 SP 253,84 EUR/Monat 202,22 EUR/Monat

In der Spitze erreicht man eine Ersparnis von über 46% gegenüber der Rerserved Instance. Hier spielt der Vorteil im Preis für das OS bei einer B-Series VM die entscheidende Rolle.

Umsetzung

Um dies auch mal praktisch umzusetzen ist hier ein kurzes Beispiel der Umsetzung.

Deployment einer VM

Der bicep-Code um eine VM bereitzustellen kann hier heruntergeladen werden oder direkt hier kopiert werden:

@description('Location to deploy the vNet and the VM')
param location string = 'westeurope'

@description('Name of the VM')
param vmName string = 'vm-sizingdemo01'

@description('Admin username for the VM')
param adminUsername string = 'demouser'

@description('Admin password for the VM')
@secure() 
param adminPassword string = 'Pass!word123'

@description('Name of the vNet')
param vnetName string = 'vnet-sizingdemo'

@description('Name of the subnet')
param subnetName string = 'snet-sizingdemo'

@description('Name of the automation account')
param automationAccountName string = 'aa-sizingdemo'


resource vnet 'Microsoft.Network/virtualNetworks@2020-11-01' = {
  name: vnetName
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        '10.0.0.0/16'
      ]
    }
    subnets: [
      {
        name: subnetName
        properties: {
          addressPrefix: '10.0.0.0/24'
        }
      }
    ]
  }
}

resource publicIp 'Microsoft.Network/publicIPAddresses@2020-11-01' = {
  name: '${vmName}-pip'
  location: location
  properties: {
    publicIPAllocationMethod: 'Dynamic'
  }
}

resource nic 'Microsoft.Network/networkInterfaces@2020-11-01' = {
  name: '${vmName}-nic'
  location: location
  properties: {
    ipConfigurations: [
      {
        name: 'ipconfig'
        properties: {
          subnet: {
            id: vnet.properties.subnets[0].id
          }
          publicIPAddress: {
            id: publicIp.id
          }
        }
      }
    ]
  }
}

resource vm 'Microsoft.Compute/virtualMachines@2020-12-01' = {
  name: vmName
  location: location
  dependsOn: [
    nic
  ]
  properties: {
    hardwareProfile: {
      vmSize: 'Standard_D8s_v5'
    }
    storageProfile: {
      imageReference: {
        publisher: 'MicrosoftWindowsServer'
        offer: 'WindowsServer'
        sku: '2019-Datacenter'
        version: 'latest'
      }
      osDisk: {
        name: '${vmName}-osdisk'
        caching: 'ReadWrite'
        createOption: 'FromImage'
        diskSizeGB: 128
      }
    }
    osProfile: {
      computerName: vmName
      adminUsername: adminUsername
      adminPassword: adminPassword
    }
    networkProfile: {
      networkInterfaces: [
        {
          id: nic.id
        }
      ]
    }
  }
}

resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' = {
  name: automationAccountName
  location: location
  properties: {
    sku: {
      name: 'Basic'
    }
  }
}

Die Parameter sollten nach eigenen Vorstellungen angepasst werden, insbesondere das Kennwort für den administrativen Zugang. Im Azure Portal ist dann folgendes bereitgestellt:

Azure Resourcegroup

Automation Account

Der Automation Account braucht dann noch eine Berechtigung, um auf der Subscription oder Resourcegroup die VM in der Größe verändern zu können. Dazu ist in diesem Beispiel der Automation Account “aa-sizimgdemo” mit einer System Assigned Identity und dem entsprechendem Azure Role Assignment versehen worden (vgl. MS Learn):

Azure Automation Account

Runbook erstellen und mit einem Schedule verbinden

Das Runbook auf Basis von Powershell zum Verändern der VM-Größe in diesem beschriebenen Szenario würde dann wie folgt aussehen:

# Set variables
$resourceGroup = "rg-sizingdemo"
$vm = "vm-sizingdemo01"
# Set desired VM-Sizes
$normalsize = "Standard_D8s_v5"
$smallersize = "Standard_B4s_v2"

# login to Azure

# Ensures you do not inherit an AzContext in your runbook
Disable-AzContextAutosave -Scope Process

# Connect to Azure with system-assigned managed identity
Connect-AzAccount -Identity

# check if the desired VM size is available
$availableSizes = Get-AzVMSize  -ResourceGroupName $resourceGroup -VMName $vm | Select-Object -ExpandProperty Name

if($availableSizes -notcontains $normalsize) {
    Write-Host "The desired normal VM size is not available."
    exit 1
}

if($availableSizes -notcontains $smallersize) {
    Write-Host "The desired smaller VM size is not available."
    exit 1
}

# Check current Size
$updatevm = Get-AzVM -ResourceGroupName $resourceGroup -Name $vm

$actualsize = $updatevm.HardwareProfile.VmSize

Write-Host "Current Size is $actualsize"

$targetsize = ($actualsize -eq $normalsize) ? $smallersize : $normalsize

# Deallocate the VM
Stop-AzVM -ResourceGroupName $resourceGroup -Name $vm -StayProvisioned -Force 
Write-Host "The VM is deallocated."

Write-Host "Target Size is $targetsize"
$updatevm.HardwareProfile.VmSize = $targetsize

# Resize the VM
Update-AzVM -ResourceGroupName $resourceGroup -VM $updatevm
Write-Host "New Size is $targetsize"

# Start the VM
Start-AzVM -ResourceGroupName $resourceGroup -Name $vm
Write-Host "The VM is started."

HINWEIS: Mitlerweile gibt es eine Extension für VisualStudio Code um sowohl das Runbook als auch den Schedule und die komplette Konfiguraiton direkt in VSCode zu machen.

Der Schedule wurde auf exemplarisch alle 12 Stunden gestellt:

{
    "id": "/subscriptions/<YOURSUBSCRIPTION>/resourceGroups/rg-sizingdemo/providers/Microsoft.Automation/automationAccounts/aa-sizingdemo/schedules/Resizing",
    "name": "Resizing",
    "type": "Microsoft.Automation/AutomationAccounts/Schedules",
    "startTime": "2023-10-06T16:00:00.000Z",
    "startTimeOffsetMinutes": 120,
    "expiryTime": "9999-12-31T23:59:59.999Z",
    "expiryTimeOffsetMinutes": 0,
    "isEnabled": true,
    "nextRun": "2023-10-06T16:00:00.000Z",
    "nextRunOffsetMinutes": 120,
    "interval": 12,
    "frequency": "Hour",
    "timeZone": "Europe/Berlin",
    "advancedSchedule": null,
    "creationTime": "2023-10-06T08:45:43.643Z",
    "lastModifiedTime": "2023-10-06T08:45:43.643Z",
    "description": ""
}

HINWEIS: Es handelt sich nur um eine exemplarische Umsetzung. Für den produktiven Betireb empfielt sich eine Lösung, die das Resizing z.B. anhand von Tags automatisiert die VMs in der Größe anpasst, damit nicht für jede VM ein Script aufgesetzt werden muss. Beispiele dafür finden sich in der Runbook Gallery direkt im Azure Portal aufrufbar oder auf Github. Siehe auch aka.ms/AzureAutomationGitHub