Развёртывание через Docker Compose
Установка ActionPulse на одном сервере из поставляемого комплекта — проверка архива, окружение, миграции, порядок запуска сервисов, журналы и безопасная остановка.
На этой странице
- Что нужно на сервере
- Комплект и границы поставки
- Порядок установки
- Шаг 1. Проверьте архив и распакуйте его
- Шаг 2. Заполните окружение
- Шаг 3. Подготовьте файлы секретов
- Шаг 4. Проверьте конфигурацию до первого запуска
- Шаг 5. Поднимите зависимости, миграции и сервисы
- Шаг 6. Проверьте работоспособность
- Шаг 7. Лицензия, первая организация и первый проект
- Состав сервисов и порядок запуска
- Журналы, остановка и удаление
- Что проверить и частые ошибки
Так ActionPulse ставится на один сервер: вы получаете подписанный комплект, заполняете окружение, применяете миграции одноразовым контейнером и поднимаете сервисы. Всё — из каталога комплекта; репозиторий продукта для установки не нужен.
Страница описывает первую установку на чистую машину. Если у вас уже есть работающие тома PostgreSQL, ClickHouse или NATS, это не инструкция обновления: переход версий stateful-сервисов идёт отдельным поэтапным маршрутом.
Что нужно на сервере
Коротко: Linux amd64 или arm64, Docker Engine 24 или новее с Docker Compose v2
(docker compose version), открытые входящие порты 80 и 443, файл ключа
лицензии от поставщика и публичный ключ вендора для офлайн-проверки. Стартовая
конфигурация из документов продукта — 4 vCPU, 8 ГБ памяти, 50 ГБ диска.
Комплект и границы поставки
Комплект приходит из аутентифицированного канала поставки тремя файлами:
архив actionpulse-onprem-<версия>.tgz, файл контрольной суммы .tgz.sha256
и подписанный .release-manifest.json. Внутри архива — единственный каталог
actionpulse-onprem/:
actionpulse-onprem/
├── docker-compose.onprem.yml # единственный compose, запускается из корня
├── .env.example # шаблон конфигурации; версия и образы уже подставлены
├── preflight.sh # проверка окружения до первого запуска
├── Caddyfile # обратный прокси
├── OPERATIONS.md # полное руководство по эксплуатации
├── redis-users.acl.example # шаблон ACL Redis
├── nats-server.conf.example # шаблон конфигурации NATS
├── clickhouse/ # pp-server.xml, pp-users.xml, cluster/
├── postgres/roles.sql # роли PostgreSQL по сервисам
├── backup/ # named collection для ClickHouse, шаблон и README
├── observability/ # prometheus.yml, alertmanager, grafana, filebeat
├── monitoring/prometheus/ # actionpulse.rules.yml — правила алертов
├── jaeger/, helm/actionpulse/ # трейсинг и чарт для Kubernetes
├── docs/ # CONTRACTS.md, SECURITY_PRIVACY.md, openapi.yaml
├── empty/, VERSION
└── release/ # images.lock, SBOM, provenance, отчёты сканера
Порядок установки
Шаг 1. Проверьте архив и распакуйте его
Контрольную сумму и подписанный манифест проверяйте до распаковки — из того же канала, откуда пришёл архив.
sha256sum -c actionpulse-onprem-vX.Y.Z.tgz.sha256
tar xzf actionpulse-onprem-vX.Y.Z.tgz
cd actionpulse-onprem
В release/images.json перечислены точные ссылки на образы в форме tag@sha256
и digest’ы по платформам, в release/sbom/ — CycloneDX и SPDX, в
release/provenance/ — provenance. Содержимое release/trivy/ — сырые кандидаты
сканера, а не список подтверждённых уязвимостей: каждый пункт требует отдельной
оценки достижимости.
Шаг 2. Заполните окружение
install -m 0600 .env.example .env
Права 0600 обязательны: preflight.sh отказывается работать с файлом, у
которого есть групповые или общие права, и с символической ссылкой. В шаблоне
уже указаны точные ссылки на образы — не заменяйте их ссылками только по тегу.
Значения секретов не берите из примеров — генерируйте своё независимое:
openssl rand -base64 32 # по одному вызову на каждый отдельный секрет
Обязательный минимум перед первым запуском. Часть значений проверяет сам Compose,
часть — preflight.sh, часть — сервисы при старте; практической разницы нет, без
любого из них рабочей установки не получится.
| Группа | Переменные (по именам) |
|---|---|
| Домен и публичные origin’ы | PP_DOMAIN, APP_BASE_URL, PUBLIC_INGEST_URL, ADMIN_APP_BASE_URL, CORS_ORIGINS |
| Ссылки на образы | PP_INGEST_IMAGE_REF, PP_QUERY_IMAGE_REF, PP_WRITER_IMAGE_REF, PP_WORKER_IMAGE_REF, PP_BACKUP_IMAGE_REF, NATS_IMAGE_REF, CLICKHOUSE_IMAGE_REF |
| Секреты приложения | JWT_SECRET, ALERT_WEBHOOK_ENC_KEY, IMPORT_ENC_KEY, IMPORT_HMAC_CURRENT_VERSION, IMPORT_HMAC_CURRENT_SECRET, IMPORT_FENCE_HMAC_CURRENT_VERSION, IMPORT_FENCE_HMAC_CURRENT_SECRET, IMPORT_PRIVACY_HMAC_CURRENT_VERSION, IMPORT_PRIVACY_HMAC_CURRENT_SECRET |
| PostgreSQL, Redis, NATS | PG_PASSWORD, REDIS_URL, NATS_URL, REDIS_ACL_FILE, NATS_CONFIG_FILE |
| ClickHouse | CH_DEFAULT_PASSWORD, CH_MIGRATE_PASSWORD, CH_WRITE_PASSWORD, CH_READ_PASSWORD, CH_BACKUP_PASSWORD, CH_CONSOLE_PASSWORD и полные CH_MIGRATE_DSN, CH_WRITE_DSN, CH_READ_DSN, CH_CONSOLE_DSN |
| Наблюдаемость | GRAFANA_ADMIN_PASSWORD, ELASTIC_PASSWORD, KIBANA_SYSTEM_PASSWORD, ELASTICSEARCH_FILEBEAT_USERNAME, ELASTICSEARCH_FILEBEAT_PASSWORD, ELASTIC_CA_FILE, ELASTICSEARCH_CERT_FILE, ELASTICSEARCH_KEY_FILE, KIBANA_CERT_FILE, KIBANA_KEY_FILE |
| Лицензия | LICENSE_PUBKEY — публичный ключ вендора для офлайн-проверки |
| Первый владелец | BOOTSTRAP_EMAIL, BOOTSTRAP_PASSWORD — только до создания первого владельца |
| Подпись резервных копий | BACKUP_MANIFEST_SIGNING_KEY, BACKUP_MANIFEST_PUBLIC_KEYS — требуются всегда, даже если профиль резервного копирования не включён |
Необязательные переменные (журналирование, телеметрия, SMTP, GeoIP, пределы JetStream, отдельные учётные записи хранилищ на каждый сервис) имеют рабочие значения по умолчанию — полный перечень в Конфигурации.
Шаг 3. Подготовьте файлы секретов
ACL Redis, аутентифицированная конфигурация NATS и приватные ключи TLS для Elasticsearch и Kibana лежат отдельными файлами и монтируются как файловые секреты Docker.
install -d -m 0700 secrets
install -m 0600 redis-users.acl.example secrets/redis-users.acl
install -m 0600 nats-server.conf.example secrets/nats-server.conf
Шаблоны намеренно нерабочие: вместо паролей в них заглушки, и до вашей правки
проверка их не пропустит. Заполните пароли пользователей, синхронизируйте их с
REDIS_URL и NATS_URL, затем положите CA, сертификаты и приватные ключи по
путям из ELASTIC_* и KIBANA_* — ключи с правами 0600. Подробности — в
статье TLS и секреты.
Шаг 4. Проверьте конфигурацию до первого запуска
./preflight.sh .env
./preflight.sh --validate-acl-contracts secrets/redis-users.acl secrets/nats-server.conf
docker compose -f docker-compose.onprem.yml --env-file .env config --quiet
preflight.sh — это отказ по умолчанию, а не подсказка. Он проверяет, что .env
— обычный файл с правами 0600 и ровно одной записью на ключ; что двенадцать
обязательных секретов не короче 24 символов, без пробелов и не совпадают с
известными заглушками; что все семь ссылок на образы имеют вид tag@sha256; что
NATS_URL и REDIS_URL содержат учётные данные; что роли в DSN соответствуют
назначению; что файлы ACL, конфигурации NATS и приватных ключей существуют, не
являются ссылками и имеют права 0600; что в ACL Redis пользователь default
выключен, а в конфигурации NATS включён JetStream. Успех — одна строка о том, что
окружение, точные ссылки на образы и внешние файлы секретов проверку прошли.
Второй вызов отдельно сверяет контракты доступов в ACL Redis и в учётных записях
NATS.
Шаг 5. Поднимите зависимости, миграции и сервисы
На чистой машине достаточно одной команды — compose сам соблюдает порядок через зависимости и состояние здоровья:
docker compose -f docker-compose.onprem.yml --env-file .env up -d
Если вы хотите видеть работу одноразовых контейнеров в терминале, тот же порядок раскладывается на три шага:
docker compose -f docker-compose.onprem.yml --env-file .env up -d \
postgres clickhouse redis nats
docker compose -f docker-compose.onprem.yml --env-file .env up \
query-api-nats-bootstrap query-api-migrate
docker compose -f docker-compose.onprem.yml --env-file .env up -d
query-api-migrate применяет миграции PostgreSQL и ClickHouse: идемпотентно, под
advisory-локами от гонок, и обязан завершиться успешно до старта долгоживущего
API. query-api-nats-bootstrap идемпотентно создаёт и обновляет ровно три потока
JetStream — EVENTS, REPLAY и IMPORT_FENCES — и обязан завершиться до
ingest-api: приём событий в on-prem потоки не создаёт, он только читает их
состояние и отказывается стартовать, если подготовка не выполнена.
Шаг 6. Проверьте работоспособность
PP_HOST=https://YOUR_ACTIONPULSE_HOST # адрес установки — тот же, что PP_DOMAIN в .env
docker compose -f docker-compose.onprem.yml --env-file .env ps
curl -fsS "$PP_HOST/healthz"
В ps долгоживущие сервисы должны быть running или healthy, а одноразовые —
exited (0): это query-api-nats-bootstrap, query-api-migrate,
elastic-security-setup и backup-init. Ответ /healthz — {"status":"ok"};
на стороне query-api он проверяет доступность PostgreSQL, на стороне
ingest-api — соединение с NATS.
Шаг 7. Лицензия, первая организация и первый проект
Первая организация и её владелец создаются автоматически при первом старте
HTTP-сервиса — из BOOTSTRAP_EMAIL и BOOTSTRAP_PASSWORD. Отдельной команды для
этого нет, и повторно шаг не выполняется: если в базе уже есть пользователи, он
пропускается.
Войдите этим владельцем и загрузите лицензию. Пароль вводится интерактивно, тело запроса идёт через канал — так секрет не попадёт ни в историю команд, ни в список процессов:
PP_HOST=https://YOUR_ACTIONPULSE_HOST
read -rp "e-mail владельца: " PP_OWNER_EMAIL
read -rsp "пароль владельца: " PP_OWNER_PASSWORD; echo
export PP_OWNER_EMAIL PP_OWNER_PASSWORD
TOKEN=$(python3 -c 'import json,os;print(json.dumps({
"email": os.environ["PP_OWNER_EMAIL"],
"password": os.environ["PP_OWNER_PASSWORD"]}))' |
curl -fsS -X POST "$PP_HOST/api/v1/auth/login" \
-H "Content-Type: application/json" --data-binary @- |
python3 -c 'import json,sys;print(json.load(sys.stdin)["access_token"])')
unset PP_OWNER_PASSWORD
python3 -c 'import json,sys;print(json.dumps({"key":sys.stdin.read().strip()}))' \
< license.key |
curl -fsS -X PUT "$PP_HOST/api/v1/license" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" --data-binary @-
curl -fsS "$PP_HOST/api/v1/license" -H "Authorization: Bearer $TOKEN"
Ответ GET содержит valid, read_only, reason, срок действия и список
включённых возможностей. Без действующей лицензии запись отвечает
403 license_invalid, а чтение работает; после истечения срока действует
семидневный период только для чтения. Замена ключа через PUT подхватывается
всеми сервисами примерно за секунду, перезапуск не нужен.
Затем создайте проект и ключ приёма — методы описаны в разделах Проекты и Ключи API — и вставьте сниппет сбора на сайт по инструкции Тег скрипта.
Состав сервисов и порядок запуска
| Сервис | Что делает | Порт внутри сети |
|---|---|---|
postgres |
учётные записи, организации, проекты, отчёты, импорты, задания приватности | 5432 |
clickhouse |
события и аналитические таблицы | 8123, 9000, метрики 9363 |
redis |
счётчики, дедупликация, кэш | 6379 |
nats |
транспорт событий JetStream | 4222, мониторинг 8222 |
query-api-nats-bootstrap |
одноразовый: создаёт потоки EVENTS, REPLAY, IMPORT_FENCES |
— |
query-api-migrate |
одноразовый: миграции PostgreSQL и ClickHouse | — |
query-api |
основной API и обслуживание кабинета | 8080 |
ingest-api |
приём событий | 8081 |
ch-writer |
запись событий из JetStream в ClickHouse | — |
worker |
письма, алерты, импорты, удаление данных субъекта | — |
caddy |
обратный прокси; единственный публикует 80 и 443 | 80, 443 |
Вместе с ними обычной командой up -d поднимается внутренний стек наблюдаемости:
prometheus, alertmanager, grafana, node-exporter, postgres-exporter,
redis-exporter, nats-exporter, elasticsearch, одноразовый
elastic-security-setup, kibana, filebeat, filebeat-metrics и jaeger.
Отдельного профиля у них нет, а их пароли и файлы TLS обязательны — то есть стек
не опционален. Резервное копирование, наоборот, включается явно профилем:
docker compose -f docker-compose.onprem.yml --env-file .env --profile backup up -d
Порядок запуска задан зависимостями и не требует вашего вмешательства: сначала
хранилища до состояния healthy, затем оба одноразовых контейнера, затем
query-api и ingest-api, после того как query-api стал healthy —
ch-writer и worker, и последним caddy.
Сети разделены: app с исходящим доступом (SMTP, webhook’и, телеметрия по
согласию), внутренние data и observability без маршрута наружу, и edge,
где у Caddy статический адрес. Именно этому адресу и только ему доверяются
заголовки с адресом клиента.
Журналы, остановка и удаление
Журналы сервисов читаются штатно:
docker compose -f docker-compose.onprem.yml --env-file .env logs -f query-api
docker compose -f docker-compose.onprem.yml --env-file .env logs -f ch-writer
Метрики приложения слушают порт 9090 и наружу не публикуются, поэтому смотреть их нужно изнутри контейнера:
docker compose -f docker-compose.onprem.yml --env-file .env exec query-api \
wget -qO- http://localhost:9090/metrics | grep pp_
Логи всех контейнеров собираются в Elasticsearch и доступны через Kibana, метрики и дашборды — через Grafana; публикуемого порта нет ни у одного из этих интерфейсов.
Остановка и удаление:
# Остановить сервисы, оставив контейнеры и тома
docker compose -f docker-compose.onprem.yml --env-file .env stop
# Удалить контейнеры и сети; именованные тома остаются на месте
docker compose -f docker-compose.onprem.yml --env-file .env down
down без дополнительных флагов данные не удаляет. Всё состояние лежит в
именованных томах проекта actionpulse-onprem: pg-data, ch-data,
redis-data, nats-data, caddy-data, caddy-config, import-uploads,
prometheus-data, alertmanager-data, grafana-data, es-data, kibana-data,
filebeat-data, backup-metrics, backup-state. После down установку
поднимают снова тем же up -d с тем же .env.
Что проверить и частые ошибки
preflight.shотказал — читайте его сообщение буквально. Чаще всего это оставленное значение-заглушка, отсутствующие права0600у.envили у приватного ключа, дублирующаяся строка переменной либо ссылка на образ без@sha256.ingest-apiне стартует — скорее всего не завершилсяquery-api-nats-bootstrap. Проверьте его журнал иPP_NATS_BOOTSTRAP_URL: эту одноразовую учётную запись нельзя выдавать долгоживущим сервисам, и проверка окружения такое отклоняет.403 license_invalidна запись — лицензия не загружена или истекла, проверьтеGET /api/v1/license.401— истёк access-токен (15 минут), обновите его через/api/v1/auth/refresh.- События не доходят до отчётов — смотрите журнал
ch-writerи метрикуpp_writer_lag. - Контейнер перезапускается по кругу — начинайте с
logsэтого сервиса. У Filebeat это обычно недоступный Elasticsearch, неверный CA или неверные учётные данные: проверка доставки специально сделана так, чтобы поломка была видна как unhealthy, а не как тишина в Kibana. - Веб-интерфейс не отдаётся с этого адреса — статика кабинета в комплект не
входит, обратный прокси проксирует остальные пути на
query-api. Всё, что описано выше, выполняется через API; способ раздачи статики согласуйте с поставщиком.
Дальше: проверки состояния и наблюдаемость и конфигурация целиком.