Chapter 4: Storage

Azure Storage is the foundation for persisting data in the cloud. It is durable (99.999999999%, eleven nines), highly available, and massively scalable.

Storage Account

Almost all Azure storage services live inside a Storage Account. It is the top-level namespace and billing unit.

# Create a general-purpose v2 storage account (recommended default)
az storage account create \
  --name mystorageacct \
  --resource-group myapp-rg \
  --location eastus \
  --sku Standard_LRS \
  --kind StorageV2 \
  --access-tier Hot

Redundancy Options

SKUFull NameCopiesProtection
LRSLocally Redundant Storage3 in 1 data centreHardware failure
ZRSZone-Redundant Storage3 across 3 AZsData centre failure
GRSGeo-Redundant Storage6 (3 primary + 3 secondary region)Regional outage (read from secondary on failover)
GZRSGeo-Zone-Redundant Storage6 (3 across AZs + 3 secondary region)AZ + regional outage
RA-GRSRead-Access GRSSame as GRSSecondary always readable
RA-GZRSRead-Access GZRSSame as GZRSSecondary always readable

General guidance:

  • Dev/test → LRS (cheapest)
  • Production web apps → ZRS
  • Business-critical data → GRS or GZRS
  • Need read replica in another region → RA-GRS or RA-GZRS

Access Tiers (Blob Storage)

TierAccess costStorage costUse Case
HotLowHigherFrequently accessed data
CoolMediumLowerInfrequently accessed, stored 30+ days
ColdHigherLowerRarely accessed, stored 90+ days
ArchiveHighest (rehydration needed)LowestLong-term backup, stored 180+ days

Blob Storage

Blob (Binary Large OBject) Storage is Azure's object store, the equivalent of AWS S3. Store any unstructured data: images, videos, backups, logs, static website files, and more.

Concepts

Storage Account (mystorageacct)
└── Container (images)           ← like a bucket or folder
    ├── photo1.jpg               ← Block Blob (most common)
    ├── video.mp4                ← Block Blob (large file, streamed)
    └── logfile.txt              ← Block Blob
  • Block Blob: Standard blob for files. Max size 190.7 TiB.
  • Append Blob: Optimised for append operations (logging).
  • Page Blob: Random read/write access; used for VM disks.

Working with Blobs

# Get connection string (or use --account-key / --sas-token / --auth-mode login)
export STORAGE_CONN=$(az storage account show-connection-string \
  --name mystorageacct \
  --resource-group myapp-rg \
  --query connectionString \
  --output tsv)

# Create a container
az storage container create \
  --name images \
  --connection-string $STORAGE_CONN \
  --public-access blob   # blob = individual blobs public; container = list + blobs; off = private

# Upload a file
az storage blob upload \
  --container-name images \
  --name photo1.jpg \
  --file ./photo1.jpg \
  --connection-string $STORAGE_CONN

# Upload a whole directory
az storage blob upload-batch \
  --source ./assets \
  --destination images \
  --connection-string $STORAGE_CONN

# List blobs in a container
az storage blob list \
  --container-name images \
  --connection-string $STORAGE_CONN \
  --output table

# Download a blob
az storage blob download \
  --container-name images \
  --name photo1.jpg \
  --file ./downloaded.jpg \
  --connection-string $STORAGE_CONN

# Generate a SAS token (time-limited, permission-scoped URL)
az storage blob generate-sas \
  --container-name images \
  --name photo1.jpg \
  --permissions r \
  --expiry 2025-12-31 \
  --connection-string $STORAGE_CONN \
  --output tsv

# Delete a blob
az storage blob delete \
  --container-name images \
  --name photo1.jpg \
  --connection-string $STORAGE_CONN

Static Website Hosting

Serve a single-page application (SPA) or static site directly from Blob Storage:

# Enable static website hosting
az storage blob service-properties update \
  --account-name mystorageacct \
  --static-website \
  --index-document index.html \
  --404-document 404.html

# Upload your site
az storage blob upload-batch \
  --source ./dist \
  --destination '$web' \
  --connection-string $STORAGE_CONN

# Get the website URL
az storage account show \
  --name mystorageacct \
  --resource-group myapp-rg \
  --query "primaryEndpoints.web" \
  --output tsv

Lifecycle Management

Automatically tier or delete blobs after a set number of days:

{
  "rules": [
    {
      "name": "MoveToArchive",
      "enabled": true,
      "type": "Lifecycle",
      "definition": {
        "filters": { "blobTypes": ["blockBlob"], "prefixMatch": ["backups/"] },
        "actions": {
          "baseBlob": {
            "tierToCool": { "daysAfterModificationGreaterThan": 30 },
            "tierToArchive": { "daysAfterModificationGreaterThan": 90 },
            "delete": { "daysAfterModificationGreaterThan": 365 }
          }
        }
      }
    }
  ]
}
az storage account management-policy create \
  --account-name mystorageacct \
  --resource-group myapp-rg \
  --policy @lifecycle-policy.json

