Продвинутый · Инфраструктура

DevOps & Docker

Как Claude Code работает с Docker-контейнерами через MCP, настраивает WSL2 и Caddy, и не ломает продакшн. Полный разбор — от основ до безопасности.

MCP вместо Bash 15+ инструментов WSL2 · Caddy

Зачем Docker в связке с Claude Code

Docker упаковывает приложение со всеми зависимостями в изолированный «контейнер» — он работает одинаково на любой машине. Для Claude Code это важно: CC может запускать команды, миграции и тесты внутри контейнера, не засоряя вашу систему и не завися от локальных версий PHP/Python/Node.

Главный принцип страницы: на Windows + WSL2 не давайте CC выполнять docker через Bash — это ненадёжно. Используйте MCP-инструменты mcp__docker__*, которые работают через Docker SDK напрямую.

Четыре понятия, которые нужно знать

Image (Образ)
Шаблон, «слепок» приложения. Неизменяем. Например postgres:16. Из образа создаются контейнеры.
Container (Контейнер)
Запущенный экземпляр образа — живой процесс. Можно запустить, остановить, удалить. Имя: my-project-backend-1.
Volume (Том)
Постоянное хранилище данных. Переживает перезапуск контейнера. Здесь живёт БД — удалить = потерять всё.
Network (Сеть)
Виртуальная сеть между контейнерами. Они видят друг друга по имени. БД — только во внутренней сети.

Что Claude Code умеет с Docker

Запускать команды
Миграции, artisan, alembic, pytest внутри контейнера
Читать логи
Логи отдельного сервиса или всего стека для отладки
Управлять стеком
Запуск, остановка, перезапуск контейнеров compose
Мониторить ресурсы
CPU/RAM, health-check, поиск OOM и боттлнеков
Писать compose
Генерация docker-compose.yml по вашим правилам
Настраивать сети
Создание сетей, подключение к Caddy reverse proxy

Docker через MCP (не через Bash)

На Windows с WSL2 прямые docker команды из Claude Code часто не работают из-за PATH. Кроме того, Bash hook в настройках блокирует их явно. Правило: всегда использовать mcp__docker__* инструменты.

💡
Почему MCP, а не Bash? MCP docker-инструменты используют Docker SDK напрямую, минуя shell. Это безопаснее, предсказуемее и не зависит от PATH. Bash hook (bash-mcp-guard.cjs) перехватит любой docker exec и предложит альтернативу.
❌ НЕТ Bash команды
docker exec -it backend-1 php artisan route:list docker logs -f backend-1 docker compose ps
✅ ДА MCP инструменты
mcp__docker__docker_exec container: "backend-1" command: "php artisan route:list" mcp__docker__docker_container_logs container: "backend-1" mcp__docker__docker_compose_ps path: "E:/Clients/project"

Полный справочник Docker MCP инструментов

MCP инструментАналог docker командыКогда использовать
docker_execdocker exec -itЗапуск команд внутри контейнера
docker_container_logsdocker logsПросмотр логов контейнера
docker_list_containersdocker ps -aСписок всех контейнеров
docker_inspect_containerdocker inspectДетальная информация о контейнере
docker_container_statsdocker statsCPU/RAM использование
docker_start_containerdocker startЗапустить остановленный контейнер
docker_stop_containerdocker stopОстановить контейнер
docker_restart_containerdocker restartПерезапустить контейнер
docker_compose_psdocker compose psСтатус compose-стека
docker_compose_logsdocker compose logsЛоги всего стека
docker_compose_updocker compose up -dЗапуск стека
docker_compose_downdocker compose downОстановка стека (без --volumes!)
docker_compose_restartdocker compose restartПерезапуск сервиса в стеке
docker_list_imagesdocker imagesСписок образов
docker_create_networkdocker network createСоздать сеть
docker_list_networksdocker network lsСписок сетей

Подключение Docker MCP

Глобальные MCP-серверы прописываются в ~/.claude.json (не в settings.json, не в settings.local.json). Три точки входа покрывают все Docker-потребности:

