Blob Storage: файлы и объекты

Как хранить в облаке файлы, бэкапы, логи и картинки — без единого сервера и за копейки.

Azure Blob Storage — объектное хранилище: вы кладёте в него файлы (их называют «блобами»), а Azure выдаёт на каждый HTTPS-адрес. Ни дисков, ни файловой системы, ни машины, которую надо патчить.

Зачем нужно отдельное хранилище

Первое, что делает новичок в облаке: поднимает виртуальную машину, подключает к ней диск и складывает пользовательские файлы туда. Через полгода выясняется неприятное. Диск на терабайт стоит в разы дороже, чем терабайт в Blob Storage. Бэкапить его надо самому. Упала машина — файлы недоступны, хотя с ними всё в порядке. А раздать видео миллиону зрителей эта машина всё равно не сможет: она захлебнётся сетью раньше, чем процессором.

Blob Storage закрывает ровно эту боль. Он:

  • масштабируется до петабайт — вы не «выбираете размер», вы просто пишете;
  • хранит минимум три копии каждого байта и сам молча чинит битые;
  • отдаёт файлы напрямую по HTTPS — ваше приложение в раздаче вообще не участвует;
  • стоит от долей цента за гигабайт в месяц.

Типичные жильцы: аватарки и вложения пользователей, бэкапы баз, логи, видео, датасеты для машинного обучения, артефакты сборок, статические сайты. Правило простое: если файл не нужно менять посередине — ему место в блобе.

Иерархия: аккаунт → контейнер → блоб

В Azure всё живёт внутри подписки и группы ресурсов, а дальше начинается собственная иерархия хранилища.

УровеньЧто это
Storage account (аккаунт хранилища)Точка входа и единица тарификации. Задаёт регион, тип репликации, уровень доступа по умолчанию. Его имя становится частью адреса.
Container (контейнер)Плоская «папка верхнего уровня»: avatars, backups, logs. Уровень публичности настраивается именно тут.
Blob (блоб)Сам файл. Имя может содержать слэши — но это часть имени, а не настоящая вложенность.

Адрес любого файла складывается предсказуемо:

https://<account>.blob.core.windows.net/<container>/<blob>

https://ccdemostore7.blob.core.windows.net/avatars/users/42/photo.png

Раз имя аккаунта попадает в публичное доменное имя, оно уникально на весь Azure: 3–24 символа, только строчные латинские буквы и цифры. myapp-storage не пройдёт (дефис запрещён), ccdemostore7 — пройдёт, если никто не занял.

Три типа блобов

Block blobОбычные файлы: картинки, архивы, видео. Собирается из блоков, поэтому большой файл заливается параллельно и докачивается после обрыва. Ваш выбор в 95% случаев.
Append blobТолько дозапись в конец. Логи и аудит: несколько процессов пишут одновременно, ничего не затирая.
Page blobПроизвольный доступ страницами по 512 байт. Под ним живут диски виртуальных машин. Руками почти никогда не создают.

Репликация: сколько копий и где они лежат

LRS3 копии в одном дата-центре. Дешевле всего. Сгорел ЦОД — данных нет.
ZRS3 копии в трёх зонах доступности одного региона. Переживает падение целого ЦОД.
GRSLRS + асинхронная копия во втором регионе за сотни километров. Читать вторую копию нельзя — только после аварийного переключения.
RA-GRSТо же, но вторую копию можно читать всегда. Удобно для географически разнесённого чтения.

Для логов и временных артефактов честно хватает LRS — не платите за георепликацию мусора. Для бэкапов, которые вы обязаны предъявить после катастрофы, берите GRS.

Уровни доступа: Hot, Cool, Cold, Archive

Главная экономическая идея объектного хранилища звучит так: чем реже вы читаете данные, тем дешевле их хранить — но тем дороже каждое обращение. Azure даёт четыре уровня (tier) и разрешает переключать их у отдельного блоба.

УровеньХранениеЧтениеМинимальный срокКогда доступен файл
Hotдорогопочти бесплатнонетмгновенно
Coolпримерно вдвое дешевлеплатно за гигабайт30 днеймгновенно
Coldещё в два раза дешевледороже, чем Cool90 днеймгновенно
Archiveкопейкидорого + регидратация180 днейофлайн: часы ожидания

Обратите внимание на две колонки, из-за которых чаще всего попадают на деньги. Минимальный срок — если удалить или перевести блоб раньше, вам всё равно выставят счёт за оставшиеся дни (early deletion fee). А Archive офлайн в буквальном смысле: чтобы прочитать файл, его надо «регидратировать» — перевести в Hot или Cool и подождать от часа (High priority) до 15 часов (Standard).

Посчитаем экономику на пальцах. Цифры ниже — порядок величин для LRS в европейском регионе; точные ставки смотрите в калькуляторе Azure, но соотношение между уровнями меняется редко. Сценарий: храним 1 ТБ архива, из которого за месяц реально скачиваем 50 ГБ.

