5 min read
Azure Cost Optimization Tips for 2023
As we head into 2023, cost optimization is top of mind. Here are practical tips to reduce your Azure spend without sacrificing performance.
Quick Wins
1. Stop Unused Resources
# Find and deallocate stopped VMs that are still incurring charges
az vm list --query "[?powerState!='VM running'].{Name:name, RG:resourceGroup, State:powerState}" -o table
# Deallocate to stop charges
az vm deallocate --resource-group $RG --name $VM_NAME
# Delete unused disks
az disk list --query "[?diskState=='Unattached'].{Name:name, RG:resourceGroup, Size:diskSizeGb}" -o table
# Delete unattached public IPs
az network public-ip list --query "[?ipConfiguration==null].{Name:name, RG:resourceGroup}" -o table
2. Right-Size VMs
from azure.mgmt.monitor import MonitorManagementClient
from azure.mgmt.compute import ComputeManagementClient
def get_rightsizing_recommendations(subscription_id: str):
"""Analyze VMs and suggest right-sizing."""
compute_client = ComputeManagementClient(credential, subscription_id)
monitor_client = MonitorManagementClient(credential, subscription_id)
recommendations = []
for vm in compute_client.virtual_machines.list_all():
# Get CPU metrics
cpu_metrics = monitor_client.metrics.list(
vm.id,
metricnames="Percentage CPU",
aggregation="Average",
timespan="P7D"
)
avg_cpu = calculate_average(cpu_metrics)
current_size = vm.hardware_profile.vm_size
if avg_cpu < 20:
recommendations.append({
"vm": vm.name,
"current_size": current_size,
"avg_cpu": f"{avg_cpu:.1f}%",
"recommendation": "Downsize or use B-series",
"potential_savings": "40-60%"
})
return recommendations
3. Use Spot VMs for Fault-Tolerant Workloads
resource spotVmss 'Microsoft.Compute/virtualMachineScaleSets@2022-03-01' = {
name: 'spot-vmss'
location: location
sku: {
name: 'Standard_D4s_v3'
tier: 'Standard'
capacity: 10
}
properties: {
virtualMachineProfile: {
priority: 'Spot'
evictionPolicy: 'Deallocate'
billingProfile: {
maxPrice: -1 // Pay up to on-demand price
}
}
// ... other config
}
}
Storage Optimization
Use Appropriate Tiers
# Storage tier recommendations based on access patterns
def recommend_storage_tier(
access_frequency: str,
retention_days: int
) -> str:
"""Recommend storage tier based on access patterns."""
if access_frequency == "frequent":
return "Hot"
elif access_frequency == "monthly":
if retention_days > 30:
return "Cool"
return "Hot"
elif access_frequency == "quarterly":
return "Cool"
elif access_frequency == "yearly" or retention_days > 180:
return "Archive"
else:
return "Cool"
# Lifecycle management policy
lifecycle_policy = {
"rules": [
{
"name": "moveToCoool",
"enabled": True,
"type": "Lifecycle",
"definition": {
"filters": {"blobTypes": ["blockBlob"]},
"actions": {
"baseBlob": {
"tierToCool": {"daysAfterModificationGreaterThan": 30},
"tierToArchive": {"daysAfterModificationGreaterThan": 90},
"delete": {"daysAfterModificationGreaterThan": 365}
}
}
}
}
]
}
Optimize Cosmos DB
// Use serverless for variable workloads
var cosmosClientOptions = new CosmosClientOptions
{
// Enable content response on write = false to reduce RU consumption
EnableContentResponseOnWrite = false,
// Use Direct mode for better performance
ConnectionMode = ConnectionMode.Direct
};
// Efficient queries reduce RU consumption
var query = new QueryDefinition(
"SELECT c.id, c.name FROM c WHERE c.partitionKey = @pk")
.WithParameter("@pk", partitionKey);
// Use point reads when possible (1 RU vs query cost)
var response = await container.ReadItemAsync<Item>(id, new PartitionKey(pk));
Reserved Instances
# Analyze reservation opportunities
def analyze_reservation_savings(usage_data: dict) -> dict:
"""Calculate potential savings from reserved instances."""
vm_usage = usage_data.get("virtual_machines", [])
recommendations = []
total_savings = 0
for vm in vm_usage:
if vm["uptime_percentage"] > 70: # Good candidate for reservation
current_monthly = vm["monthly_cost"]
# Reservation savings estimates
one_year_savings = current_monthly * 0.20 * 12
three_year_savings = current_monthly * 0.40 * 36
recommendations.append({
"vm_size": vm["size"],
"quantity": vm["count"],
"current_monthly": current_monthly,
"1yr_reservation_monthly": current_monthly * 0.80,
"3yr_reservation_monthly": current_monthly * 0.60,
"1yr_total_savings": one_year_savings,
"3yr_total_savings": three_year_savings
})
total_savings += three_year_savings
return {
"recommendations": recommendations,
"total_potential_savings": total_savings
}
Dev/Test Optimization
// Use Azure Dev/Test pricing for non-production
// Requires Visual Studio subscription
// Schedule resources to stop outside business hours
resource automationAccount 'Microsoft.Automation/automationAccounts@2021-06-22' = {
name: 'automation-account'
location: location
properties: {
sku: {
name: 'Basic'
}
}
}
resource stopVmsSchedule 'Microsoft.Automation/automationAccounts/schedules@2021-06-22' = {
parent: automationAccount
name: 'stop-dev-vms'
properties: {
startTime: '2023-01-01T18:00:00Z'
expiryTime: '2024-12-31T18:00:00Z'
interval: 1
frequency: 'Day'
timeZone: 'Pacific Standard Time'
}
}
resource startVmsSchedule 'Microsoft.Automation/automationAccounts/schedules@2021-06-22' = {
parent: automationAccount
name: 'start-dev-vms'
properties: {
startTime: '2023-01-01T08:00:00Z'
expiryTime: '2024-12-31T08:00:00Z'
interval: 1
frequency: 'Day'
advancedSchedule: {
weekDays: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
}
timeZone: 'Pacific Standard Time'
}
}
Network Optimization
# Network cost reduction strategies
network_optimization:
reduce_egress:
- Use CDN for static content
- Deploy resources in same region
- Use private endpoints instead of public
- Compress data before transfer
use_azure_cdn:
benefits:
- Reduced egress from origin
- Better performance
- Lower latency
private_endpoints:
benefits:
- No public IP costs
- No egress through internet
- Better security
Monitoring and Alerting
// Set up cost alerts
resource costAlert 'Microsoft.CostManagement/alerts@2022-10-01' = {
name: 'daily-cost-spike'
properties: {
definition: {
type: 'ActualCost'
threshold: 1000
timeframe: 'TheLastDay'
}
notification: {
contactEmails: ['finops@company.com']
contactRoles: ['Owner']
}
}
}
// Anomaly detection
resource anomalyAlert 'Microsoft.Insights/scheduledQueryRules@2022-06-15' = {
name: 'cost-anomaly-detection'
location: location
properties: {
enabled: true
evaluationFrequency: 'PT1H'
windowSize: 'PT1H'
criteria: {
allOf: [
{
query: '''
AzureDiagnostics
| where Category == "Costs"
| summarize HourlyCost = sum(Cost) by bin(TimeGenerated, 1h)
| where HourlyCost > threshold_value
'''
timeAggregation: 'Total'
threshold: 0
operator: 'GreaterThan'
}
]
}
actions: {
actionGroups: [costAlertActionGroup.id]
}
}
}
Cost Optimization Checklist
weekly:
- [ ] Review Azure Advisor recommendations
- [ ] Check for unused resources
- [ ] Monitor budget alerts
monthly:
- [ ] Review cost by resource group/tag
- [ ] Analyze VM utilization
- [ ] Check storage tier usage
- [ ] Review data transfer costs
quarterly:
- [ ] Evaluate reservation opportunities
- [ ] Review architectural efficiency
- [ ] Assess new Azure pricing options
- [ ] Benchmark against targets
Conclusion
Cost optimization is an ongoing practice, not a one-time project. The combination of right-sizing, reservations, storage optimization, and operational discipline can reduce Azure spend by 30-50% without impacting performance. Make it a regular part of your cloud operations.