> Как дебажить в Docker контейнере (Python)

Уровень: senior · Роль: backend · Язык: Python · Категория: Технические вопросы

Компании: Sunlight

Стек: Python, Docker

> Пример ответа

Короткий ответ

Дебаг в Docker сводится к трём уровням: логи приложения, инспекция контейнера и подключение отладчика. Основные инструменты - docker logs, docker exec, docker inspect, а для Python - pdb или debugpy с пробросом порта. Ключевой момент - не пересобирать образ ради каждой правки, а использовать volume mount для кода и live-reload. Для production-среды - централизованный сбор логов и remote debugging через отдельный debug-сервис.

Подробное объяснение

Деббаг в контейнере отличается от локального тем, что процесс изолирован, файловая система эфемерна, а сеть ограничена. Основные подходы:

  1. Логи - самый быстрый способ. docker logs <container> показывает stdout/stderr. Для Python используй logging с выводом в stdout, а не в файл - иначе логи не попадут в Docker.

  2. Инспекция состояния - docker inspect даёт полную информацию о конфигурации, network, mounts, environment variables. docker exec -it <container> bash открывает shell внутри контейнера.

  3. Volume mount - монтируй исходники в контейнер: -v $(pwd):/app. Тогда правки кода применяются без пересборки образа. Для Python добавь --reload в uvicorn/gunicorn.

  4. Remote debugging - для Python используй debugpy. Установи его в образ, запусти с --listen 0.0.0.0:5678, пробрось порт -p 5678:5678 и подключись из IDE (VS Code, PyCharm).

  5. Debug-режим в compose - отдельный сервис с профилем debug, который включает отладчик, verbose-логирование и hot-reload. Production-сервис остаётся чистым.

  6. Снимки состояния - docker commit создаёт образ из текущего состояния контейнера, что полезно для воспроизведения бага.

На практике

Для senior-позиции важно показать системный подход. Начни с воспроизведения: запусти контейнер с теми же environment variables и volume mounts, что и в проде. Затем:

  • Проверь, что контейнер вообще стартует: docker ps -a, docker logs.
  • Если стартует, но падает - добавь --entrypoint для запуска с pdb или ipdb.
  • Если проблема в сети - docker exec внутрь и проверь curl до зависимых сервисов.
  • Для сложных багов - подключи debugpy и ставь breakpoints в IDE.

Для production-багов используй docker cp для извлечения файлов, docker export для полного дампа файловой системы, и docker events для отслеживания lifecycle-событий.

Пример кода

# Dockerfile.debug
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install debugpy
COPY . .
CMD ["python", "-m", "debugpy", "--listen", "0.0.0.0:5678", "--wait-for-client", "app.py"]
YAML
# docker-compose.debug.yml
services:
app:
build:
context: .
dockerfile: Dockerfile.debug
ports:
- "8000:8000"
- "5678:5678"
volumes:
- .:/app
environment:
- DEBUG=1
PYTHON
# app.py
import debugpy
if os.getenv("DEBUG"):
debugpy.listen(("0.0.0.0", 5678))
print("Waiting for debugger attach...")
debugpy.wait_for_client()
# твой код

Как отвечать на собеседовании

Структурируй ответ по уровням сложности: от простого к сложному. Начни с логов, затем exec, затем remote debugging. Обязательно упомяни trade-off между удобством дебага и безопасностью - debug-порт не должен быть доступен извне в production. Покажи понимание lifecycle контейнера: почему docker logs не показывает логи из файла, почему volume mount быстрее пересборки. Приведи реальный кейс из практики, например, дебаг race condition или утечки памяти.

Что проверяет интервьюер

  • Понимание изоляции процессов и эфемерности контейнеров.
  • Умение работать с Docker CLI и compose.
  • Знание специфики Python-отладки в контейнере.
  • Способность выбрать правильный инструмент под задачу.
  • Понимание production-ограничений: безопасность, производительность, observability.

Типичные ошибки

  • Попытка использовать gdb или strace без установки в образ - они отсутствуют в slim-образах.
  • Запуск отладчика на порту, который не проброшен наружу.
  • Использование docker attach вместо docker exec - attach привязан к PID 1 и ломает lifecycle.
  • Монтирование volume поверх директории с зависимостями - например, -v .:/app затирает установленные пакеты.
  • Забывают про --init для корректной обработки сигналов - без него Ctrl+C не остановит Python-процесс.
  • Дебаг в production-контейнере напрямую вместо воспроизведения в staging-окружении.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью