Диагностика установки
Симптом, вероятная причина, точная проверка и безопасное исправление для десяти отказов on-prem установки ActionPulse — от контейнера, который не поднимается, до недействительного сертификата.
На этой странице
- Контейнеры не поднимаются
- Сервис не запускается: контейнер сразу выходит или перезапускается по кругу
- Сервис поднялся, но не отвечает на проверку работоспособности
- База данных, аналитическое хранилище и очередь
- Не подключается база данных
- Не подключается аналитическое хранилище
- Не подключается очередь
- Миграции
- Миграции не проходят
- События не доходят до отчётов
- Приём отвечает 202, но событий в отчётах нет
- Кабинет и запросы API
- Кабинет открывается, но запросы падают
- Диск и сертификат
- Закончилось место на диске
- Сертификат недействителен
- Что дальше
Эта страница для оператора, у которого установка на своих серверах уже запущена
или запускается прямо сейчас — и что-то не работает. Каждый случай разобран
одинаково: симптом, вероятная причина, конкретная проверка и исправление,
которое не портит данные. Если отказ на стороне интеграции — событие не
отправляется, приём отвечает 401, 403 или 422 — начните с общего дерева
диагностики. Если непонятно, чей это отказ вообще, — пять
минут на разделение.
Все команды выполняются из корня распакованного комплекта — каталога, где лежат
docker-compose.onprem.yml, .env и preflight.sh. Команд make … в комплекте
нет: они работают только из клона репозитория продукта, и ни одна инструкция
оператора на них не опирается. В примерах ${PP_DOMAIN} — домен из вашего
.env; подставьте своё значение или экспортируйте переменную в оболочку. Общее
состояние всегда показывает docker compose -f docker-compose.onprem.yml ps -a:
долгоживущие сервисы обязаны быть running, одноразовые задачи — exited (0).
Контейнеры не поднимаются
Сервис не запускается: контейнер сразу выходит или перезапускается по кругу
Вероятная причина. Незаполненный или некорректный .env: обязательные
переменные заданы жёстко, и без них конфигурация вообще не разворачивается.
Дальше по частоте — ссылка на образ не в виде tag@sha256, отсутствующий или
слишком открытый файл секрета (ACL Redis, конфигурация NATS, сертификаты и ключи
Elasticsearch и Kibana) и ожидание зависимости, которая не стала здоровой.
Как проверить. Закрытая проверка окружения, затем разворачивание конфигурации, затем журнал конкретного сервиса:
./preflight.sh .env
docker compose -f docker-compose.onprem.yml --env-file .env config --quiet
docker compose -f docker-compose.onprem.yml logs --tail 200 ingest-api
preflight.sh печатает одну строку и называет виновника: групповые права у
.env (use chmod 0600), must contain at least 24 characters, must be an exact tag@sha256 reference, must contain exactly one … entry, must use an authenticated URL without whitespace. Успешный проход заканчивается строкой
preflight: environment, exact image refs and external secret files passed.
Безопасное исправление. Исправьте .env (обычный файл, режим 0600),
досоздайте недостающие файлы секретов и поднимите только затронутый сервис:
docker compose -f docker-compose.onprem.yml --env-file .env up -d ingest-api.
Данные ни один из этих шагов не касается.
Если не помогло. Сверьте перечень обязательных переменных и файлов с конфигурацией и порядком запуска в развёртывании на Docker Compose. Если сервис ждёт зависимость, поднимите хранилища отдельно и дождитесь их готовности.
Сервис поднялся, но не отвечает на проверку работоспособности
Вероятная причина. Либо приложение действительно не готово — query-api
отдаёт 503, когда не может опросить PostgreSQL, ingest-api — когда потерял
соединение с NATS, — либо снаружи не проходит край: не запущен Caddy, домен не
разрешается, закрыты порты 80 и 443.
Как проверить. Сравните ответ изнутри контейнера и снаружи:
docker compose -f docker-compose.onprem.yml exec -T query-api wget -q -O- http://localhost:8080/healthz
docker compose -f docker-compose.onprem.yml exec -T ingest-api wget -q -O- http://localhost:8081/healthz
curl -sS -o /dev/null -w '%{http_code}\n' "https://${PP_DOMAIN}/healthz"
Успех — {"status":"ok"}. Отказы приходят в обычном конверте:
{"error":{"code":"internal","message":"postgres unavailable","details":{}}} у
query-api и nats disconnected у ingest-api.
Безопасное исправление. Изнутри ok, снаружи нет — дело в крае: смотрите
logs --tail 200 caddy, проверьте, что домен указывает на этот хост, и
перезапустите только прокси: docker compose -f docker-compose.onprem.yml --env-file .env restart caddy. Сертификаты лежат в отдельном томе и перезапуск
переживают. Изнутри тоже отказ — идите в раздел про названное хранилище.
Если не помогло. Других маршрутов готовности нет: /readyz и /livez не
существует. Полный перечень штатных проверок — в проверках
работоспособности.
База данных, аналитическое хранилище и очередь
Не подключается база данных
Вероятная причина. Контейнер PostgreSQL не стал здоровым; либо пароль в
.env изменили после того, как том с данными уже создан — пароль применяется
только при первичной инициализации кластера, а проверка работоспособности его не
сверяет, поэтому контейнер остаётся здоровым, а сервисы падают на аутентификации;
либо в подключении сервиса указана роль, которой в базе ещё нет, потому что
roles.sql не применён.
Как проверить. В журнале сервиса ищите префикс pgpool: и сообщение об
отказе аутентификации, затем сверьте состояние самой базы и список ролей —
последняя команда не печатает ни одного пароля:
docker compose -f docker-compose.onprem.yml logs --tail 100 postgres
docker compose -f docker-compose.onprem.yml exec -T postgres pg_isready -U pp -d actionpulse
docker compose -f docker-compose.onprem.yml exec -T postgres \
sh -ec 'PGPASSWORD="$POSTGRES_PASSWORD" psql -U pp -d actionpulse -Atc "SELECT rolname FROM pg_roles ORDER BY 1"'
Безопасное исправление. Если пароль разошёлся с кластером — верните в .env
значение, с которым кластер был инициализирован, и перезапустите сервисы. Если
оно утрачено, смените пароль роли в самой базе и синхронно обновите .env и все
подключения. Если не хватает ролей — примените postgres/roles.sql от имени
суперпользователя: пароли передаются переменными psql, поэтому сам файл никогда
не содержит учётных данных.
Если не помогло. На чистой базе roles.sql применяется дважды — до первой
миграции и ещё раз после неё; DDL выполняет только pp_migrator, и он никогда не
обслуживает трафик.
Не подключается аналитическое хранилище
Вероятная причина. Пароли в подключениях к ClickHouse разошлись с паролями пользователей; пароль внутри подключения не экранирован по правилам URL; адрес сервиса не попадает в сеть, разрешённую пользователю ClickHouse; либо контейнер не стал здоровым и до аутентификации дело не доходит.
Как проверить. Повторите проверку, которой пользуется compose, и посмотрите,
какие пользователи существуют. В журналах приложения ищите
AUTHENTICATION_FAILED — разошлись пароль или адрес, — и ACCESS_DENIED
(код 497) — не хватает права у роли.
docker compose -f docker-compose.onprem.yml logs --tail 200 clickhouse
docker compose -f docker-compose.onprem.yml exec -T clickhouse \
sh -ec 'clickhouse-client --user default --password "$CH_DEFAULT_PASSWORD" --query "SELECT 1"'
docker compose -f docker-compose.onprem.yml exec -T clickhouse \
sh -ec 'clickhouse-client --user default --password "$CH_DEFAULT_PASSWORD" --query "SELECT name FROM system.users ORDER BY name"'
Безопасное исправление. Приведите подключения в соответствие с паролями, экранируйте специальные символы в паролях внутри подключений, проверьте, что подсеть служебной сети совпадает с той, что задана пользователям ClickHouse, и перезапустите ClickHouse: пароли пользователей читаются из окружения при старте контейнера. Данные при этом не затрагиваются.
Если не помогло. Совместимый пользователь default разрешён только с
петлевого адреса, поэтому «починить» доступ, подставив его в рабочее подключение,
не получится: роль каждого подключения фиксирована, и закрытая проверка отвергает
подмену. Если в списке нет пользователя SQL-консоли, значит не применены миграции
ClickHouse — см. ниже.
Не подключается очередь
Вероятная причина. Конфигурация NATS не содержит того, чего от неё ждёт
установка: JetStream с каталогом хранения /data и служебный listener 8222,
по которому идёт проверка работоспособности. Либо подключение задано без учётных
данных или с чужим паролем. Либо одноразовая задача создания потоков не
завершилась успешно — тогда ingest-api, ch-writer и worker намеренно не
стартуют: в on-prem они не создают потоки сами, а только проверяют их наличие.
Как проверить. Точная строка отказа в журнале приложения: ingest-api: required pre-provisioned stream EVENTS. У ch-writer и worker формулировка та
же, но со своими именами потоков.
docker compose -f docker-compose.onprem.yml logs --tail 100 nats
docker compose -f docker-compose.onprem.yml logs query-api-nats-bootstrap
docker compose -f docker-compose.onprem.yml logs --tail 100 ingest-api
./preflight.sh --validate-acl-contracts secrets/redis-users.acl secrets/nats-server.conf
Безопасное исправление. Одноразовая задача идемпотентна — она создаёт или
обновляет ровно три потока, EVENTS, REPLAY и IMPORT_FENCES, — поэтому её
можно запустить повторно:
docker compose -f docker-compose.onprem.yml --env-file .env up query-api-nats-bootstrap
docker compose -f docker-compose.onprem.yml --env-file .env up -d ingest-api ch-writer worker
Если не проходит проверка работоспособности самой очереди, добавьте в её
конфигурацию отсутствующий блок JetStream или служебный listener и перезапустите
только nats.
Если не помогло. Проверьте, что учётная запись одноразового создания потоков не подставлена ни в один долгоживущий сервис: закрытая проверка запрещает это специально, а перепутанные подключения дают отказ на операциях, которых у роли нет.
Миграции
Миграции не проходят
Вероятная причина. Одноразовая задача миграции завершилась с ошибкой, а
query-api ждёт именно её успешного завершения и поэтому не стартует. Причины:
подключение не под ролью миграций, не применён или применён не в том порядке
roles.sql, ClickHouse ещё не готов, либо релиз требует отдельных
предварительных шагов.
Как проверить. Различайте два префикса в журнале задачи: pgpool: goose up:
— упала миграция PostgreSQL; chmigrate: <файл>: — упала миграция ClickHouse, и
в сообщении названа конкретная. Журнал применённых миграций ClickHouse хранится в
PostgreSQL, в таблице ch_schema_migrations.
docker compose -f docker-compose.onprem.yml logs query-api-migrate
docker compose -f docker-compose.onprem.yml exec -T postgres \
sh -ec 'PGPASSWORD="$POSTGRES_PASSWORD" psql -U pp -d actionpulse -Atc "SELECT max(version_id) FROM goose_db_version WHERE is_applied"'
docker compose -f docker-compose.onprem.yml exec -T postgres \
sh -ec 'PGPASSWORD="$POSTGRES_PASSWORD" psql -U pp -d actionpulse -Atc "SELECT max(version), count(*) FROM ch_schema_migrations"'
Безопасное исправление. Миграции идемпотентны и сериализованы advisory-блокировкой, поэтому повторный запуск после устранения причины безопасен:
docker compose -f docker-compose.onprem.yml --env-file .env up query-api-migrate
Если причина в правах — примените postgres/roles.sql и повторите. Порядок на
чистой базе: roles.sql, миграции, roles.sql ещё раз. При обновлении: сначала
миграции, потом повторное применение roles.sql, и только затем выкладка
ingest-api со своим подключением.
Если не помогло. Не обходите отказ ручным поэтапным запуском сервисов: у обновления есть обязательный порядок и обязательные предварительные шаги — см. обновление. Заодно убедитесь, что на существующем томе не запущена версия хранилища из будущего: для NATS и ClickHouse это запрещено без проверенной цепочки промежуточных шагов.
События не доходят до отчётов
Приём отвечает 202, но событий в отчётах нет
Вероятная причина. Приём подтверждает запись в очередь, а в аналитическое
хранилище её переносит отдельный сервис ch-writer. Значит, либо он не работает,
либо не успевает, либо ClickHouse отвергает вставки, либо сообщения ушли в
dead-letter. Отдельный случай: ch-writer намеренно не стартует, если в
хранилище остались устаревшие записи об отклонённых исторических импортах — тогда
он прямо пишет об этом в журнал.
Как проверить. Журнал сервиса и три метрики. Метрики слушают только внутри контейнера и наружу не публикуются:
docker compose -f docker-compose.onprem.yml logs --tail 200 ch-writer
docker compose -f docker-compose.onprem.yml exec -T ch-writer \
sh -ec 'wget -q -O- http://localhost:9090/metrics' \
| grep -E 'pp_writer_lag|pp_writer_insert_errors_total|pp_writer_dlq_total'
pp_writer_lag — сколько сообщений ждёт обработки; pp_writer_insert_errors_total
растёт на каждой неудачной попытке вставки; pp_writer_dlq_total — когда
сообщение ушло в dead-letter. Те же сигналы приходят алертами
ActionPulseEventsConsumerLagHigh, ActionPulseClickHouseInsertErrors и
ActionPulseDLQGrowth — см. мониторинг.
Безопасное исправление. Сначала устраните причину на стороне ClickHouse — место на диске, ошибки вставки, доступность, — затем дайте отставанию слиться само. Масштабировать обработчики до устранения причины не нужно: это только добавит нагрузки хранилищу, которое и так не справляется.
Если не помогло. Рост pp_writer_dlq_total означает, что не записанные
сообщения попали в dead-letter внутри потока событий, где они хранятся не дольше
48 часов. Разбор dead-letter выполняет поставщик: обратитесь в поддержку,
приложив время, метрики и журнал ch-writer. Не удаляйте сообщения и не
подтверждайте их массово — это молча теряет данные.
Кабинет и запросы API
Кабинет открывается, но запросы падают
Вероятная причина. По коду ответа:
| Код | Причина |
|---|---|
401 |
истёк токен доступа — он живёт 15 минут, обновляется через /api/v1/auth/refresh |
403 с license_invalid |
лицензия отсутствует, недействительна или истекла |
404 на /api/v1/billing/… |
биллинга в on-prem нет вовсе, это ожидаемо |
5xx на отчётах |
недоступно аналитическое хранилище или база |
| отказ по origin | APP_BASE_URL и CORS_ORIGINS не совпадают с адресом, по которому открыт кабинет |
Важно: проверка работоспособности query-api опрашивает только PostgreSQL.
Недоступный ClickHouse её не окрашивает — /healthz продолжит отвечать ok,
пока отчёты падают.
Как проверить. Статус лицензии и журнал сервиса:
curl -fsS "https://${PP_DOMAIN}/api/v1/license" -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
docker compose -f docker-compose.onprem.yml logs --tail 200 query-api
Ответ содержит поля valid, read_only и reason. Значения reason, которые
объясняют отказ записи: active — всё в порядке; expired; grace period (read-only) — срок вышел, семь дней работает только чтение; expired beyond grace period — и этот запас исчерпан. Тела отказов буквальные: license invalid or missing: <причина>, license expired; running read-only until renewed,
license status is temporarily unavailable.
Безопасное исправление. Для 401 достаточно обновить токен. Для
license_invalid — загрузите действующий ключ от имени владельца: замена
подхватывается всеми сервисами примерно за секунду, перезапуск не нужен, см.
лицензию. Для 5xx — идите в разделы про хранилища выше.
Для отказа по origin — приведите публичные адреса в .env к тому виду, по
которому кабинет открывается, и перезапустите query-api; адрес приложения
обязан остаться на https, иначе слетит защищённый флаг у cookie аутентификации.
Если не помогло. Соберите код ответа, значение заголовка X-Request-ID из
ответа и журнал query-api за то же окно: по идентификатору запроса поддержка
найдёт запись, не запрашивая у вас тело запроса.
Диск и сертификат
Закончилось место на диске
Вероятная причина. Растут тома данных: аналитическое хранилище (события), база, очередь, журналы Elasticsearch, хранилище метрик Prometheus, рабочий каталог резервного копирования.
Как проверить.
df -h
docker system df -v
docker compose -f docker-compose.onprem.yml exec -T clickhouse df -h /var/lib/clickhouse
Штатные сигналы: ActionPulseDiskSpaceLow — ниже 15 процентов свободного в
течение 15 минут; ActionPulseDiskSpaceCritical — ниже 5 процентов в течение
пяти минут; ActionPulseDiskTelemetryMissing — метрики файловых систем пропали,
и дисковые алерты ослепли. Убедитесь, что алерт смотрит на реальную файловую
систему с данными, а не на overlay.
Безопасное исправление. Добавьте ёмкость и примените штатные сроки хранения:
для метрик Prometheus, для журналов в Elasticsearch (политику удаления создаёт
одноразовая настройка, по умолчанию 30 дней; переменной для этого срока в шаблоне
.env нет — задайте её вручную) и для резервных копий. Несущественные
исторические импорты и записи сессий останавливайте их собственными органами
управления, сохранив надёжность приёма.
Если не помогло. Без исправного экспортёра метрик хоста дисковые сигналы слепы вовсе — починить надо сначала их, иначе следующий раз вы узнаете о переполнении от пользователей.
Сертификат недействителен
Вероятная причина. Домен установки указан как localhost — тогда край
выдаёт внутренний самоподписанный сертификат, и предупреждение браузера
ожидаемо. Для настоящего домена автоматический выпуск требует, чтобы запись DNS
указывала на этот хост, а порты 80 и 443 были доступны извне: без этого
выпуск не завершается.
Как проверить. Вывод openssl показывает издателя и срок — внутренний
самоподписанный сертификат отличается от настоящего сразу:
docker compose -f docker-compose.onprem.yml logs --tail 200 caddy
openssl s_client -connect "${PP_DOMAIN}:443" -servername "${PP_DOMAIN}" </dev/null 2>/dev/null \
| openssl x509 -noout -issuer -subject -dates
Безопасное исправление. Убедитесь, что домен в .env — настоящее имя, DNS
указывает на этот хост, а 80 и 443 открыты снаружи, и перезапустите только
край: docker compose -f docker-compose.onprem.yml --env-file .env restart caddy.
Выданные сертификаты лежат в отдельном томе и перезапуск переживают — повторный
выпуск не потребуется.
Если не помогло. Собственный сертификат в поставляемой конфигурации края не
предусмотрен: в ней нет ни директивы для своего сертификата, ни адреса
ACME-аккаунта. Если по политике организации нужен свой сертификат или внутренний
удостоверяющий центр, согласуйте изменение конфигурации края с поставщиком — не
подменяйте её наугад на работающей установке. Учтите и то, что для любого имени,
кроме localhost, включается принудительный HTTPS сроком на год: после первого
успешного визита браузер уже не пойдёт на http.
Что дальше
Набор для обращения в поддержку — cat VERSION, ps -a, вывод ./preflight.sh .env, журналы затронутых сервисов и метрики pp_*; полный перечень с
пояснениями, что из чего берётся, — в пяти минутах на
разделение. Оттуда же начинайте, если непонятно, чей это отказ.
Если отказ появился сразу после смены версии, идите в
обновление: у него есть обязательный порядок, который нельзя
обойти. Что проверять на здоровой установке — проверки
работоспособности.