GB = 1024  # 1 ТБ в гигабайтах
read_gb = 50  # столько гигабайт реально читаем за месяц

storage_price = {"Hot": 0.0184, "Cool": 0.0100, "Cold": 0.0045, "Archive": 0.00099}
read_price = {"Hot": 0.0, "Cool": 0.01, "Cold": 0.03, "Archive": 0.02}

for tier, price in storage_price.items():
    storage = GB * price
    access = read_gb * read_price[tier]
    total = storage + access
    print(f"{tier:8} хранение ${storage:7.2f} + доступ ${access:6.2f} = ${total:7.2f} в месяц")

Результат:

Hot      хранение $  18.84 + доступ $  0.00 = $  18.84 в месяц
Cool     хранение $  10.24 + доступ $  0.50 = $  10.74 в месяц
Cold     хранение $   4.61 + доступ $  1.50 = $   6.11 в месяц
Archive  хранение $   1.01 + доступ $  1.00 = $   2.01 в месяц

Разница между Hot и Archive — почти десятикратная. Но поменяйте условие: скачивать не 50 ГБ, а 800 ГБ в месяц — и Archive мгновенно станет самым дорогим вариантом, да ещё и с многочасовой задержкой. Поэтому уровень выбирают не «по красоте названия», а по частоте чтения.

Практика: поднимаем хранилище из CLI

Три команды — и у вас есть боевое хранилище.

az group create \
  --name rg-storage-demo \
  --location westeurope

az storage account create \
  --name ccdemostore7 \
  --resource-group rg-storage-demo \
  --location westeurope \
  --sku Standard_LRS \
  --kind StorageV2 \
  --access-tier Hot \
  --allow-blob-public-access false

az storage container create \
  --name avatars \
  --account-name ccdemostore7 \
  --auth-mode login

Разберём флаги, которые реально важны:

  • --kind StorageV2 — современный универсальный аккаунт. Всегда он; V1 остался для совместимости.
  • --sku Standard_LRS — тип репликации, тот самый выбор из таблицы выше. Есть и Premium_LRS (SSD, низкая задержка, дорого).
  • --allow-blob-public-access falseзапрет анонимного доступа на уровне всего аккаунта. Ставьте его сразу: это страховка от того, что кто-то из коллег случайно откроет контейнер наружу.
  • --auth-mode login — работать от имени вашей учётной записи Azure AD (Entra ID), а не по ключу аккаунта. Ключ — это пароль ко всему хранилищу целиком, и он неизбежно утекает в git.

Загрузка и просмотр файлов

# один файл
az storage blob upload \
  --account-name ccdemostore7 \
  --container-name avatars \
  --name users/42/photo.png \
  --file ./photo.png \
  --auth-mode login

# целая папка одной командой
az storage blob upload-batch \
  --account-name ccdemostore7 \
  --destination avatars \
  --source ./local-avatars \
  --auth-mode login

# что там лежит
az storage blob list \
  --account-name ccdemostore7 \
  --container-name avatars \
  --auth-mode login \
  --output table

# скачать обратно
az storage blob download \
  --account-name ccdemostore7 \
  --container-name avatars \
  --name users/42/photo.png \
  --file ./restored.png \
  --auth-mode login

Для больших объёмов вместо az storage берут утилиту azcopy — она жмёт из машины все доступные мегабиты и умеет синхронизировать директории.

Статический сайт прямо из блоба

Blob Storage умеет притворяться веб-сервером. Ни VM, ни App Service, ни nginx — просто включаете флаг, и Azure заводит служебный контейнер $web, содержимое которого отдаётся по HTTP.

az storage blob service-properties update \
  --account-name ccdemostore7 \
  --static-website true \
  --index-document index.html \
  --404-document 404.html \
  --auth-mode login

az storage blob upload-batch \
  --account-name ccdemostore7 \
  --destination '$web' \
  --source ./dist \
  --auth-mode login

# узнать адрес сайта
az storage account show \
  --name ccdemostore7 \
  --resource-group rg-storage-demo \
  --query "primaryEndpoints.web" \
  --output tsv

Результат:

https://ccdemostore7.z6.web.core.windows.net/

Собранный фронтенд на React или Vue выкладывается сюда за секунды и стоит центы. Одно «но»: свой домен и HTTPS-сертификат Blob Storage сам не выдаст — сверху ставят Azure CDN или Front Door. Заодно получаете кеш на краю сети и защиту от всплесков трафика.

Правила жизненного цикла: экономия на автопилоте

Руками перекладывать миллионы блобов между уровнями невозможно. Для этого есть политика жизненного цикла — JSON, который Azure применяет раз в сутки.

{
  "rules": [
    {
      "name": "logs-tiering",
      "enabled": true,
      "type": "Lifecycle",
      "definition": {
        "filters": {
          "blobTypes": ["blockBlob"],
          "prefixMatch": ["logs/"]
        },
        "actions": {
          "baseBlob": {
            "tierToCool": { "daysAfterModificationGreaterThan": 30 },
            "tierToArchive": { "daysAfterModificationGreaterThan": 90 },
            "delete": { "daysAfterModificationGreaterThan": 365 }
          }
        }
      }
    }
  ]
}

