Перейти к содержанию

VPN Config Service — проблемы с worker

Worker (vpn-config-worker) — отдельный процесс, который синхронизирует конфиги с VPN-серверов по SSH. При зависании или падении клиенты не получают обновлённые конфиги, трафик перестаёт считаться.


Симптомы

  • Grafana алерт «Worker Unhealthy» / heartbeat не обновляется
  • docker logs vpn-config-worker не показывает «Online sync done» каждые ~60 сек
  • SSH cascade timeout: в логах много SSH: Connection timed out подряд
  • fill_configs зависает более 10 минут (обычно завершается за 2-4 мин)
  • Config pipeline не двигается: один и тот же сервер в логах сотни раз подряд

Диагностика

1. Проверить состояние контейнеров VCS

./scripts/ssh-internal.sh 10.99.87.249 "docker ps | grep vpn-config"

Ожидается: vpn-config-service (Up), vpn-config-worker (Up), vpn-config-postgres (Up), vpn-config-redis (Up).

2. Проверить heartbeat worker

./scripts/ssh-internal.sh 10.99.87.249 \
  "stat /tmp/worker_heartbeat/heartbeat 2>/dev/null || echo 'NO HEARTBEAT'"

Heartbeat обновляется каждые ~60 сек (online sync cycle). Если файл старше 5 мин — worker завис.

3. Проверить health endpoint VCS API

./scripts/ssh-internal.sh 10.99.87.249 "curl -s http://localhost:8000/health"

Ожидается: {"status": "ok", ...}. Если API не отвечает — упал контейнер vpn-config-service.

4. Нормальное время выполнения health_check

Health_check при 50+ серверах может занимать до 240 секунд — это нормально.

Параметр Значение
Таймаут на сервер 90s
Общий таймаут (основной цикл) 240s
Таймаут перезапуска проб 120s
Внешний safety timeout worker'а 270s

Если health_check превышает 270s, worker принудительно завершает задачу и вызывает flush_dead() для очистки мёртвых SSH-соединений.

5. Хвост логов worker

./scripts/ssh-internal.sh 10.99.87.249 "docker logs vpn-config-worker --tail 100"

Смотреть: - Online sync done in Xs: N sessions — нормальный ритм - SSH: Connection timed out — мёртвые SSH-соединения в пуле - fill_configs started без fill_configs done — fill завис - flush_dead — worker сам обнаружил и почистил мёртвые соединения

6. Статистика SSH-пула через API

./scripts/ssh-internal.sh 10.99.87.249 \
  "curl -s http://localhost:8000/api/v1/stats \
   -H 'X-API-Key: VazVBGPEBLTG7qNVOQQu4xR21DWTBi4_fodUjuEojnE' | python3 -m json.tool"

Поля ssh_pool_active и ssh_pool_in_use: если in_use близко к active и не меняется — пул заблокирован мёртвыми соединениями.

7. Проверить PostgreSQL VCS

./scripts/ssh-internal.sh 10.99.87.249 \
  "docker exec vpn-config-postgres psql -U vpnconfig vpnconfig \
   -c 'SELECT COUNT(*) FROM servers WHERE is_active = true;'"

Если возвращает 0 — servers не загружены из MySQL (нужен mysql_sync).


Причины и решения

Симптом Причина Решение
Cascade SSH timeouts SSH pool забит мёртвыми conn Перезапустить worker (flush_dead)
fill_configs завис Один из серверов не отвечает Перезапустить worker
servers = 0 в stats MySQL sync не прошёл POST /api/v1/sync/mysql-servers
Worker exited (код != 0) OOM или необработанное исключение docker logs, перезапустить
Config pipeline одни ошибки Множество серверов down Проверить SSH с backend на эти IP

Исправление

Перезапустить worker (основное действие)

./scripts/ssh-internal.sh 10.99.87.249 \
  "cd /opt/vpn-config-service && \
   docker compose -f docker-compose.prod.yml restart vpn-config-worker"

После перезапуска в логах должно появиться fill_configs started через ~3 мин (стартап stagger), затем Online sync done.

Принудительный mysql_sync (если нет серверов в PostgreSQL)

./scripts/ssh-internal.sh 10.99.87.249 \
  "curl -sX POST http://localhost:8000/api/v1/sync/mysql-servers \
   -H 'X-API-Key: VazVBGPEBLTG7qNVOQQu4xR21DWTBi4_fodUjuEojnE'"

Проверить SSH-доступность с backend на проблемный сервер

./scripts/ssh-internal.sh 10.99.87.249 \
  "timeout 10 ssh -i /opt/vpn-config-service/ssh/id_ed25519_vpn_config_service \
   -o StrictHostKeyChecking=no -o ConnectTimeout=5 \
   root@SERVER_IP 'echo ok' 2>&1"

Перезапустить весь VCS стек (крайняя мера)

./scripts/ssh-internal.sh 10.99.87.249 \
  "cd /opt/vpn-config-service && \
   docker compose -f docker-compose.prod.yml down && \
   docker compose -f docker-compose.prod.yml up -d"

Затем применить миграции и загрузить серверы:

./scripts/ssh-internal.sh 10.99.87.249 \
  "docker exec vpn-config-service alembic upgrade head && \
   curl -sX POST http://localhost:8000/api/v1/sync/mysql-servers \
   -H 'X-API-Key: VazVBGPEBLTG7qNVOQQu4xR21DWTBi4_fodUjuEojnE'"

Проверить DB lock в PostgreSQL VCS

./scripts/ssh-internal.sh 10.99.87.249 \
  "docker exec vpn-config-postgres psql -U vpnconfig vpnconfig \
   -c 'SELECT pid, state, wait_event_type, query FROM pg_stat_activity WHERE state != '\''idle'\'';'"

Если есть транзакции в состоянии idle in transaction — worker завис с незакрытой транзакцией. Решение: перезапустить worker.


Эскалация

  • Если перезапуск worker не помогает — деплоить новую версию через CI/CD (GitLab pipeline проект 55)
  • Если падает PostgreSQL VCS — проверить дисковое пространство: df -h на 10.99.87.249
  • При подозрении на баг в коде — задокументировать инцидент (monorepo: incidents/VCS-WORKER-NAME-YYYY-MM-DD.md)

См. также: VPN Config Service · Runbooks · DevOps скрипты · Репозитории