Blob Storage
Compatible with the azure-storage-blob SDKs (Java, Python, Node.js), the Azure CLI
(az storage blob), and Azurite-style connection strings. Speaks the Azure Storage Blob REST
protocol with Shared Key authentication and XML responses.
HTTP-only — no Docker. Data is held by the configured storage backend (
memoryby default;persistent,hybrid, orwalfor durability).
Features
- Containers — Create, Get properties, Delete, List (
?comp=list); duplicate create returns409 ContainerAlreadyExists - Blobs — Put (upload), Get (download), Delete, List within a container; overwrite semantics
- Block blobs — staged block upload (
?comp=block) followed by commit (?comp=blocklist) for large payloads, in addition to single-requestPut Blob - Range download —
Range: bytes=…returns206 Partial Content - Conditional download —
If-Match/If-None-Matchhonored; a stale ETag is rejected - Metadata —
x-ms-meta-*set on upload and returned on Get, round-tripped exactly - Not-found semantics — missing blob/container returns the Azure
404 BlobNotFound/ContainerNotFoundXML error shape
Endpoint
http://localhost:4577/{account}/{container} # container operations
http://localhost:4577/{account}/{container}/{blob} # blob operations
The account also answers at the host-style address {account}.blob.core.windows.net (and the Data
Lake Gen2 alias {account}.dfs.core.windows.net, which maps to the same blob backend) when the
Host header is set, matching how the SDKs address storage endpoints.
Quickstart
from azure.storage.blob import BlobServiceClient
conn = ("DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;"
"AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMh0==;"
"BlobEndpoint=http://localhost:4577/devstoreaccount1;")
svc = BlobServiceClient.from_connection_string(conn)
container = svc.create_container("my-container")
container.upload_blob("hello.txt", b"hello world")
print(container.download_blob("hello.txt").readall())
The well-known Azurite development key (Eby8vdM0…) is accepted; any account name works.
Configuration
floci-az:
services:
blob:
enabled: true
storage:
services:
blob:
# mode: wal # override the global storage.mode for blob only
flush-interval-ms: 5000
| Property | Env var | Default | Description |
|---|---|---|---|
enabled |
FLOCI_AZ_SERVICES_BLOB_ENABLED |
true |
Enables the Blob Storage service |
storage.services.blob.mode |
FLOCI_AZ_STORAGE_SERVICES_BLOB_MODE |
(inherits storage.mode) |
Per-service backend override (memory / persistent / hybrid / wal) |
storage.services.blob.flush-interval-ms |
FLOCI_AZ_STORAGE_SERVICES_BLOB_FLUSH_INTERVAL_MS |
5000 |
Background flush-to-disk interval for the hybrid mode only; ignored by memory / persistent / wal (wal compacts on storage.wal.compaction-interval-ms instead) |
Intentional deviations
- Shared Key signatures are accepted but not cryptographically verified — the emulator is a
local dev target; any well-formed
Authorizationheader (or the Azurite key) is honored. - No SAS enforcement — SAS query parameters are parsed but not validated.
- Snapshots, versioning, leases, and tiering are not modeled.