Раздел 11. Production-ready containers
«Работает у меня» и «готово к эксплуатации» — разные состояния. Между ними лежит набор требований, каждое из которых появилось после конкретного инцидента: сервис, который не отдаёт логи; образ, где нашли уязвимость, но никто не знает, какие версии внутри; приложение, которое при перезапуске теряет запросы; container, съевший всю память на узле.
Раздел систематизирует эти требования и показывает, как проверить каждое. Он не даёт «правильный production-Dockerfile» для копирования: требования зависят от контекста, и задача раздела — научить их выводить.
Отдельно разбирается то, что регулярно ломается именно в Python: поведение памяти под cgroup limits, расчёт worker-процессов, обработка сигналов через несколько уровней процессов.
Цели обучения
После раздела учащийся сможет:
- сформулировать принципы immutable infrastructure и объяснить их практические следствия;
- объяснить, почему «один процесс на container» — guideline, и назвать обоснованные исключения;
- превратить development-образ в production-ready и доказать каждое улучшение проверкой;
- применить runtime hardening: non-root, read-only rootfs,
--cap-drop,--security-opt; - различать liveness и readiness и корректно реализовать оба;
- настроить structured logging и объяснить, почему логи идут в stdout;
- обеспечить graceful shutdown с корректными таймаутами на всех уровнях;
- задать resource limits и объяснить их влияние на поведение Python-приложения;
- передать конфигурацию и secrets, не оставив следов в образе;
- организовать сканирование образов, работу с SBOM и provenance;
- спланировать rollback и объяснить, почему он невозможен без неизменяемых тегов.
Предварительные знания
- Раздел 06. Python внутри Container — весь раздел;
- Раздел 09. Docker Compose — описание системы;
- Раздел 05. Dockerfile — multi-stage и воспроизводимость;
- опыт эксплуатации любого сервиса желателен, но не обязателен.
Материалы
-
Принципы production
Immutable infrastructure и почемуdocker execдля исправления в production — антипаттерн. «Один процесс на container»: происхождение правила, его смысл и обоснованные исключения. Twelve-Factor в применении к containers. Чек-лист требований, из которого выводятся остальные уроки раздела. -
Runtime hardening
Запуск от non-root: в образе и через--user. Read-only root filesystem и определение необходимыхtmpfs. Отбор capabilities через--cap-drop=ALLи точечный--cap-add.--security-opt=no-new-privileges.--pids-limit. Проверка каждого пункта командой. -
Healthchecks и readiness
Liveness и readiness: разные вопросы и разные последствия ошибок. Что должен и чего не должен проверять healthcheck.start_periodдля медленного старта. Почему проверка зависимости в liveness-пробе приводит к каскадным перезапускам. Реализация обоих endpoint в FastAPI. -
Resource limits и память Python
--memory,--memory-reservation,--cpus,--cpu-shares. Что видит Python:os.cpu_count()против доступных CPU, отсутствие представления о memory limit. Поведение аллокатора и рост RSS. OOM killer и exit code137. Расчёт worker count. Методика подбора лимитов по измерениям. -
Конфигурация и secrets
Конфигурация через environment: возможности и границы. Почему секрет вENVостаётся в метаданных образа. Способы доставки secrets: файлы, secret mounts при сборке, внешние хранилища. Разделение конфигурации по окружениям. Валидация конфигурации при старте. -
Supply chain
Сканирование образов и интерпретация результатов: какие уязвимости требуют действий. SBOM: что это, как получить и зачем нужен. Provenance и attestations. Pinning по digest. Registry authentication. Rollback: почему он требует неизменяемых тегов и как это организовать. -
Практические задания
Лабораторные задания раздела с проверкой результата.
Рекомендуемый порядок чтения
Последовательный: 01 → 02 → 03 → 04 → 05 → 06 → exercises.
Урок 04 самый сложный технически и самый ценный практически: именно там объясняется поведение, которое в эксплуатации выглядит как «приложение внезапно падает без ошибок».
Практические задания
| № | Задание | Тип |
|---|---|---|
| 1 | Взять development-образ из раздела 10 и последовательно применить восемь требований, измеряя эффект каждого | обяз. |
| 2 | Запустить приложение с --read-only и минимальным набором tmpfs | обяз. |
| 3 | Запустить с --cap-drop=ALL и определить, какие capabilities действительно нужны | обяз. |
| 4 | Реализовать /healthz и /readyz с разной логикой и объяснить разницу | обяз. |
| 5 | Проверить graceful shutdown под нагрузкой: ни один активный запрос не должен быть оборван | обяз. |
| 6 | Подобрать --memory по измерениям, а не по догадке; зафиксировать методику | доп. |
| 7 | Просканировать образ, разобрать отчёт и обосновать, какие находки требуют действий | доп. |
| 8 | Сгенерировать SBOM и найти в нём конкретную версию зависимости | доп. |
| 9 | В образе обнаружен пароль от базы. Найти, как он туда попал, и устранить | диаг. |
| 10 | Организовать tagging так, чтобы откат на предыдущую версию был выполним одной командой | ★ |
Полные формулировки — в exercises.md.
Критерии завершения раздела
Раздел пройден, когда учащийся может без подсказок:
- Перечислить не менее восьми требований к production-образу и объяснить причину каждого.
- Доказать командами, что приложение работает от non-root с read-only rootfs.
- Объяснить, почему liveness-проба не должна проверять доступность базы данных.
- Объяснить, почему Python-приложение с
--memory=512mможет падать раньше, чем достигнет 512 MB по своим внутренним метрикам. - Показать, что секрет не присутствует ни в одном слое образа.
- Описать процедуру отката на предыдущую версию и требования к тегам, которые её обеспечивают.
Проверьте себя: Quiz 11 и Checkpoint 3.
Что дальше
Раздел затронул безопасность как часть production-требований. Следующий раздел рассматривает её отдельно и системно — начиная с того, что изоляция container не является полноценной границей безопасности.
Навигация
← Предыдущий раздел: Development workflow
Вернуться к главному оглавлению
Следующий раздел: Security →