Azure Files

Azure Files is a managed cloud file share using the SMB (Server Message Block) or NFS protocol. Mount it on Windows, Linux, or macOS, just like a network drive.

Use cases: Lift-and-shift of on-premises file servers, shared config/logs for VMs, persistent storage for containers.

# Create a file share (quota in GB)
az storage share create \
  --name myfileshare \
  --quota 100 \
  --connection-string $STORAGE_CONN

# Mount on Linux
# Get the mount command from the portal, or build it:
sudo mkdir /mnt/myfileshare
sudo mount -t cifs //mystorageacct.file.core.windows.net/myfileshare /mnt/myfileshare \
  -o vers=3.0,username=mystorageacct,password=<storage-key>,dir_mode=0777,file_mode=0777,serverino

# Mount on Windows (PowerShell)
$connectTestResult = Test-NetConnection -ComputerName mystorageacct.file.core.windows.net -Port 445
net use Z: \\mystorageacct.file.core.windows.net\myfileshare /user:Azure\mystorageacct <storage-key>

# Upload a file to a share
az storage file upload \
  --share-name myfileshare \
  --source ./config.env \
  --path config/config.env \
  --connection-string $STORAGE_CONN

Azure File Sync

Azure File Sync caches cloud file shares on Windows Server machines on-premises. Users access files locally at LAN speeds; Azure holds the full dataset.

Queue Storage

Azure Queue Storage is a simple, durable message queue for asynchronous communication between application components. Max message size is 64 KB; queue can hold unlimited messages.

# Create a queue
az storage queue create \
  --name myqueue \
  --connection-string $STORAGE_CONN

# Send a message
az storage message put \
  --queue-name myqueue \
  --content '{"orderId": "12345", "action": "process"}' \
  --connection-string $STORAGE_CONN

# Receive messages (makes them invisible for 30s by default)
az storage message get \
  --queue-name myqueue \
  --connection-string $STORAGE_CONN

# Delete a message after processing
az storage message delete \
  --queue-name myqueue \
  --id <message-id> \
  --pop-receipt <pop-receipt> \
  --connection-string $STORAGE_CONN

# Peek (read without locking)
az storage message peek \
  --queue-name myqueue \
  --connection-string $STORAGE_CONN

For complex messaging needs (guaranteed ordering, topics/subscriptions, dead-lettering) use Azure Service Bus instead.

Table Storage

Azure Table Storage is a NoSQL key-value store. Each row has a PartitionKey and RowKey (together form the primary key), plus up to 252 custom properties.

When to use: Simple, high-volume structured data that doesn't need relational queries. Very cheap.

# Create a table
az storage table create \
  --name events \
  --connection-string $STORAGE_CONN

# Insert an entity
az storage entity insert \
  --table-name events \
  --entity PartitionKey=2024 RowKey=evt001 EventName="UserSignup" UserId="u123" \
  --connection-string $STORAGE_CONN

# Query entities
az storage entity query \
  --table-name events \
  --filter "PartitionKey eq '2024'" \
  --connection-string $STORAGE_CONN

For richer querying and indexing, prefer Azure Cosmos DB Table API or Azure SQL.

Shared Access Signatures (SAS)

A SAS token grants time-limited, permission-scoped access to a storage resource without sharing your account keys.

# Account SAS: access to all services
az storage account generate-sas \
  --account-name mystorageacct \
  --services blob \
  --resource-types container,object \
  --permissions rwld \
  --expiry 2025-12-31T00:00:00Z \
  --output tsv

# Service SAS: access to a specific container
az storage container generate-sas \
  --name images \
  --permissions rl \
  --expiry 2025-06-30 \
  --connection-string $STORAGE_CONN \
  --output tsv

SAS vs Managed Identity vs Connection String

MethodUse When
Connection stringDev/test only (contains account key)
Account keyAvoid in production (full access)
SAS tokenShare limited access with third parties
Managed IdentityApplications running in Azure (no secrets needed, preferred)

Azure Managed Disks

Managed Disks are block storage volumes attached to Azure VMs (not directly accessible via the storage APIs).

# Create a standalone managed disk
az disk create \
  --resource-group myapp-rg \
  --name myDataDisk \
  --size-gb 256 \
  --sku Premium_SSD

# Attach to a VM
az vm disk attach \
  --resource-group myapp-rg \
  --vm-name mywebvm \
  --name myDataDisk

Storage Summary

ServiceTypeProtocolBest For
Blob StorageObjectHTTP/RESTFiles, images, backups, static sites
Azure FilesFile shareSMB / NFSLift-and-shift file servers
Queue StorageMessage queueHTTP/RESTSimple async decoupling
Table StorageKey-value NoSQLHTTP/RESTSimple structured data
Managed DisksBlockOS-levelVM operating system and data volumes

Next Steps

Continue to 05-networking.md to learn about Virtual Networks, security, and connectivity.