Объектное хранилище выглядит как «положил и забыл» — но без операционной дисциплины бакеты превращаются в десятки терабайт бесхозных данных с непредсказуемым счётом. Разберём, как правильно настроить резервное копирование, защититься от потери данных и не переплачивать.
S3 как место для резервных копий
S3 — удобный целевик для резервных копий любых систем: дампы PostgreSQL, снапшоты MongoDB и Elasticsearch, конфигурационные файлы, зашифрованные секреты.
Почему S3 хорошо подходит для этой роли:
- Надёжность 99.999999999% (11 девяток) — данные хранятся в нескольких зонах доступности внутри одного региона.
- Холодные классы хранения — Glacier Deep Archive стоит около $1 за терабайт в месяц; ежедневные бэкапы годичной давности хранить почти бесплатно.
- Версионирование защищает от случайного удаления и вирусов-шифровальщиков: «удалённый» объект на самом деле получает метку удаления, старая версия остаётся.
- Репликация в другой регион обеспечивает восстановление при катастрофах.
Типичная структура бакета с резервными копиями выглядит так:
s3://backup-bucket/
├── pg/ ← дампы PostgreSQL
├── mongo/ ← дампы MongoDB
├── es/ ← снапшоты Elasticsearch
└── app/ ← экспорты приложения
На бакете включают: версионирование, lifecycle-политику (переход в Glacier через 30 дней, удаление старых версий через 90), репликацию в другой регион.
Кросс-региональная репликация
AWS даёт 11 девяток надёжности, но главный враг данных — человеческая ошибка: случайно удалили бакет, скомпрометировали учётную запись.
Cross-Region Replication (CRR) решает обе проблемы. Каждый объект, помещённый в исходный бакет, асинхронно копируется в бакет-приёмник в другом регионе (или аккаунте). Если что-то случится с продакшн-аккаунтом — резервная копия недосягаема для атакующего.
Настройка через AWS CLI:
{
"Role": "arn:aws:iam::ACCOUNT:role/replication-role",
"Rules": [{
"Status": "Enabled",
"Destination": {
"Bucket": "arn:aws:s3:::backup-dr-bucket",
"StorageClass": "STANDARD_IA"
},
"DeleteMarkerReplication": { "Status": "Enabled" }
}]
}
Важный момент: репликация работает только для новых объектов. Данные, которые уже лежат в бакете, не реплицируются автоматически — для них нужен aws s3 sync или S3 Batch Replication.
Версионирование и MFA Delete
Версионирование включают на уровне бакета. После включения каждый PUT создаёт новую версию объекта, а DELETE добавляет метку удаления — физически объект остаётся.
Для критичных бакетов с резервными копиями добавляют MFA Delete: удаление объектов требует одноразового кода с MFA-устройства root-аккаунта. Даже если учётка разработчика скомпрометирована — уничтожить бэкапы не получится.
aws s3api put-bucket-versioning \
--bucket backup-bucket \
--versioning-configuration Status=Enabled,MFADelete=Enabled \
--mfa "arn:aws:iam::ACCOUNT:mfa/user 123456"
Object Lock — ещё жёстче: режим WORM (write-once-read-many) делает удаление физически невозможным на заданный срок, даже для администратора. Используется в compliance-бакетах для финансовых и медицинских данных.
Lifecycle-политики для разных случаев
Lifecycle управляет переходами между классами хранения и удалением объектов. Несколько типичных наборов:
Пользовательский контент (аватарки, загрузки):
- prefix: "tmp/"
Expiration: 7 days
- prefix: "users/"
NoncurrentVersionExpiration: 30 days
AbortIncompleteMultipartUpload: 7 days
Журналы и аудит:
- prefix: "audit/"
Transitions:
- 30 days → STANDARD_IA
- 90 days → GLACIER_FLEXIBLE
- 365 days → DEEP_ARCHIVE
Expiration: 2555 days # 7 лет для compliance
Резервные копии PostgreSQL:
- prefix: "pg/"
Transitions:
- 7 days → STANDARD_IA # быстрое восстановление первой недели
- 30 days → GLACIER_INSTANT # доступ за минуты
- 90 days → DEEP_ARCHIVE # долгосрочное хранение
Expiration: 365 days
NoncurrentVersionExpiration: 30 days
AbortIncompleteMultipartUpload: 1 day
Правило AbortIncompleteMultipartUpload стоит добавлять везде: незавершённые составные загрузки незаметно накапливаются и тоже биллятся.
Из чего складывается стоимость S3
AWS S3 выставляет счёт по трём статьям.
Хранение
Оплата за гигабайт в месяц. Класс хранения определяет цену:
| Класс | $/ГБ/месяц (us-east-1) | Применение |
|---|---|---|
| Standard | $0.023 | Активные данные |
| Standard-IA | $0.0125 | Резервные копии, доступ раз в месяц |
| Glacier Instant | $0.004 | Архив с возможностью быстрого доступа |
| Glacier Flexible | $0.0036 | Compliance, доступ за часы |
| Deep Archive | $0.00099 | Холодный архив, доступ за сутки |
100 ТБ на Standard — около $2300 в месяц. На Deep Archive — около $100 в месяц.
Запросы
PUT/COPY/POST/LIST: ~$0.005 за 1000 запросов. GET: ~$0.0004 за 1000 запросов.
Для большинства приложений это незаметные суммы. Но если приложение пишет каждое событие отдельным файлом — счёт растёт. Миллион операций LIST в день = $5/день = $150 в месяц.
Типичная ошибка: писать миллион файлов по 1 КБ вместо одного файла в 1 ГБ. Стоимость хранения одинакова, а расходы на запросы — в миллион раз больше.
Исходящий трафик
Самая коварная статья. Трафик из S3 в интернет: ~$0.09 за ГБ.
100 ТБ в месяц = $9000. Для публичных бакетов с медиаконтентом эта статья часто превышает стоимость самого хранения.
Способы снизить:
- CloudFront перед S3 — кэширование на граничных серверах снижает исходящий трафик из S3; трафик CloudFront → пользователь дешевле ($0.085/ГБ при объёме свыше 10 ТБ).
- VPC Endpoint для трафика из EC2 в том же регионе — бесплатно. Для backend-сервисов, работающих в AWS, это нужно включать всегда.
Альтернативы AWS S3
| Провайдер | Исходящий трафик | Особенность |
|---|---|---|
| AWS S3 | $0.09/ГБ | Стандарт |
| Backblaze B2 | $0.01/ГБ | S3-совместимый API, дешёвый трафик |
| Cloudflare R2 | бесплатно | S3-совместимый API, нет платы за трафик |
| Wasabi | бесплатно (с ограничениями) | Дешёвое хранение |
| Yandex Object Storage | ~$0.005–0.01/ГБ | Российская юрисдикция |
Cloudflare R2 — особенно интересен для публичного контента с большим трафиком: S3-совместимый API позволяет переключиться через endpointOverride в SDK без переписывания кода.
Мониторинг
Метрики CloudWatch
S3 автоматически отправляет метрики в CloudWatch:
| Метрика | Что значит | Повод для сигнала |
|---|---|---|
BucketSizeBytes | Размер бакета (раз в день) | Внезапный скачок |
NumberOfObjects | Число объектов (раз в день) | Рост на тысячи в день |
AllRequests / 4xxErrors / 5xxErrors | Запросы и ошибки | Ошибок > 0.1% |
BytesDownloaded | Исходящий трафик | Основа для оценки затрат |
Журналы доступа
Server access logging пишет каждый запрос в текстовый файл в другой бакет: IP, время, действие, ключ объекта, статус, размер, задержка, user-agent.
aws s3api put-bucket-logging --bucket production-bucket \
--bucket-logging-status '{
"LoggingEnabled": {
"TargetBucket": "audit-bucket",
"TargetPrefix": "logs/production-bucket/"
}
}'
Альтернатива — CloudTrail data events: формат JSON, чуть большая задержка, зато интегрируется с остальными событиями CloudTrail.
S3 Inventory
S3 Inventory формирует ежедневный (или еженедельный) отчёт по всем объектам бакета в формате CSV или Parquet. Колонки: ключ, размер, класс хранения, дата изменения, статус шифрования.
Полезно для проверки, что lifecycle-политика работает как ожидается, и для поиска «сирот» — объектов, у которых нет записей в базе данных.
Типичные проблемы и защита
Компрометация учётки и удаление данных
Сценарий: атакующий получил учётную запись с правами s3:DeleteObject и удалил всё содержимое.
Защита:
- Versioning — объекты не удалены физически, только добавлены метки удаления. Восстановление через
aws s3api list-object-versions. - MFA Delete — массовое удаление требует MFA-токен root-аккаунта.
- Object Lock — физическое удаление невозможно на заданный срок.
- Репликация в другой аккаунт — резервная копия недосягаема для скомпрометированной учётки.
Объекты ушли в Deep Archive по ошибке
Lifecycle-политика с неточным фильтром применилась к горячим данным. Чтение из Deep Archive занимает до 12 часов и стоит денег.
Защита: всегда проверяйте lifecycle-политику на небольшом тестовом префиксе перед применением ко всему бакету.
Восстановление: запрос restore-object, ожидание (до 12 часов), потом копирование в Standard.
Бакет случайно стал публичным
Ошибочные правки в bucket policy сделали весь бакет доступным извне. Возможна утечка данных и огромный счёт за исходящий трафик.
Защита: Block Public Access на уровне аккаунта — глобальный переключатель, который не позволяет ни одному бакету стать публичным, даже если кто-то изменил политику. Включайте на корневом аккаунте всегда.
Миллионы мелких файлов — неожиданный счёт
Каждое событие логируется отдельным PUT. Через месяц — миллионы файлов и заметные расходы на запросы.
Решение: накапливать события локально и сбрасывать в S3 пакетами раз в несколько минут или по достижении порогового размера. Amazon Kinesis Data Firehose делает это автоматически.
Чек-лист production-бакета
Минимальный набор настроек, который должен быть на каждом бакете в продакшне:
- Block Public Access включён (на уровне аккаунта тоже)
- Versioning включён
- SSE-S3 или SSE-KMS (для новых бакетов включено по умолчанию с 2023 года, для старых — проверить)
- Lifecycle-политика: прерывание незавершённых составных загрузок через 7 дней, удаление старых версий, переход в холодные классы
- Сигнал CloudWatch на резкий рост размера и числа объектов
- Журналы доступа или CloudTrail data events для аудита
- Кросс-региональная репликация для критичных бакетов
- VPC Endpoint для трафика из EC2/EKS
- MFA Delete на бакетах с резервными копиями
- IAM с минимальными правами —
s3:*без ограничений недопустим
Коротко
- S3 — надёжное место для резервных копий баз данных и файлов; Glacier Deep Archive снижает стоимость долгосрочного хранения до $1/ТБ в месяц.
- Версионирование защищает от случайного удаления и вирусов-шифровальщиков — объект удаляется только физически, когда истечёт версия.
- Cross-Region Replication копирует новые объекты в другой регион или аккаунт; для уже существующих объектов нужен
aws s3 sync. - MFA Delete блокирует массовое удаление даже при компрометации учётки.
- Стоимость S3 складывается из хранения, запросов и исходящего трафика; трафик — самая коварная статья ($0.09/ГБ в интернет).
- VPC Endpoint делает трафик из EC2 в S3 внутри одного региона бесплатным.
- Cloudflare R2 — S3-совместимый вариант без платы за исходящий трафик; переключение через
endpointOverride. - CloudWatch, журналы доступа и S3 Inventory покрывают основные потребности в мониторинге.
Что почитать дальше
- Fundamentals — устройство S3: бакет, объект, ключ, классы хранения.
- Spring + AWS SDK v2 для S3 — работа с S3 из Java-приложения.
- Эксплуатация Elasticsearch — S3 как цель для снапшотов Elasticsearch.