Главная/Production-ready containers/Обзор

Раздел 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 и объяснить, почему он невозможен без неизменяемых тегов.

Предварительные знания

Материалы

  1. Принципы production
    Immutable infrastructure и почему docker exec для исправления в production — антипаттерн. «Один процесс на container»: происхождение правила, его смысл и обоснованные исключения. Twelve-Factor в применении к containers. Чек-лист требований, из которого выводятся остальные уроки раздела.

  2. Runtime hardening
    Запуск от non-root: в образе и через --user. Read-only root filesystem и определение необходимых tmpfs. Отбор capabilities через --cap-drop=ALL и точечный --cap-add. --security-opt=no-new-privileges. --pids-limit. Проверка каждого пункта командой.

  3. Healthchecks и readiness
    Liveness и readiness: разные вопросы и разные последствия ошибок. Что должен и чего не должен проверять healthcheck. start_period для медленного старта. Почему проверка зависимости в liveness-пробе приводит к каскадным перезапускам. Реализация обоих endpoint в FastAPI.

  4. Resource limits и память Python
    --memory, --memory-reservation, --cpus, --cpu-shares. Что видит Python: os.cpu_count() против доступных CPU, отсутствие представления о memory limit. Поведение аллокатора и рост RSS. OOM killer и exit code 137. Расчёт worker count. Методика подбора лимитов по измерениям.

  5. Конфигурация и secrets
    Конфигурация через environment: возможности и границы. Почему секрет в ENV остаётся в метаданных образа. Способы доставки secrets: файлы, secret mounts при сборке, внешние хранилища. Разделение конфигурации по окружениям. Валидация конфигурации при старте.

  6. Supply chain
    Сканирование образов и интерпретация результатов: какие уязвимости требуют действий. SBOM: что это, как получить и зачем нужен. Provenance и attestations. Pinning по digest. Registry authentication. Rollback: почему он требует неизменяемых тегов и как это организовать.

  7. Практические задания
    Лабораторные задания раздела с проверкой результата.

Рекомендуемый порядок чтения

Последовательный: 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.

Критерии завершения раздела

Раздел пройден, когда учащийся может без подсказок:

  1. Перечислить не менее восьми требований к production-образу и объяснить причину каждого.
  2. Доказать командами, что приложение работает от non-root с read-only rootfs.
  3. Объяснить, почему liveness-проба не должна проверять доступность базы данных.
  4. Объяснить, почему Python-приложение с --memory=512m может падать раньше, чем достигнет 512 MB по своим внутренним метрикам.
  5. Показать, что секрет не присутствует ни в одном слое образа.
  6. Описать процедуру отката на предыдущую версию и требования к тегам, которые её обеспечивают.

Проверьте себя: Quiz 11 и Checkpoint 3.

Что дальше

Раздел затронул безопасность как часть production-требований. Следующий раздел рассматривает её отдельно и системно — начиная с того, что изоляция container не является полноценной границей безопасности.

Навигация

← Предыдущий раздел: Development workflow
Вернуться к главному оглавлению
Следующий раздел: Security →

Markdown на GitHub ↗