Пара 15 / ноябрь
Compose: сеть, тома и декларативный запуск Запустить сервис с постоянным томом и объяснить адреса внутри Compose.
Запустить сервис с постоянным томом и объяснить адреса внутри Compose. compose.yaml задаёт сервисы и настройки. docker compose config проверяет и раскрывает конфигурацию, up -d приводит запуск к описанию, ps и logs показывают состояние. YAML чувствителен к отступам; проверка config дешевле долгого поиска ошибки запуска. В современном Compose не нужен устаревший верхний ключ version. Переменные .env для подстановки Compose и environment для процесса — разные механизмы: наличие файла само по себе не гарантирует, что значение попало в контейнер. В нашем минимальном compose все нужные настройки явны, а расширение monitoring подключается отдельным файлом в декабре.
Контекст Файл конфигурации связывает образы, сеть и хранилище.
Запустить сервис с постоянным томом и объяснить адреса внутри Compose.
compose.yaml задаёт сервисы и настройки. docker compose config проверяет и раскрывает конфигурацию, up -d приводит запуск к описанию, ps и logs показывают состояние. YAML чувствителен к отступам; проверка config дешевле долгого поиска ошибки запуска. В современном Compose не нужен устаревший верхний ключ version. Переменные .env для подстановки Compose и environment для процесса — разные механизмы: наличие файла само по себе не гарантирует, что значение попало в контейнер. В нашем минимальном compose все нужные настройки явны, а расширение monitoring подключается отдельным файлом в декабре.
Compose описывает желаемый запуск Файл конфигурации связывает образы, сеть и хранилище.
01 compose.yaml
→ 02 Проверка config
→ 03 Сеть + том
→ 04 Запуск сервисов
Аналогия: список участников, помещений и оборудования одной лаборатории.
compose.yaml задаёт сервисы и настройки. docker compose config проверяет и раскрывает конфигурацию, up -d приводит запуск к описанию, ps и logs показывают состояние. YAML чувствителен к отступам; проверка config дешевле долгого поиска ошибки запуска. В современном Compose не нужен устаревший верхний ключ version. Переменные .env для подстановки Compose и environment для процесса — разные механизмы: наличие файла само по себе не гарантирует, что значение попало в контейнер. В нашем минимальном compose все нужные настройки явны, а расширение monitoring подключается отдельным файлом в декабре.
Имена сервисов и внутренние порты Внутри сети Compose используем имя сервиса, а не порт хоста.
01 Клиент → localhost:8000
02 Сеть Compose
03 app:8000
04 prometheus:9090
Аналогия: номер внутреннего телефона отличается от городского номера.
Сервисы в общей сети могут обращаться по имени service, которое разрешает Docker DNS. Prometheus позже будет читать http://app:8000/metrics. localhost внутри prometheus указывал бы на prometheus, а не app. Host port 8000 нужен клиенту на ноутбуке; внутренний port 8000 нужен соседнему контейнеру. Публикуем наружу только необходимые интерфейсы и для учебного запуска привязываем их к 127.0.0.1. Не переносим приватную сеть Compose в публичную DNS-зону. Отдельная сеть ограничивает случайное смешивание учебных проектов, но не заменяет полноценную авторизацию.
Named volume и bind mount Данные не должны случайно зависеть от срока жизни контейнера.
01 Контейнер → /data
→ 02 Named volume
→ 03 Пересоздание
→ 04 Данные остаются
Аналогия: квартира меняет жильца, а отдельное хранилище не выбрасывается вместе с мебелью.
Изменяемый слой контейнера удаляется с контейнером. Named volume хранится отдельно и управляется Docker; bind mount показывает выбранный каталог хоста. В курсе named volume data хранит events.jsonl. Compose down удаляет контейнеры и сеть, но без -v оставляет именованные тома. down -v разрушает учебные данные; его не используем для обычной остановки. Volume — не резервная копия: ошибка приложения или удаления может повредить данные. Bind mount удобен для разработки, но права, путь и содержимое хоста становятся частью поведения.
Команды и наблюдения Ubuntu / Bash, lab
docker compose config --quiet
docker compose up -d --build
docker compose ps
curl -sS -H "Content-Type: application/json" -d '{"hours":4}' http://127.0.0.1:8000/predict
docker compose exec app cat /data/events.jsonl
docker compose up -d --force-recreate app
docker compose exec app cat /data/events.jsonlКоманда force-recreate затрагивает только app в собственной учебной Compose-папке. Перед опытом освобождаем порт от предыдущих демонстраций. Ожидаемое наблюдение: Запись запроса остаётся в events.jsonl после пересоздания app.
Разбор результата Запись запроса остаётся в events.jsonl после пересоздания app.
Команда force-recreate затрагивает только app в собственной учебной Compose-папке. Перед опытом освобождаем порт от предыдущих демонстраций.
Проверка: docker compose exec app wc -l /data/events.jsonl до и после down/up. Том связан с Compose project, поэтому запуск из другой папки или с другим -p может показать другой том. Диагностика: docker compose ls, docker volume ls, docker inspect только собственного app. Не удалять том ради восстановления «правильного» имени.
На macOS Compose-команды одинаковы. Named volumes живут в Linux-среде Desktop; bind mount проходит через механизм обмена файлами macOS и может отличаться по скорости и правам. Не использовать down -v для обычной остановки.
docker compose config --quiet
docker compose up -d --build
docker compose ps
docker compose downКоманды macOS необходимо проверить на конкретном устройстве. Compose-команды одинаковы. Named volumes живут в Linux-среде Desktop; bind mount проходит через механизм обмена файлами macOS и может отличаться по скорости и правам. Не использовать down -v для обычной остановки.
Состояние переживает пересоздание Поднимите базовый compose, сделайте три POST-запроса. Проверьте /data/events.jsonl и сохраните количество строк. Выполните down без -v, затем up -d. Убедитесь, что старые записи доступны; объясните, почему это ещё не backup. Работа в парах: один оператор, второй проверяет гипотезу. Смена ролей в середине. Проверка: docker compose exec app wc -l /data/events.jsonl до и после down/up. Том связан с Compose project, поэтому запуск из другой папки или с другим -p может показать другой том. Диагностика: docker compose ls, docker volume ls, docker inspect только собственного app. Не удалять том ради восстановления «правильного» имени.
Что должно получиться compose.yaml и доказательство сохранности записей.
Данные переживают смену контейнера; опубликованные порты ограничены localhost.
Проверка: docker compose exec app wc -l /data/events.jsonl до и после down/up. Том связан с Compose project, поэтому запуск из другой папки или с другим -p может показать другой том. Диагностика: docker compose ls, docker volume ls, docker inspect только собственного app. Не удалять том ради восстановления «правильного» имени.
Ошибка для диагностики Использование down -v стирает именованный том.
Симптом → Гипотеза → Проверка
Проверка: docker compose exec app wc -l /data/events.jsonl до и после down/up. Том связан с Compose project, поэтому запуск из другой папки или с другим -p может показать другой том. Диагностика: docker compose ls, docker volume ls, docker inspect только собственного app. Не удалять том ради восстановления «правильного» имени.
Основные выводы По имени app и внутреннему порту 8000. Нет, он обеспечивает отдельное хранение, но не независимое восстановление. По имени app и внутреннему порту 8000.
Нет, он обеспечивает отдельное хранение, но не независимое восстановление.
После пары Задокументировать назначение тома и команды безопасной остановки проекта.
Конспект, команды и разбор → Проверьте критерии сдачи и дайте возможность повторной попытки. Первоисточники: https://docs.docker.com/compose/ https://docs.docker.com/engine/storage/volumes/
localhost зависит от точки зрения Prometheus хочет прочитать метрики app.
http://localhost:8000 http://app:8000 prometheus → ? app
Выберите адрес внутри сети Compose Внутри контейнера localhost означает этот контейнер. В теме Linux предварительно подчеркните, что это мысленный пример будущего Compose.
Пара 16 / ноябрь
Готовность, ограничения и конфигурация контейнеров Проверить healthcheck, задать лимиты и не путать порядок запуска с готовностью.
Проверить healthcheck, задать лимиты и не путать порядок запуска с готовностью. Running означает, что процесс контейнера не завершился. Healthcheck выполняет отдельную проверку и присваивает состояние healthy/unhealthy. В нашем примере он вызывает /healthz. Не каждый healthcheck проверяет все зависимости: он должен иметь понятный смысл. Readiness — готовность обслуживать запросы, liveness — жизнеспособность процесса; в разных платформах это отдельные механизмы. Docker сам по себе не обязательно перезапускает unhealthy-контейнер: restart policy обычно реагирует на завершение процесса. Поэтому важны мониторинг и реакция, а не только зелёная метка.
Контекст Процесс существует, проверка проходит и пользовательский путь работает — разные факты.
Проверить healthcheck, задать лимиты и не путать порядок запуска с готовностью.
Running означает, что процесс контейнера не завершился. Healthcheck выполняет отдельную проверку и присваивает состояние healthy/unhealthy. В нашем примере он вызывает /healthz. Не каждый healthcheck проверяет все зависимости: он должен иметь понятный смысл. Readiness — готовность обслуживать запросы, liveness — жизнеспособность процесса; в разных платформах это отдельные механизмы. Docker сам по себе не обязательно перезапускает unhealthy-контейнер: restart policy обычно реагирует на завершение процесса. Поэтому важны мониторинг и реакция, а не только зелёная метка.
Running, healthy, ready Процесс существует, проверка проходит и пользовательский путь работает — разные факты.
01 Running
→ 02 Healthcheck
→ 03 Ready
→ 04 Пользовательский запрос
Аналогия: свет в кафе горит, кухня готова и заказ выдан — три проверки.
Running означает, что процесс контейнера не завершился. Healthcheck выполняет отдельную проверку и присваивает состояние healthy/unhealthy. В нашем примере он вызывает /healthz. Не каждый healthcheck проверяет все зависимости: он должен иметь понятный смысл. Readiness — готовность обслуживать запросы, liveness — жизнеспособность процесса; в разных платформах это отдельные механизмы. Docker сам по себе не обязательно перезапускает unhealthy-контейнер: restart policy обычно реагирует на завершение процесса. Поэтому важны мониторинг и реакция, а не только зелёная метка.
Зависимости Compose Порядок старта не гарантирует завершение инициализации.
01 Старт базы
→ 02 Инициализация
→ 03 Healthcheck OK
→ 04 Старт app
Аналогия: открыть дверь склада не значит закончить приёмку товаров.
depends_on задаёт зависимость порядка запуска. При condition: service_healthy Compose может дождаться healthcheck зависимости перед запуском потребителя. Это не постоянный контроль её доступности и не магическая защита после сбоя. Приложению всё равно нужны timeout, ограниченные retry и понятное поведение при отказе. В нашем сервисе нет внешней базы, поэтому не добавляем искусственную зависимость ради YAML. На схеме обсуждаем будущий вариант app → база и отмечаем, что старт и готовность могут разойтись во времени.
Предел ресурсов и поверхность доступа Ограничиваем ущерб и наблюдаем результат ограничения.
01 Лимит CPU / RAM
02 Non-root
03 Readonly + /data
04 Наблюдение stats
Аналогия: лабораторная работает в пределах выделенного бюджета, а не занимает всё здание.
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 показывает потребление.
Разбор результата Healthcheck становится healthy; запись в /app отказана, в /data разрешена; stats показывает потребление.
Отказ touch /app/test-write — ожидаемый результат политики, не дефект курса. Удалите собственный /data/test-write после проверки.
Базовый 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, затем реальный ответ сервиса. Не снижайте защиту целиком ради одной настройки.
На macOS Healthcheck и ограничения выполняются внутри Linux-VM Docker Desktop. Показатели контейнера не равны всему потреблению macOS. Проверяйте выделенный Desktop бюджет CPU/RAM и доступность устройства.
docker stats --no-stream
docker compose ps
docker compose exec app idКоманды macOS необходимо проверить на конкретном устройстве. Healthcheck и ограничения выполняются внутри Linux-VM Docker Desktop. Показатели контейнера не равны всему потреблению macOS. Проверяйте выделенный Desktop бюджет CPU/RAM и доступность устройства.
Проверки ограничений Объясните каждое ограничение базового compose. Покажите healthcheck и запрос predict отдельно. Проверьте, что код нельзя изменить внутри контейнера, а учебные события можно сохранять. Запишите configured limit и наблюдаемое потребление: почему это разные числа? Работа в парах: один оператор, второй проверяет гипотезу. Смена ролей в середине. Базовый 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, затем реальный ответ сервиса. Не снижайте защиту целиком ради одной настройки.
Что должно получиться Таблица проверок: ожидаемое поведение / наблюдение / вывод.
Все ограничения сохраняют рабочий predict; unhealthy не объявляется автоматическим рестартом.
Базовый 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, затем реальный ответ сервиса. Не снижайте защиту целиком ради одной настройки.
Ошибка для диагностики 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, затем реальный ответ сервиса. Не снижайте защиту целиком ради одной настройки.
Основные выводы Нет, healthcheck и restart policy имеют разные механизмы. Ожидание готовности зависимости при запуске, но не гарантию её вечной доступности. Нет, healthcheck и restart policy имеют разные механизмы.
Ожидание готовности зависимости при запуске, но не гарантию её вечной доступности.
После пары Составить checklist контейнерного запуска и предложить healthcheck для реального ML-API.
Конспект, команды и разбор → Проверьте критерии сдачи и дайте возможность повторной попытки. Первоисточники: https://docs.docker.com/compose/how-tos/startup-order/ https://docs.docker.com/reference/compose-file/services/