Контроль затрат: как не получить счёт-сюрприз
Почему облако внезапно выставляет счёт на 400 $ за пустой проект — и как сделать так, чтобы этого не случилось с вами.
Контроль затрат в облаке — это не «экономить», а знать заранее: за что платим, сколько это будет к концу месяца и что произойдёт, если забыть выключить.
Классическая история: студент поднял виртуальную машину «на посмотреть», закрыл ноутбук и уехал на каникулы. Через месяц приходит счёт. Машина честно работала все 720 часов, публичный IP исправно резервировался, диск существовал. Никто ничего не сломал — облако просто делало ровно то, о чём его попросили. В этом и суть модели pay-as-you-go: вы платите за существование ресурса, а не за пользу от него.
Хорошая новость: Azure даёт полный набор инструментов, чтобы такого не случилось. Плохая: по умолчанию ни один из них не включён.
Откуда вообще берётся счёт
Каждый ресурс привязан к одному или нескольким метрам (meters) — счётчикам вида «часы работы VM размера B2s в West Europe», «гигабайты в Blob Storage уровня Hot», «исходящий трафик за пределы региона». Раз в час платформа записывает показания. В конце периода показания умножаются на цену метра — это и есть счёт.
Из этого следуют неочевидные вещи:
- VM тарифицируется по времени существования, а не по загрузке. Простаивающая на 1% машина стоит столько же, сколько загруженная на 100%.
- Диск тарифицируется отдельно от VM. Удалили машину, а диск остался — платите за диск.
- Входящий трафик бесплатен, исходящий — нет. Первые 100 ГБ в месяц идут бесплатно, дальше порядка 0,08–0,12 $ за гигабайт. Раздача видео с VM легко даёт счёт больше, чем сама VM.
У новой подписки есть подушка: кредит примерно 200 $ на 30 дней, 12 месяцев бесплатных лимитов на популярные сервисы и набор «always free» (например, 1 млн вызовов Azure Functions в месяц). Пока действует кредит, у подписки включён spending limit — при исчерпании ресурсы просто отключаются. Как только вы переходите на pay-as-you-go, этот предохранитель исчезает навсегда. Именно в этот момент и нужны бюджеты.
Калькулятор цен: считать до, а не после
Первый инструмент — Azure Pricing Calculator (azure.microsoft.com/pricing/calculator). Собираете конфигурацию, видите месячную сумму. Занимает пять минут и убивает половину сюрпризов: например, вы обнаруживаете, что Application Gateway стоит ~0,25 $ в час — это ~180 $ в месяц просто за то, что он есть.
Второй, менее известный, — Retail Prices API: цены Azure доступны публично, без авторизации, и их можно спрашивать из скрипта.
curl -s "https://prices.azure.com/api/retail/prices?\$filter=serviceName eq 'Virtual Machines' and armRegionName eq 'westeurope' and armSkuName eq 'Standard_B2s' and priceType eq 'Consumption'" \
| python3 -m json.tool | head -30
А оценку счёта удобно прикинуть обычным калькулятором. Ниже — маленькая модель, которая показывает главное недоразумение новичков: выключенная машина стоит денег.
HOURS = 730 # часов в среднем месяце
WORK = 190 # ~9 часов в день x 21 рабочий день
vm = 0.0416 # Standard_B2s, Linux, $/час
disk = 0.0263 # управляемый диск 128 ГБ, $/час
ip = 0.005 # статический публичный IP, $/час
always_on = (vm + disk + ip) * HOURS
scheduled = vm * WORK + (disk + ip) * HOURS
idle = (disk + ip) * HOURS
print("VM работает 24/7: ", round(always_on, 2), "$/мес")
print("VM по расписанию: ", round(scheduled, 2), "$/мес")
print("Экономия: ", round(always_on - scheduled, 2), "$/мес")
print("Платим за выключенную:", round(idle, 2), "$/мес")
Результат:
VM работает 24/7: 53.22 $/мес
VM по расписанию: 30.75 $/мес
Экономия: 22.46 $/мес
Платим за выключенную: 22.85 $/мес
Последняя строка — та самая, которую стоит запомнить. Даже полностью остановленная машина продолжает тянуть почти 23 $ в месяц за диск и зарезервированный IP. Экономия от расписания реальна, но не бесконечна: чтобы платить ноль, нужно удалить, а не выключить.
Бюджеты и алерты
Бюджет в Azure Cost Management — это правило «если расходы по этой подписке (или группе ресурсов) достигнут N, пришли письмо». Ставится за минуту и стоит ноль.
SUB=$(az account show --query id -o tsv)
az consumption budget create \
--budget-name budget-learning \
--amount 20 \
--category Cost \
--time-grain Monthly \
--start-date 2026-08-01 \
--end-date 2027-08-01 \
--resource-group rg-shop-demo
# посмотреть, сколько уже потрачено за период
az consumption usage list --top 5 --query "[].{res:instanceName, cost:pretaxCost, cur:currency}" -o table
Дальше в портале к бюджету добавляются пороги уведомлений: 50 %, 80 %, 100 % от суммы. Практика такая: 80 % — письмо себе, 100 % — письмо себе и тимлиду.
Главное заблуждение о бюджетах: бюджет НЕ останавливает трату денег. Это будильник, а не автомат защиты. Достигли 100 % — вам напишут, ресурсы продолжат работать и продолжат тарифицироваться.
Если нужен именно «рубильник», его собирают руками: бюджет отправляет событие в Action Group, тот дёргает Azure Function или Automation Runbook, а тот уже делает az vm deallocate или удаляет группу ресурсов. Для учебной подписки это оправданный час работы.
Главные пожиратели денег
Практически все счета-сюрпризы состоят из одного и того же набора. Вот он, отсортированный по частоте:
| Что | Порядок цены | Почему забывают |
| Забытая VM | 30–200 $/мес | «Я же её остановил» — остановил в ОС, а не deallocate |
| Диски без хозяина | 5–40 $/мес каждый | Удалили VM, диски по умолчанию остались |
| Публичные IP (Standard) | ~3,6 $/мес каждый | Тарифицируются даже неприсоединённые |
| Исходящий трафик | 0,08–0,12 $/ГБ | Раздача файлов/видео, бэкапы наружу |
| Application Gateway / NAT Gateway | от 30 до 200+ $/мес | Стоят по факту существования, не по нагрузке |
| Cosmos DB с provisioned RU/s | от 25 $/мес и вверх | Платите за зарезервированную пропускную способность, даже при нуле запросов |
| Снимки и бэкапы | копятся месяцами | Про политику хранения никто не вспоминает |
| Log Analytics / App Insights | ~2,3 $/ГБ логов | Включили verbose-логирование «на время отладки» |
Отдельно про «я остановил VM». Остановка изнутри гостевой ОС (shutdown -h now) переводит машину в состояние Stopped, но вычислительные ресурсы за ней остаются зарезервированы — и счёт идёт. Освобождает их только deallocate:
az vm deallocate -g rg-lab -n vm-lab # правильно: вычисления больше не тарифицируются
az vm stop -g rg-lab -n vm-lab # НЕ то же самое, если вызывать выключение внутри ОС
# найти диски-сироты (не подключены ни к одной VM)
az disk list --query "[?diskState=='Unattached'].{name:name, gb:diskSizeGb, rg:resourceGroup}" -o table
# найти публичные IP без владельца
az network public-ip list --query "[?ipConfiguration==null].{name:name, rg:resourceGroup}" -o table
Эти две команды стоит гонять раз в месяц. У любой команды, работающей с Azure дольше года, они что-нибудь да находят.
Автоотключение и гигиена
Самое дешёвое решение — не полагаться на память. Для учебных и dev-машин есть встроенное автовыключение по расписанию:
# гасить машину каждый день в 19:00 по указанной таймзоне
az vm auto-shutdown -g rg-lab -n vm-lab --time 1900 --email me@example.com
# проверить, что расписание включено
az vm auto-shutdown -g rg-lab -n vm-lab --query "{status:status, time:dailyRecurrence.time}" -o table
Второй приём — теги. Помечайте всё, что создаёте, владельцем и сроком жизни. Тогда «чей это ресурс и можно ли его снести» перестаёт быть детективом.
az group create -n rg-lab -l westeurope --tags owner=ivan purpose=learning delete-after=2026-08-01
# отчёт: что в подписке не помечено владельцем — кандидаты на разбор
az resource list --query "[?tags.owner==null].{name:name, type:type, rg:resourceGroup}" -o table
И третий, самый действенный для учёбы: одна группа ресурсов на один эксперимент. Тогда уборка — это az group delete --yes --no-wait, и вы не оставляете за собой хвостов вроде одинокого IP-адреса, который будет капать три года.
Как это работает
Данные о расходах не появляются мгновенно. Показания метров попадают в систему учёта пачками, и в Cost Management цифры отстают от реальности примерно на 8–24 часа. Практическое следствие важное: алерт бюджета приходит с задержкой. Если вы случайно подняли восемь машин серии D в пятницу вечером, письмо «превышено 100 %» может прийти в субботу днём — когда набежит уже вдвое больше.
Поэтому защита строится слоями: калькулятор до запуска (не создавать заведомо дорогое), бюджет с порогом 50 % (ранний сигнал, а не финальный), автоотключение (снижает цену ошибки), удаление группы после эксперимента (обнуляет). Ни один слой не заменяет остальные.
Ещё одна деталь: цены в калькуляторе и в счёте — розничные. Реальные скидки в Azure получают не за торг, а за обязательства: Reserved Instances (обещаете использовать VM год или три — минус 30–70 %) и Savings Plans. Для учебных подписок это неактуально, для рабочих — первое, куда смотрит финансовый отдел.
Частые ошибки
- Считать, что бюджет остановит расходы. Не остановит. Бюджет уведомляет. Рубильник надо собирать самому.
- Путать stop и deallocate. Машина, выключенная изнутри ОС, продолжает тарифицироваться как работающая.
- Удалять VM без дисков. Диски переживают машину и молча тянут деньги годами.
- Считать неиспользуемое бесплатным. Публичный IP, зарезервированные RU/s в Cosmos DB, Application Gateway — платные по факту существования.
- Тестировать на «взрослых» SKU. Разница между B-серией и D-серией на учебной задаче не видна, а в счёте — в разы.
- Не ставить бюджет вообще. Пять минут работы, которые страхуют от трёхзначного счёта. Это первое, что делают в новой подписке.
Итоги
- Облако тарифицирует существование ресурса, а не пользу от него: простаивающая машина стоит как работающая.
- Бюджет — это будильник, а не автомат защиты. Ставьте пороги 50/80/100 % и не рассчитывайте, что расходы остановятся сами.
deallocate≠ выключение из гостевой ОС. Только deallocate снимает плату за вычисления — но не за диск и IP.- Регулярно ищите сирот: неприсоединённые диски и публичные IP. Две команды
az— и минус десятки долларов в месяц. - Для учёбы: один эксперимент — одна группа ресурсов, автоотключение на VM, удаление группы в тот же день. Тогда счёт-сюрприз становится невозможен.