// ~/.claude.json — глобальные MCP-серверы { "mcpServers": { "MCP_DOCKER": { "command": "docker", "args": ["mcp", "gateway", "run"] // Gateway: context7, fetch, memory, playwright... }, "ruflo": { "type": "http", "url": "http://localhost:3100/mcp" // HTTP-сервер: агенты, swarm, vector memory } } }
⚠️
Bash(docker*) — запрещён в deny-листе. Все Docker-операции только через mcp__MCP_DOCKER__* инструменты. Docker Desktop должен быть запущен с WSL2 backend.

WSL2 — настройка памяти

На Windows Server 2025 с 47 GB RAM конфигурация WSL2 критична для Docker. OOM убивал PostgreSQL при ETL-операциях — решение зафиксировано.

# C:\Users\Администратор\.wslconfig # Применить: wsl --shutdown (потом перезапустить Docker Desktop) [wsl2] memory=38GB # 80% от 47GB — Windows-хосту остаётся 9GB swap=2GB # Большой swap маскирует OOM и замедляет работу localhostForwarding=true [experimental] hostAddressLoopback=true # Контейнеры видят host.docker.internal
Правило памяти: WSL2 = 80% RAM. Swap = минимальный (2GB). Большой swap создаёт иллюзию достаточности памяти, но приводит к деградации производительности.

Caddy Reverse Proxy

Все публичные домены проксируются через Caddy. Caddy — единственный сервис, занимающий порты 80/443. Никакой другой контейнер не биндится на эти порты.

Расположение и управление

# Папка прокси E:\Clients\Windows\proxy\ # CLI управление (PowerShell) proxy.cmd list # Текущие маршруты + TLS даты proxy.cmd add site.ru container-name:80 # Добавить домен proxy.cmd connect my-network # Подключить Caddy к сети сайта proxy.cmd backup # Архив + сертификаты LE

Текущая маршрутизация

Снимок на момент написания — актуальный список даёт proxy list.