Читается как фраза: «логи месяц лежат горячими, потом три месяца охлаждаются, потом уезжают в архив, а через год удаляются». Одна такая политика на проекте с активным логированием экономит больше, чем месяц оптимизации кода.

Как это работает

Плоское пространство имён. Внутри контейнера нет папок. users/42/photo.png — это целиком имя блоба, где слэши ничем не отличаются от букв. Портал Azure рисует «дерево», просто группируя блобы по общему префиксу. Отсюда следствие: «переименовать папку» нельзя — можно только скопировать каждый блоб под новым именем и удалить старые. Если вам нужна настоящая файловая иерархия с атомарным переименованием (это важно для Spark и аналитики), включают опцию hierarchical namespace — так рождается Azure Data Lake Storage Gen2.

Каждая операция — HTTP-запрос. Загрузка — это PUT, чтение — GET. У каждого блоба есть ETag, и вы можете отправить заголовок If-Match: «перезапиши, только если версия та же». Так делается оптимистическая блокировка без всякой базы данных.

Доступ без ключей. Раздавать ключ аккаунта клиентам нельзя. Вместо этого выдают SAS-токен (Shared Access Signature) — подписанную ссылку с ограничением по времени и правам:

https://ccdemostore7.blob.core.windows.net/avatars/users/42/photo.png
  ?sv=2023-11-03&se=2026-07-14T18%3A00%3A00Z&sp=r&sig=Xf9%2B...

Здесь sp=r — только чтение, se — момент истечения. Браузер пользователя скачивает файл напрямую из хранилища, ваш сервер не тратит на это ни байта трафика.

Из чего складывается счёт. Три слагаемых: хранение (гигабайты × дни), транзакции (каждая операция чтения/записи — доли цента за 10 000 операций) и исходящий трафик из региона наружу. Входящий трафик бесплатен всегда.

Частые ошибки

  • Публичный контейнер «на пять минут». Anonymous read у контейнера с пользовательскими данными — классическая утечка, которую находят сканеры интернета за часы. Держите --allow-blob-public-access false и раздавайте SAS-ссылки.
  • Archive для файлов, которые читают. Кто-то увидел цену в 20 раз ниже и перевёл туда всё подряд. Дальше приложение падает с ошибкой «This operation is not permitted on an archived blob», а восстановление терабайта занимает полдня и стоит дороже, чем год хранения в Hot.
  • Плата за досрочное удаление. Залили в Cool, через неделю передумали и стёрли — счёт придёт как за 30 дней. В Archive — как за 180. Прежде чем массово менять уровень, посмотрите на минимальный срок.
  • Миллионы крошечных блобов. Хранение мегабайта логов почти ничего не стоит, а вот 50 миллионов операций записи — уже заметная строка в счёте. Пакуйте мелочь в архивы, пишите логи батчами.
  • Ключ аккаунта в репозитории. Ключ даёт полный доступ ко всему хранилищу и не имеет срока жизни. Используйте Managed Identity для сервисов и --auth-mode login для людей.
  • Нет lifecycle-политики. Самая тихая утечка бюджета: терабайты логов трёхлетней давности в Hot, за которые вы платите каждый месяц.

Итоги

  • Blob Storage — объектное хранилище: аккаунт → контейнер → блоб, у каждого файла свой HTTPS-адрес.
  • Имя аккаунта уникально на весь Azure: 3–24 строчных латинских символа и цифры.
  • Block blob — для файлов, append — для логов, page — для дисков VM.
  • Hot / Cool / Cold / Archive: чем дешевле хранение, тем дороже чтение и длиннее минимальный срок. Archive — офлайн, регидратация занимает часы.
  • Политика жизненного цикла автоматически охлаждает и удаляет старые данные — это самая простая крупная экономия.
  • Публичный доступ выключайте на уровне аккаунта, а клиентам выдавайте SAS-ссылки с ограниченным сроком.
  • Статический сайт поднимается из контейнера $web одной командой; домен и HTTPS добавляет CDN или Front Door.
Проверьте себя
1. Файлы с бэкапами лежат в Archive. Приложению внезапно понадобилось прочитать один из них. Что произойдёт?
AФайл скачается как обычно, просто чуть медленнее
BЗапрос на чтение вернёт ошибку: блоб сначала нужно регидратировать в Hot или Cool, и это займёт часы
CAzure автоматически переведёт блоб в Hot и отдаст его через несколько секунд
DArchive вообще не позволяет восстановить данные, файл потерян
2. Вы залили 500 ГБ данных в уровень Cool, а через 5 дней решили их удалить. Что будет со счётом?
AОплата спишется только за 5 дней хранения
BНичего не спишется: удаление бесплатно
CПридётся заплатить как за 30 дней хранения — это минимальный срок для Cool (early deletion fee)
DПридётся заплатить как за 180 дней — минимальный срок одинаков для всех уровней