Questions
Azure Storage costs are $30K/month. Implement tiering and lifecycle policies.
The Scenario
Your Azure Storage bill analysis shows:
Storage Account: proddata (60TB total)
├── Hot tier: 60TB ($1,242/month storage + $1,500 transactions)
├── logs/ container: 30TB - 99% older than 30 days
├── backups/ container: 20TB - accessed monthly
├── media/ container: 10TB - frequently accessed
└── No lifecycle policies configured
Total: $30,000/month (including egress and transactions)
Most data is rarely accessed but stored in Hot tier.
The Challenge
Implement a tiered storage strategy with lifecycle management to reduce costs by at least 50% while maintaining required access patterns.
A junior engineer might move everything to Archive tier, delete old data without checking retention requirements, or manually move blobs periodically. These approaches break access patterns, cause compliance violations, or create operational overhead.
A senior engineer analyzes access patterns per container, implements automated lifecycle policies for tier transitions, uses Cool for infrequently accessed data, Archive for compliance/backup data, and sets up access tier tracking in Azure Monitor.
Step 1: Analyze Current Usage
# Get storage account metrics
az monitor metrics list \
--resource /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Storage/storageAccounts/proddata \
--metric "BlobCount,BlobCapacity" \
--interval PT1H \
--start-time 2024-01-01 \
--end-time 2024-01-31
# List blobs with last access time
az storage blob list \
--account-name proddata \
--container-name logs \
--query "[].{name:name,tier:properties.blobTier,lastAccess:properties.lastAccessedOn,size:properties.contentLength}" \
--output table
# Enable last access time tracking
az storage account blob-service-properties update \
--account-name proddata \
--resource-group myRG \
--enable-last-access-tracking trueStep 2: Understand Azure Storage Tiers
| Tier | Storage Cost/GB | Access Cost | Min Duration | Use Case |
|---|---|---|---|---|
| Hot | $0.0184 | Low | None | Frequent access |
| Cool | $0.01 | Medium | 30 days | Monthly access |
| Cold | $0.0036 | Higher | 90 days | Quarterly access |
| Archive | $0.00099 | High + delay | 180 days | Yearly/compliance |
Step 3: Implement Lifecycle Policies
{
"rules": [
{
"enabled": true,
"name": "logs-lifecycle",
"type": "Lifecycle",
"definition": {
"filters": {
"blobTypes": ["blockBlob"],
"prefixMatch": ["logs/"]
},
"actions": {
"baseBlob": {
"tierToCool": {
"daysAfterModificationGreaterThan": 7
},
"tierToCold": {
"daysAfterModificationGreaterThan": 30
},
"tierToArchive": {
"daysAfterModificationGreaterThan": 90
},
"delete": {
"daysAfterModificationGreaterThan": 365
}
}
}
}
},
{
"enabled": true,
"name": "backups-lifecycle",
"type": "Lifecycle",
"definition": {
"filters": {
"blobTypes": ["blockBlob"],
"prefixMatch": ["backups/"]
},
"actions": {
"baseBlob": {
"tierToCool": {
"daysAfterModificationGreaterThan": 1
},
"tierToArchive": {
"daysAfterModificationGreaterThan": 30
},
"delete": {
"daysAfterModificationGreaterThan": 2555
}
}
}
}
},
{
"enabled": true,
"name": "cleanup-snapshots",
"type": "Lifecycle",
"definition": {
"filters": {
"blobTypes": ["blockBlob"]
},
"actions": {
"snapshot": {
"tierToCool": {
"daysAfterCreationGreaterThan": 30
},
"delete": {
"daysAfterCreationGreaterThan": 90
}
}
}
}
}
]
}# Apply lifecycle policy
az storage account management-policy create \
--account-name proddata \
--resource-group myRG \
--policy @lifecycle-policy.jsonStep 4: Bicep Implementation
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: 'proddata'
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
accessTier: 'Hot' // Default tier for new blobs
allowBlobPublicAccess: false
minimumTlsVersion: 'TLS1_2'
}
}
resource blobServices 'Microsoft.Storage/storageAccounts/blobServices@2023-01-01' = {
parent: storageAccount
name: 'default'
properties: {
lastAccessTimeTrackingPolicy: {
enable: true
name: 'AccessTimeTracking'
trackingGranularityInDays: 1
blobType: ['blockBlob']
}
}
}
resource lifecyclePolicy 'Microsoft.Storage/storageAccounts/managementPolicies@2023-01-01' = {
parent: storageAccount
name: 'default'
properties: {
policy: {
rules: [
{
enabled: true
name: 'logs-tier-and-delete'
type: 'Lifecycle'
definition: {
filters: {
blobTypes: ['blockBlob']
prefixMatch: ['logs/']
}
actions: {
baseBlob: {
tierToCool: {
daysAfterLastAccessTimeGreaterThan: 7
}
tierToCold: {
daysAfterLastAccessTimeGreaterThan: 30
}
tierToArchive: {
daysAfterLastAccessTimeGreaterThan: 90
}
delete: {
daysAfterLastAccessTimeGreaterThan: 365
}
}
}
}
}
{
enabled: true
name: 'media-optimization'
type: 'Lifecycle'
definition: {
filters: {
blobTypes: ['blockBlob']
prefixMatch: ['media/']
}
actions: {
baseBlob: {
tierToCool: {
daysAfterLastAccessTimeGreaterThan: 30
}
}
}
}
}
]
}
}
}Step 5: Use Cold Tier for Additional Savings
# Cold tier (new in 2023) offers better economics than Cool for 90+ day retention
# Cold: $0.0036/GB storage, higher access costs
# Cool: $0.01/GB storage, lower access costs
# Break-even: ~2 reads per blob per month
# Move existing blobs to Cold
az storage blob set-tier \
--account-name proddata \
--container-name backups \
--name "backup-2023-01.zip" \
--tier ColdStep 6: Archive Tier for Compliance Data
# Archive tier: $0.00099/GB but requires rehydration
# Rehydration time: Standard (up to 15 hours), High priority (< 1 hour)
# Set blob to Archive
az storage blob set-tier \
--account-name proddata \
--container-name compliance \
--name "audit-2020.zip" \
--tier Archive
# Rehydrate when needed
az storage blob set-tier \
--account-name proddata \
--container-name compliance \
--name "audit-2020.zip" \
--tier Hot \
--rehydrate-priority HighStep 7: Monitor and Optimize
// Alert on unexpected Hot tier growth
resource storageAlert 'Microsoft.Insights/metricAlerts@2018-03-01' = {
name: 'hot-tier-growth-alert'
location: 'global'
properties: {
description: 'Alert when Hot tier capacity grows unexpectedly'
severity: 2
enabled: true
scopes: [storageAccount.id]
evaluationFrequency: 'PT1H'
windowSize: 'PT6H'
criteria: {
'odata.type': 'Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria'
allOf: [
{
name: 'HotCapacityGrowth'
metricName: 'BlobCapacity'
dimensions: [
{
name: 'Tier'
operator: 'Include'
values: ['Hot']
}
]
operator: 'GreaterThan'
threshold: 15000000000000 // 15TB threshold
timeAggregation: 'Average'
}
]
}
actions: [
{
actionGroupId: actionGroup.id
}
]
}
}Cost Calculation
BEFORE:
- All 60TB in Hot tier
- Storage: 60TB × $0.0184 = $1,104/month
- Transactions + egress: ~$28,896/month
- Total: ~$30,000/month
AFTER (with lifecycle policies):
logs/ (30TB):
- 2TB Hot (current week): $37
- 5TB Cool (week 2-4): $50
- 10TB Cold (month 2-3): $36
- 13TB Archive (older): $13
Subtotal: $136
backups/ (20TB):
- 1TB Cool (current month): $10
- 19TB Archive: $19
Subtotal: $29
media/ (10TB):
- 8TB Hot: $147
- 2TB Cool: $20
Subtotal: $167
Storage Total: $332/month (was $1,104)
Transactions reduced ~40%: $17,338
Total: ~$17,670/month
SAVINGS: ~$12,330/month (41% reduction) Lifecycle Policy Decision Guide
| Data Type | Access Pattern | Recommended Tier | Lifecycle Action |
|---|---|---|---|
| Logs | 7-day analysis | Hot → Cool → Archive | Tiered transition |
| Backups | Monthly restore | Cool → Archive | After 30 days |
| Media | Varies | Use last access tracking | Dynamic tiering |
| Compliance | Yearly audit | Archive | Direct to Archive |
Important Considerations
- Minimum storage duration - Early deletion incurs charges
- Rehydration time - Archive needs 1-15 hours
- Access costs - Cool/Cold reads are more expensive
- Last access tracking - Enable for smarter policies
Practice Question
Why is the Cold tier better than Cool tier for data accessed less than once per month?