ДоменUpstream
phone.rosveb.ruphone-rosveb-ru-frontend-1:3000
/api/* → phone-rosveb-ru-backend-1:8000
massage.rosveb.ruproject-nginx-1:80
dev.gulaev.rugulaev-nginx:80
notal.rosveb.runotal-nginx:80
gis.rosveb.rucatalog_nginx:80

Добавление нового сайта — чек-лист

# 1. Подключить Caddy к сети сайта proxy connect <имя-docker-сети> # 2. Добавить маршрутизацию proxy add new-site.example.ru container-name:80 # 3. Адаптация приложения под reverse proxy: # Laravel — в AppServiceProvider или bootstrap/app.php: URL::forceScheme(request()->isSecure() ? 'https' : 'http'); # + TrustProxies middleware с указанием Caddy IP # Next.js / Nuxt: NEXT_PUBLIC_SITE_URL=https://new-site.example.ru # FastAPI: uvicorn main:app --proxy-headers --forwarded-allow-ips='*'
🚫
НЕ публиковать порты 80/443 в docker-compose.yml для своих сервисов — они заняты Caddy. Dev-доступ — только через свободные порты из PORTS.md (например :8011).

Docker Compose — лучшие практики

Шаблон compose для Laravel-проекта

# docker-compose.yml services: backend: build: . container_name: my-project-backend-1 networks: - internal - proxy # Caddy видит этот контейнер environment: - APP_ENV=production depends_on: db: condition: service_healthy db: image: postgres:16 container_name: my-project-db-1 volumes: - pg_data:/var/lib/postgresql/data networks: - internal # ТОЛЬКО внутренняя сеть, не proxy! healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 10s timeout: 5s retries: 5 networks: internal: proxy: external: true # Создана через proxy connect volumes: pg_data:
💡
Именование контейнеров: используй паттерн <проект>-<сервис>-1. Это совпадает с автоматическим именованием Compose и важно для Caddy, который обращается по имени через embedded DNS.
⚠️
Частая ошибка новичков: команда docker compose down --volumes уничтожает все named volumes — включая данные PostgreSQL. Если вы попросили CC «перезапустить стек», убедитесь что он не добавил флаг --volumes. Используйте docker_compose_down через MCP (без флага), а данные БД всегда держите в named volumes, а не в bind mounts.

Выполнение команд внутри контейнеров

Laravel Artisan через Docker MCP

// Вместо: docker exec -it backend-1 php artisan migrate // Использовать MCP инструмент: mcp__docker__docker_exec({ container: "phone-rosveb-ru-backend-1", command: "php artisan migrate --force" }) // Очередь (queue worker) — проверить статус: mcp__docker__docker_exec({ container: "phone-rosveb-ru-backend-1", command: "php artisan queue:work --once" })
⚠️
laravel-boost MCP предоставляет специализированные инструменты для Laravel: роуты, модели, события — напрямую через MCP без docker exec. Предпочитать его для Laravel-специфичных операций.

Python / FastAPI команды

mcp__docker__docker_exec({ container: "python-etl-app-1", command: "alembic upgrade head" // Миграции }) mcp__docker__docker_exec({ container: "python-etl-app-1", command: "python -m pytest tests/ -v" // Тесты })

Health Checks и мониторинг

// Проверить здоровье всех контейнеров: mcp__docker__docker_container_health_check({ container: "backend-1" }) // CPU/RAM статистика: mcp__docker__docker_container_stats({ container: "backend-1" }) // Inspect — сети, порты, env (без secrets): mcp__docker__docker_inspect_container({ container: "backend-1" })

Признаки OOM и решение

СимптомДиагнозРешение
Контейнер перезапускается самOOM killerУменьшить shared_buffers в PG, увеличить WSL2 memory
Exit code 137SIGKILL от OOMСнизить max_parallel_workers в PG
Медленные запросы при ETLSwap активенСнизить work_mem, добавить батчинг
PG не стартуетshared_buffers > 25% WSL2ALTER SYSTEM SET shared_buffers = '4GB'

Безопасность контейнеров

# Никогда не делать в docker-compose: ports: - "5432:5432" # PostgreSQL напрямую в интернет! - "6379:6379" # Redis без аутентификации! # Правильно — только внутренние сети: networks: - internal # Только для межсервисного общения # БД не имеет секции ports вообще
🚫
critical-files-guard.cjs блокирует изменение docker-compose.production.yml. Для редактирования — установить переменную CONFIRM_CRITICAL=yes или изменить вручную.

Docker + Claude Code: плюсы и минусы

Плюсы
  • Изоляция: CC не трогает вашу систему, работает в контейнере
  • Воспроизводимость: одинаково на dev и prod
  • MCP даёт предсказуемый, безопасный доступ без shell
  • CC видит логи и статус — отлаживает по реальным данным
  • Откат: пересоздать контейнер проще, чем чинить систему
Минусы и риски
  • Кривая обучения: образы, тома, сети — надо понять
  • На Windows нужен WSL2 + правильная настройка памяти
  • Bash-команды docker ненадёжны — только MCP
  • down --volumes может уничтожить данные БД
  • Опубликованные порты БД = дыра в безопасности

Типовые ошибки

Частые вопросы

На Windows + WSL2 docker в Bash зависит от PATH и часто молча падает. MCP-инструменты используют Docker SDK напрямую — надёжнее и безопаснее. Bash-хук блокирует docker и предлагает MCP-альтернативу.
Пропишите MCP-сервер MCP_DOCKER в ~/.claude.json (см. «Подключение»). Docker Desktop должен работать с WSL2 backend. После этого CC получит доступ к mcp__docker__*.
Держите данные в named volumes, добавьте docker compose down --volumes в deny-лист, используйте docker_compose_down через MCP. Регулярные бэкапы тома обязательны.
Exit 137 = SIGKILL от OOM: не хватило памяти. Увеличьте WSL2 memory, снизьте shared_buffers и max_parallel_workers в PostgreSQL, добавьте батчинг в ETL.
Нет. Для старта CC работает с обычными локальными проектами. Docker нужен, когда проект уже в контейнерах или вы деплоите на сервер. Изучайте по мере необходимости.
Три шага: proxy connect <сеть>, proxy add домен container:port, адаптация под reverse proxy (TrustProxies в Laravel, --proxy-headers в FastAPI). Не публикуйте порты 80/443 в своём compose.