type: standard
title: "Эксплуатация платформы"
status: active
version: 1.0.0
date: 2026-04-10
knowledge_level: У1
Объединённый стандарт эксплуатации: мониторинг, деплой, Docker/Drupal, очистка, создание проектов, оценка времени.
СНАЧАЛА найти причину, ПОТОМ чистить.
Резкий рост диска (>5% в час) — симптом проблемы: утечка логов, зацикленный процесс, атака. Очистка без устранения причины — борьба с симптомами.
| Скорость роста | Классификация | Действия |
|---|---|---|
| < 5% в час | Нормальный | L0 автоочистка при 90%, L1 меню при 95% |
| 5-10% в час | Быстрый | АЛЕРТ "НАЙДИ ПРИЧИНУ" + топ-5 директорий |
| > 10% в час | Критический | АЛЕРТ "СРОЧНО НАЙДИ ПРИЧИНУ" + детальный анализ |
Каждые 30 минут:
1. Проверить текущий % диска
2. Записать в disk_history.json
3. Вычислить рост за последний час
4. IF рост >= 10% в час:
→ КРИТИЧЕСКИЙ АЛЕРТ аномального роста
→ Показать топ-5 директорий
→ Показать активные логи (изменены за 24ч)
→ Показать большие файлы >50MB
→ НЕ предлагать очистку (сначала причину)
5. ELSE IF рост >= 5% в час:
→ АЛЕРТ быстрого роста
→ Показать топ-5 директорий
→ Рекомендовать проверить вручную
6. ELSE IF диск >= 98%:
→ КРИТИЧЕСКИЙ алерт (нужна L2 через SSH)
7. ELSE IF диск >= 95%:
→ L1 меню очистки (интерактивное)
8. ELSE IF диск >= 90%:
→ L0 автоочистка (БЕЗ уведомления если успешно)
# system/monitor/config.yaml
infra:
disk:
warning: 80
critical: 90
emergency: 98
auto_cleanup: true
auto_cleanup_level: L0
auto_cleanup_confirm_L1: false
from commands.diagnostics import detect_anomalous_growth
result = detect_anomalous_growth()
# {"is_anomalous": True, "growth_per_hour": 7.5, "current_percent": 93, "severity": "fast"}
from commands.diagnostics import find_large_directories
dirs = find_large_directories(limit=10)
from commands.diagnostics import find_large_files
files = find_large_files(min_size_mb=50, limit=20)
from commands.diagnostics import get_recent_log_growth
logs = get_recent_log_growth()
from commands.diagnostics import suggest_cleanup_targets
suggestions = suggest_cleanup_targets()
Файл: system/monitor/output/disk_history.json
[
{"time": "2025-12-30T14:00:00", "percent": 85},
{"time": "2025-12-30T14:30:00", "percent": 87}
]
Ротация: последние 24 часа.
КРИТИЧЕСКИЙ РОСТ ДИСКА
Рост: +12.5% за последний час
Текущий: 93%
СНАЧАЛА НАЙДИ ПРИЧИНУ
Топ-5 директорий:
/var/lib/docker: 12.5G
/var/log: 3.2G
/tmp: 1.8G
Активные логи (изменены за 24ч):
/var/log/nginx/access.log: 2.1G
Проверить вручную:
du -sh /var/lib/docker /var/log /tmp /opt | sort -h
# Ротация логов: /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
}
# Docker автоочистка (еженедельно в cron)
0 2 * * 0 docker image prune -a -f --filter "until=168h"
# Мониторинг конкретных путей
# Алерт если /var/log >5GB или /var/lib/docker >20GB
# Активные логи
find /var/log -type f -mtime -1 -size +10M -exec du -h {} \;
# Docker образы
docker images | wc -l
docker system df
# Большие файлы в /tmp
find /tmp -type f -size +50M -exec du -h {} \;
# БД дампы
find /var/backups -name "*.sql.gz" -exec du -h {} \;
# Что занимает место (top 20)
du -sh /* 2>/dev/null | sort -h | tail -20
du -sh /var/* 2>/dev/null | sort -h | tail -20
# Docker размеры
docker system df
# Claude
du -sh ~/.claude/*
/etc/systemd/system/ ← ТОЛЬКО системное (OS-уровень)
Docker compose ← ВСЕ проектные и платформенные сервисы
system/scheduler/ ← ВСЕ расписания (не cron напрямую)
ЗАПРЕЩЕНО создавать .service файлы в /etc/systemd/system/ для проектных сервисов.
| Категория | Где | Примеры |
|---|---|---|
| OS-уровень | systemd | nginx, docker, hub-mount, infra-mount, fail2ban |
| Платформа | Docker | md-viewer, file-share |
| Проекты | Docker | erp, pro1, filemanager, n8n, nocodb |
| Боты | Docker | telegram-vip, любые боты |
| Расписания | scheduler | python3 system/scheduler/run.py --list |
projects/org/{project}/app/{service}/
├── solution/ ← код
├── infrastructure/
│ ├── Dockerfile ← как собрать образ
│ ├── docker-compose.yml ← как запустить
│ └── .env.example ← переменные окружения (без секретов)
└── CLAUDE.md
Конфиг рядом с кодом — переехал проект, конфиг переехал.
FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
services:
app:
build: ../solution
container_name: {project}-{service}
restart: always
ports:
- "8000:8000"
volumes:
- ../solution:/app
- /mnt/beget-s3:/data:ro
env_file:
- ../solution/.env
networks:
- {project}-network
networks:
{project}-network:
driver: bridge
# 1. Создать Dockerfile + docker-compose.yml в infrastructure/
# 2. Проверить запуск
docker compose -f infrastructure/docker-compose.yml up -d
# 3. Убедиться что работает
curl http://localhost:{port}/
# 4. Остановить и отключить systemd
systemctl stop {service}
systemctl disable {service}
# 5. Удалить unit-файл
rm /etc/systemd/system/{service}.service
systemctl daemon-reload
Образ drupal:11.3-php8.3-apache основан на drupal/recommended-project.
/opt/drupal/ ← PROJECT ROOT (composer, vendor, drush)
├── composer.json
├── composer.lock
├── vendor/
│ └── bin/
│ └── drush ← правильный путь к drush
├── config/
│ └── sync/
└── web/ ← WEB ROOT (Apache DocumentRoot)
├── core/
├── modules/
└── sites/
└── default/
├── settings.php
└── files/
/var/www/html → /opt/drupal/web (симлинк)
Критично: /var/www/html — это симлинк на web root, не project root.
# ПРАВИЛЬНО — устанавливать в project root
cd /opt/drupal && composer require drush/drush
# НЕПРАВИЛЬНО — устанавливает в web root (не работает)
cd /var/www/html && composer require drush/drush
# ПРАВИЛЬНО — запуск
/opt/drupal/vendor/bin/drush --root=/opt/drupal/web status
FROM drupal:11.3-php8.3-apache
RUN cd /opt/drupal && composer require drush/drush --no-interaction 2>&1 | tail -3
RUN chown -R www-data:www-data /opt/drupal/vendor
# Обязательно при первом запуске
chown -R www-data:www-data /opt/drupal/web/sites/default/files
chown www-data:www-data /opt/drupal/web/sites/default/settings.php
chown -R www-data:www-data /opt/drupal/web/modules/custom
chown -R www-data:www-data /opt/drupal/web/themes/custom
volumes:
# rw — обязательно, Drupal пишет hash_salt и config_sync_directory
- ./drupal/settings.php:/var/www/html/sites/default/settings.php:rw
Никогда :ro — Drupal не сможет завершить установку.
После drush site:install добавить:
// Разрешить доступ с любого хоста (dev)
$settings['trusted_host_patterns'] = ['^.*$'];
// Или для конкретных доменов (prod)
$settings['trusted_host_patterns'] = [
'^lideravto\.aipd\.ru$',
'^new\.lideravto\.ru$',
];
services:
app:
build: .
volumes:
- drupal-files:/var/www/html/sites/default/files
- ./drupal/settings.php:/var/www/html/sites/default/settings.php:rw
- ./drupal/modules:/var/www/html/modules/custom:rw
- ./drupal/themes:/var/www/html/themes/custom:rw
environment:
DRUPAL_DATABASE_HOST: db
DRUPAL_DATABASE_NAME: ${MYSQL_DATABASE}
DRUPAL_DATABASE_USERNAME: ${MYSQL_USER}
DRUPAL_DATABASE_PASSWORD: ${MYSQL_PASSWORD}
depends_on:
db:
condition: service_healthy
db:
image: mysql:8.4
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
retries: 10
#!/bin/bash
set -e
DRUSH=/opt/drupal/vendor/bin/drush
ROOT=/opt/drupal/web
if ! $DRUSH --root=$ROOT status --field=bootstrap 2>/dev/null | grep -q "Successful"; then
echo "[entrypoint] Installing Drupal..."
$DRUSH --root=$ROOT site:install standard \
--db-url="mysql://${DRUPAL_DATABASE_USERNAME}:${DRUPAL_DATABASE_PASSWORD}@${DRUPAL_DATABASE_HOST}:3306/${DRUPAL_DATABASE_NAME}" \
--site-name="${DRUPAL_SITE_NAME:-Drupal}" \
--account-name=admin \
--account-pass="${DRUPAL_ADMIN_PASS:-Admin2026!}" \
--locale=ru \
--yes
echo "[entrypoint] Drupal installed successfully"
fi
exec "$@"
# Статус
docker exec -u www-data app /opt/drupal/vendor/bin/drush --root=/opt/drupal/web status
# Сбросить кеш
docker exec -u www-data app /opt/drupal/vendor/bin/drush --root=/opt/drupal/web cr
# Включить модуль
docker exec -u www-data app /opt/drupal/vendor/bin/drush --root=/opt/drupal/web en module_name -y
# Сменить пароль admin
docker exec -u www-data app /opt/drupal/vendor/bin/drush --root=/opt/drupal/web user:password admin "NewPass123"
# Установить модуль через composer
docker exec app bash -c "cd /opt/drupal && composer require drupal/module_name"
| Симптом | Причина | Решение |
|---|---|---|
| Сайт показывает install.php | БД пустая | Запустить entrypoint / drush site:install |
sites/default/files не writable |
root:root | chown -R www-data:www-data ...files |
| settings.php не пишется | mount :ro |
Изменить на :rw, пересоздать контейнер |
drush: command not found |
Drush в web root | cd /opt/drupal && composer require drush/drush |
trusted_host_patterns error |
Домен не в списке | Добавить в settings.php |
L0 → Автоматическая (monitor при disk >= 90%)
L1 → С подтверждением (вручную или при disk >= 95%)
L2 → Только вручную (критическая ситуация)
Освобождает: 100-500 MB. Не влияет на сервисы, не требует перезапуска.
| Категория | Команда |
|---|---|
| /tmp (>7 дней) | find /tmp -type f -mtime +7 -delete |
| APT кэш | apt-get clean |
| PIP кэш | rm -rf ~/.cache/pip/* |
| NPM кэш | npm cache clean --force |
| Docker dangling | docker image prune -f |
| Docker volumes dangling | docker volume prune -f |
| Journald | journalctl --vacuum-size=500M |
| Логи ротированные (>7 дней) | find /var/log -name "*.gz" -mtime +7 -delete |
| Claude логи (>7 дней) | find .logs -name "*.log" -mtime +7 -delete |
| Claude temp (>3 дня) | find /tmp -name "claude-*" -mtime +3 -delete |
Скрипт: infra/scripts/cleanup-L0.sh
#!/bin/bash
echo "=== L0: Безопасная очистка ==="
find /tmp -type f -mtime +7 -delete 2>/dev/null
apt-get clean -y >/dev/null 2>&1
rm -rf ~/.cache/pip/* 2>/dev/null
docker image prune -f >/dev/null 2>&1
docker volume prune -f >/dev/null 2>&1
journalctl --vacuum-size=500M >/dev/null 2>&1
find /var/log -name "*.gz" -mtime +7 -delete 2>/dev/null
find /var/log -name "*.1" -mtime +7 -exec truncate -s 0 {} \; 2>/dev/null
find $WORKSPACE/.logs -name "*.log" -mtime +7 -delete 2>/dev/null
find /tmp -name "claude-*" -mtime +3 -delete 2>/dev/null
df -h / | tail -1
Освобождает: 3-8 GB. Требует подтверждения.
| Категория | Риск |
|---|---|
| Docker images (все неиспользуемые) | Потребуется pull |
| Snap packages | Только если не используется |
| Старые бэкапы (>30 дней) | Потеря старых версий |
| venv неактивных проектов (>60 дней) | Потребуется rebuild |
| node_modules неактивных (>60 дней) | Потребуется npm install |
| Claude history (>60 дней) | Потеря старых сессий |
| Git gc | Сжатие репозитория |
| Активные логи >100M | Потеря истории |
Скрипт: infra/scripts/cleanup-L1.sh
#!/bin/bash
echo "=== L1: Средняя очистка ==="
read -p "Продолжить? (yes/no): " confirm
[ "$confirm" != "yes" ] && exit 1
docker system prune -a --volumes -f
find $INFRA/backups -type f -mtime +30 -delete 2>/dev/null
find $WORKSPACE/projects -name "venv" -type d -mtime +60 -exec rm -rf {} \; 2>/dev/null
find $WORKSPACE -name "node_modules" -type d -mtime +60 -exec rm -rf {} \; 2>/dev/null
find ~/.claude/projects -name "*.jsonl" -mtime +60 -exec gzip {} \; 2>/dev/null
cd $WORKSPACE && git gc --aggressive >/dev/null 2>&1
find /var/log -name "*.log" -size +100M -exec truncate -s 50M {} \; 2>/dev/null
df -h / | tail -1
Освобождает: 10-20 GB. Удаляет production данные. Только через SSH.
| Категория | Риск |
|---|---|
| Docker volumes (используемые) | Потеря данных |
| БД дампы | Потеря recovery точек |
| Архивы проектов | Потеря истории |
| Claude сессии (все) | Потеря всех сессий |
| Git objects (агрессивно) | Потеря истории |
Скрипт: infra/scripts/cleanup-L2.sh (подтверждение: DELETE ALL DATA)
if disk >= 98%:
→ Алерт критический
→ НЕ запускать автоочистку (слишком опасно)
→ Требовать ручное вмешательство
elif disk >= 95%:
→ Запустить L0
→ Если не помогло → алерт с предложением L1
elif disk >= 90%:
→ Запустить L0
→ Если помогло → ОК
→ Если не помогло → алерт с рекомендацией L1
bash infra/scripts/cleanup-L0.sh # безопасная (в любое время)
bash infra/scripts/cleanup-L1.sh # средняя (с подтверждением)
bash infra/scripts/cleanup-L2.sh # опасная (только критическая ситуация)
# Добавить в system/monitor/auto_cleanup.sh
RCLONE_SIZE=$(du -sm /tmp/rclone 2>/dev/null | cut -f1)
if [ "$RCLONE_SIZE" -gt 300 ]; then
rm -rf /tmp/rclone
log "Очищен rclone кэш: ${RCLONE_SIZE}MB"
fi
find /tmp -type f -mtime +7 -delete 2>/dev/null
Автоматизированная система создания новых проектов: единообразная структура, валидация, переменные вместо хардкода, синхронизация workspace/dataspace.
Файл: system/config/platform-vars.sh
export WORKSPACE=/opt/claude-workspace
export DATASPACE=/mnt/beget-s3
export INFRA=/mnt/beget-infra
export PROJECTS_NAMESPACE="projects/org"
project_ws() { echo "$WORKSPACE/$PROJECTS_NAMESPACE/$1"; }
project_data() { echo "$DATASPACE/$PROJECTS_NAMESPACE/$1"; }
project_infra() { echo "$INFRA/$PROJECTS_NAMESPACE/$1"; }
ЗАПРЕЩЕНО:
cd /opt/claude-workspace/projects/org/myproject # хардкод
ПРАВИЛЬНО:
source $WORKSPACE/system/config/platform-vars.sh
cd $(project_ws myproject)
$WORKSPACE/projects/org/{name}/ $DATASPACE/projects/org/{name}/
├── CLAUDE.md ├── prices/
├── PROJECT.md ├── images/
├── config/ ├── exports/
└── services/ └── _inbox/
# Интерактивный режим
create-project
# Прямое создание
create-project myproject --type=commercial --nocodb
Шаги:
a-z0-9-_)prices/, images/, exports/, _inbox/)| Шаблон | Файл |
|---|---|
| Коммерческий | architect/templates/PROJECT_COMMERCIAL.md |
| Внутренний | architect/templates/PROJECT_INTERNAL.md |
| Исследовательский | architect/templates/PROJECT_RESEARCH.md |
| Платформа | architect/templates/PROJECT_PLATFORM.md |
Файл: system/scripts/validate-platform.sh
# Проверить конкретный проект
validate-platform myproject
# Проверить все проекты
validate-platform
Проверки:
- Соответствие workspace/dataspace
- Наличие обязательных файлов (CLAUDE.md, PROJECT.md)
- Отсутствие хардкодов
- Отсутствие больших файлов в workspace (>10MB)
- Соответствие стандартам именования
.credentials.md в .gitignore, не в git# system/scheduler/schedule.yaml
validate_platform:
description: "Ежедневная валидация платформы"
command: "bash system/scripts/validate-platform.sh"
cron: "0 4 * * *"
enabled: true
#!/bin/bash
# Проверка хардкодов
if git diff --cached | grep -E "/opt/claude-workspace|/mnt/beget-s3"; then
echo "Найдены хардкоды! Используйте переменные."
exit 1
fi
# Проверка больших файлов
for file in $(git diff --cached --name-only); do
if [ -f "$file" ]; then
size=$(stat -c%s "$file" 2>/dev/null)
if [ "$size" -gt 10485760 ]; then
echo "Файл $file слишком большой ($(($size/1024/1024))MB)"
echo "Переместите в dataspace!"
exit 1
fi
fi
done
AI завышает оценки в 10-20 раз, думая как человек-разработчик.
| Пишу | Реально | Ошибка |
|---|---|---|
| "1-2 дня" | 30-60 минут | x20 |
| "3-5 дней" | 2-4 часа | x10 |
| "2-3 часа" | 15-30 минут | x5 |
AI_time = Human_time / Коэффициент
Коэффициенты:
- Механический код (CRUD, шаблоны, CSS): x10
- Логика + код (views, hooks, API): x6-8
- Исследование + код (новая библиотека): x3-4
- Только исследование/анализ: x2
Типовые задачи Drupal:
| Задача | Human | AI | Коэф. |
|---|---|---|---|
| Создать content type | 30 мин | 3 мин | x10 |
| Создать view | 1 час | 10 мин | x6 |
| Портировать CSS | 2 часа | 10-15 мин | x10 |
| Написать PHP hook | 1 час | 10 мин | x6 |
Комплексные задачи:
| Задача | Human | AI |
|---|---|---|
| Мигрировать footer на блоки | 1 день | 30-45 мин |
| Создать hero slider (View) | 3 часа | 20-30 мин |
| Полная миграция hardcoded->blocks | 2-3 дня | 2-4 часа |
| Создать новую тему с нуля | 1 неделя | 6-8 часов |
Backend задачи:
| Задача | Human | AI | Коэф. |
|---|---|---|---|
| REST API endpoint | 2 часа | 15 мин | x8 |
| Database migration | 1 час | 10 мин | x6 |
| Написать тесты (10 кейсов) | 3 часа | 30 мин | x6 |
| Интеграция с API (OZON) | 1 день | 2-3 часа | x3 |
Оценка: 30-45 минут
Включает: создание блоков (10 мин), шаблоны (15 мин), стили (10 мин), деплой (5 мин)
Риски:
- Если Drupal кеш не очистится: +5 мин
- Если нужно дебажить CSS конфликты: +15 мин
ВЫПОЛНЕНО за 35 минут:
Создано 4 menu blocks
Обновлён footer.html.twig
Портированы стили footer.css
ОТКЛОНЕНИЕ: -10 мин (оценка была 45 мин)
[ ] Учёл ли я что работаю как AI, а не человек?
[ ] Разделил ли задачу на подзадачи?
[ ] Указал ли время в минутах для задач < 2 часов?
[ ] Учёл ли параллельность независимых задач?
[ ] Не добавил ли "буфер на всякий случай"?
Объединены из:
- operation-monitoring.md — мониторинг роста диска
- operation-services-deployment.md — деплой сервисов
- operation-drupal-docker.md — Drupal в Docker
- operation-cleanup.md — уровни очистки диска
- operation-disk-audit.md — аудит диска
- operation-project-creation-system.md — система создания проектов
- operation-time-estimation.md — оценка времени для AI