Пара 16: Готовность, ограничения и конфигурация контейнеров

90 минут · 3 курс, ML.

Содержание и результат

Проверить healthcheck, задать лимиты и не путать порядок запуска с готовностью.

План занятия

0–10: контекст и исходная задача. 10–40: устройство и механизмы. 40–55: демонстрация команд. 55–80: лабораторная работа. 80–90: разбор результата и фиксация исправлений.

Практика выполняется в своей учебной папке и на localhost. Подготовка окружения описана в lab/README.md.

Running, healthy, ready

Процесс существует, проверка проходит и пользовательский путь работает — разные факты.

Running означает, что процесс контейнера не завершился. Healthcheck выполняет отдельную проверку и присваивает состояние healthy/unhealthy. В нашем примере он вызывает /healthz. Не каждый healthcheck проверяет все зависимости: он должен иметь понятный смысл. Readiness — готовность обслуживать запросы, liveness — жизнеспособность процесса; в разных платформах это отдельные механизмы. Docker сам по себе не обязательно перезапускает unhealthy-контейнер: restart policy обычно реагирует на завершение процесса. Поэтому важны мониторинг и реакция, а не только зелёная метка.

Аналогия: свет в кафе горит, кухня готова и заказ выдан — три проверки.

Зависимости Compose

Порядок старта не гарантирует завершение инициализации.

depends_on задаёт зависимость порядка запуска. При condition: service_healthy Compose может дождаться healthcheck зависимости перед запуском потребителя. Это не постоянный контроль её доступности и не магическая защита после сбоя. Приложению всё равно нужны timeout, ограниченные retry и понятное поведение при отказе. В нашем сервисе нет внешней базы, поэтому не добавляем искусственную зависимость ради YAML. На схеме обсуждаем будущий вариант app → база и отмечаем, что старт и готовность могут разойтись во времени.

Аналогия: открыть дверь склада не значит закончить приёмку товаров.

Предел ресурсов и поверхность доступа

Ограничиваем ущерб и наблюдаем результат ограничения.

mem_limit и cpus задают пределы ресурсов учебного app. cap_drop: ALL, no-new-privileges и read_only сокращают ненужные привилегии; /data остаётся разрешённым местом записи, /tmp подключается отдельно. Эти настройки проверяются с реальным приложением: нельзя включить read-only и удивляться отказу записи без тома. Ограничение памяти не создаёт память и может привести к остановке. docker stats показывает наблюдение, а inspect — настроенный предел. Размер Docker Desktop и WSL тоже ограничивает весь запуск. Нам не нужен GPU: учебный проект специально лёгкий.

Аналогия: лабораторная работает в пределах выделенного бюджета, а не занимает всё здание.

Команды и наблюдения

Окружение: Ubuntu / Bash, lab.

docker compose up -d --build
docker compose ps
docker compose exec app python -c "import urllib.request; print(urllib.request.urlopen('http://127.0.0.1:8000/healthz').status)"
docker stats --no-stream
docker compose exec app sh -c "touch /app/test-write"
docker compose exec app sh -c "touch /data/test-write"

Отказ touch /app/test-write — ожидаемый результат политики, не дефект курса. Удалите собственный /data/test-write после проверки.

Ожидаемый результат: Healthcheck становится healthy; запись в /app отказана, в /data разрешена; stats показывает потребление.

Вариант для macOS

Healthcheck и ограничения выполняются внутри Linux-VM Docker Desktop. Показатели контейнера не равны всему потреблению macOS. Проверяйте выделенный Desktop бюджет CPU/RAM и доступность устройства.

docker stats --no-stream
docker compose ps
docker compose exec app id

Практика: Проверки ограничений

  1. Объясните каждое ограничение базового compose.
  2. Покажите healthcheck и запрос predict отдельно.
  3. Проверьте, что код нельзя изменить внутри контейнера, а учебные события можно сохранять.
  4. Запишите configured limit и наблюдаемое потребление: почему это разные числа?

Результат: Таблица проверок: ожидаемое поведение / наблюдение / вывод.

Проверка: Все ограничения сохраняют рабочий predict; unhealthy не объявляется автоматическим рестартом.

Неисправность для разбора: Read-only root filesystem включён без writable-volume для событий.

Решение и диагностика

Базовый compose уже имеет лимиты, /data volume, tmpfs /tmp и healthcheck стандартной библиотекой Python. Проверьте docker compose ps после времени start_period; docker compose exec app id; docker compose exec app rm /data/test-write. Если healthcheck не проходит, сначала изучите его вывод через docker inspect, затем реальный ответ сервиса. Не снижайте защиту целиком ради одной настройки.

Основные выводы

Самостоятельная работа

Составить checklist контейнерного запуска и предложить healthcheck для реального ML-API.

Источники