Короткий ответ
Нужна комбинация превентивных и обнаруживающих мер: обязательное тегирование всех ресурсов (команда, окружение, владелец, срок жизни) через policy as code, проверяющую plan до apply; политики, ограничивающие дорогие типы ресурсов/размеры инстансов в неprod-окружениях без явного approval; автоматическое уничтожение временных dev-окружений по TTL (например, через scheduled job, который по тегу expiry удаляет ресурсы старше N дней); и алерты по аномальному росту расходов, привязанные к тегам команды/проекта, а не только общий биллинг-дэшборд, который кто-то должен регулярно и добровольно смотреть.
Как это работает подробнее
без обязательных тегов стоимость в биллинге облачного провайдера агрегируется плохо и не позволяет понять, какая команда/окружение несёт ответственность за рост, а без политик на этапе plan дорогой ресурс обнаруживается только постфактум, когда расход уже понесён за месяц; TTL-механизм для dev-окружений работает, потому что временные эксперименты по своей природе не нуждаются в бессрочном существовании, а их забывают удалить именно потому, что это не автоматизировано.
Сравнение
- Компромисс. Жёсткие предварительные ограничения по стоимости (запрет дорогих типов ресурсов без approval) предотвращают рост расходов надёжнее, но замедляют легитимные эксперименты и требуют поддерживать процесс исключений; чисто обнаруживающий подход (дэшборды и алерты постфактум) не мешает разработчикам, но реагирует с задержкой и уже понесёнными расходами. Разумный баланс — дёшево внедряемые превентивные меры для самых частых ошибок (забытые NAT Gateway, TTL для dev) плюс обнаруживающие алерты для менее предсказуемых случаев, с пересмотром порогов по фактической статистике инцидентов с расходами.
Пример кода
# Policy as code: требование тегов + ограничение размера БД в dev
deny[msg] {
input.resource_type == "aws_db_instance"
input.tags.Environment == "dev"
input.instance_class != "db.t3.small"
not input.tags.cost_exception_approved
msg := "БД в dev должна быть db.t3.small без явного cost_exception_approved"
}
# Infracost в CI: показывает стоимостной эффект PR до merge
$ infracost diff --path=.
Monthly cost will increase by $412 (NAT Gateway x3 added)Что использовать на практике
- Практика. превентивные политики (запрет создания NAT Gateway/instance определённого размера в dev без approval) должны быть сформулированы так, чтобы не блокировать легитимные случаи, когда dev-окружению действительно нужен более мощный ресурс (например, нагрузочное тестирование) — для этого нужен быстрый процесс временного исключения, а не постоянный запрет; также полезно считать стоимость прямо в CI на основе plan (например, через Infracost) и показывать её в PR до merge, чтобы автор видел финансовые последствия своего изменения до, а не после того, как оно попало в прод.
Подводные камни
- Ошибка. Не выполняйте изменение без проверки плана, резервной копии состояния и понятного способа отката; для production согласуйте окно работ и исключите параллельные операции.