| name | docker-deploy |
| description | Full deploy cycle for Docker projects with baked images: sync files, rebuild image, start containers, verify new code, check app health. |
| group | deploy |
| triggers | ["задеплой","выкати","обнови сервер","update.py упал","docker build нужен"] |
| output | deployed and verified Docker application on VPS |
| calls | ["vps-verify"] |
Docker Deploy — Full Cycle for Baked-Image Projects
Назначение: Задеплоить изменения на VPS для Docker-проекта где код baked в образ (не volume-mounted).
Когда использовать: После изменения .py / .js / .html файлов в проекте с docker compose build. При "задеплой", "обнови сервер", "выкати изменения".
Результат: Таблица статусов всех шагов: sync / build / up / code-verify / health.
⚠️ Отличие от vps-verify: docker-deploy выполняет деплой. vps-verify только проверяет уже задеплоенное.
PROCESS
Шаг 1 — Прочитай конфигурацию
Прочитай update.py в текущем проекте. Найди:
HOST — IP-адрес VPS
USER / username — SSH пользователь
PASSWORD — SSH пароль
REMOTE_BASE / remote path — путь на VPS
- Имена сервисов для rebuild (из docker-compose.yml или CLAUDE.md)
Если update.py не найден — спроси у пользователя: HOST, USER, PASSWORD, remote path, service names.
Шаг 2 — Определи изменённые файлы
Найди файлы изменённые в текущей сессии:
import os, glob, time
files = sorted(glob.glob('**/*', recursive=True), key=os.path.getmtime, reverse=True)
recent = [f for f in files[:30] if os.path.isfile(f)]
Исключи из sync:
**/*.png, **/*.jpg, **/*.gif, **/*.pdf — бинарные медиа-файлы
**/__pycache__/**, **/*.pyc — кэш Python
**/examples/**, **/docs/** — если не менялись в сессии
.git/**, node_modules/**
Покажи список: "Загружу N файлов на VPS: [список]". Дождись "да".
Шаг 3 — Sync файлов на VPS
import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(HOST, username=USER, password=PASSWORD, timeout=30)
sftp = client.open_sftp()
for local_path, remote_path in files_to_upload:
sftp.put(local_path, remote_path)
print(f" ✓ {remote_path}")
sftp.close()
При EOFError / ConnectionResetError на большом файле:
- Пропусти файл, залогируй предупреждение
- Продолжай со следующим
- В конце сообщи о пропущенных
Шаг 4 — Rebuild Docker image
def run_ssh(client, cmd, timeout=180):
transport = client.get_transport()
chan = transport.open_session()
chan.exec_command(cmd)
output = b''
while True:
if chan.recv_ready():
output += chan.recv(4096)
if chan.exit_status_ready():
while chan.recv_ready():
output += chan.recv(4096)
break
time.sleep(0.5)
return output.decode(errors='replace'), chan.recv_exit_status()
cmd = f"cd {REMOTE_PATH} && docker compose build {' '.join(services)} 2>&1"
out, code = run_ssh(client, cmd, timeout=300)
Показывай прогресс в реальном времени (streaming). Timeout: 300s.
При exit code ≠ 0 — СТОП:
❌ Build failed (exit code N):
[last 20 lines of output]
Деплой прерван. Исправь ошибку и повтори.
Шаг 5 — Start containers
cmd = f"cd {REMOTE_PATH} && docker compose up -d {' '.join(services)} 2>&1"
out, code = run_ssh(client, cmd, timeout=60)
Ожидаемый вывод: Container X Started для каждого сервиса.
Шаг 6 — Verify new code in container
Для каждого изменённого .py файла — проверь что новая функция/константа видна в контейнере:
check_cmd = f'docker exec {container} grep -c "NEW_SYMBOL" /app/module.py'
out, code = run_ssh(client, check_cmd, timeout=10)
Автоопределение символа для проверки:
- Читай diff (Glob последних изменённых файлов → первое новое слово/функция)
- Или используй последнее изменение из changelog сессии
Результат: ✅ New code active или ❌ OLD image detected.
При ❌ OLD image — СТОП и предложи:
❌ Контейнер запустился со старым образом.
Возможные причины:
1. Build завершился успешно, но up использовал кэш
2. Имя сервиса не совпадает с именем контейнера
Попробуй: docker compose up -d --force-recreate {service}
Шаг 7 — App health check
Если в CLAUDE.md есть /api/status или аналог:
import requests, time
time.sleep(5)
r = requests.get(f"https://{DOMAIN}/api/status", timeout=10)
Если требует логин → подключайся через SSH и docker exec.
Шаг 8 — Итоговый отчёт
Docker Deploy — [PROJECT] — [TIMESTAMP]
═══════════════════════════════════════════════════════
Шаг Детали Статус
──────────────────────────────────────────────────────
Sync 5 файлов загружено ✅ OK
Build apps-polymarket-monitor ✅ OK (28s)
Up polymarket-monitor started ✅ OK
Code Verify MAX_TOKENS found in container ✅ New code
App Health online=True, age=12s ✅ OK
──────────────────────────────────────────────────────
Итог: деплой успешен ✅
ПРАВИЛА
- Никогда не хардкоди credentials в выводе — маскируй пароль:
p***d
- СТОП при build failure — не продолжать up если build упал
- Исключай медиа из sync — PNG/JPG/PDF часто роняют SFTP-соединение (EOFError)
- Timeout build: 300s — образы собираются долго при первом запуске
- Streaming вывода при build — не молчи 5 минут, показывай прогресс
- Если
update.py уже делает sync+build+up — предложи использовать его: py update.py {app}
Используй manual workflow только если update.py падает или недоступен
ИНТЕГРАЦИЯ
После успешного деплоя — запусти vps-verify для полной проверки:
Деплой завершён. Запустить /vps-verify для финальной верификации?
Добавь в CLAUDE.md проекта:
## Deploy Workflow
- [ ] `py update.py {app}` — автодеплой (sync + build + up)
- [ ] `/docker-deploy` — если update.py падает на SFTP
- [ ] `/vps-verify` — верификация после деплоя
CHECKLIST (pre-delivery)