MAATRIX / Блог / Sentry (self-hosted) в Docker Compose: готовый файл

Sentry (self-hosted) в Docker Compose: готовый файл

MAATRIX

Ищете «просто docker-compose.yml для Sentry, чтобы скопировать и запустить» — и упираетесь в то, что готового куска YAML на 15 строк для этой задачи не существует в природе. Self-hosted Sentry — это полтора десятка сервисов с внутренними зависимостями, и честный ответ звучит иначе: файл вы получаете официальным генератором, а дальше учитесь с ним работать — понимать структуру, безопасно донастраивать под свой сервер и не терять правки при обновлениях. Ниже — разбор того, что реально лежит в этом файле, и рабочий способ подогнать его под себя без разрушения обновляемости.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Почему нет универсального docker-compose.yml на 20 строк

У большинства сервисов из серии «докер-компоуз, готовый файл» действительно достаточно одного контейнера и пары переменных окружения. Sentry устроен иначе: чтобы принять событие с ошибкой, обработать его и показать в интерфейсе, одновременно работают:

  • Postgres — хранит проекты, пользователей, настройки, релизы, алерты;
  • Redis — очереди задач и кеш;
  • Kafka + Zookeeper — шина событий между воркерами обработки;
  • ClickHouse — колоночная база, куда фактически ложатся события и трассировки;
  • Snuba (несколько контейнеров: api, consumer, outcomes-consumer, replacer, cleanup и другие) — прослойка между Kafka/ClickHouse и остальным Sentry;
  • Relay — приёмный шлюз, который первым получает событие от SDK;
  • Symbolicator — разбирает нативные стектрейсы (крэши мобильных и десктопных приложений);
  • web, worker, cron — сам Sentry: интерфейс, фоновые задачи, планировщик;
  • nginx — точка входа внутри compose-сети.

Написать всё это вручную с нуля — не только долго, но и рискованно: версии сервисов в разных релизах Sentry жёстко привязаны друг к другу (конкретная Kafka под конкретную Snuba под конкретный ClickHouse), и малейшее расхождение ломает обработку событий на ровном месте с непонятной ошибкой в логах воркера. Поэтому практика, которая реально работает — не писать файл заново, а взять генератор от разработчиков и относиться к результату как к вендорному конфигу, который вы контролируемо расширяете сверху. Это ровно та же логика, что и с Docker Compose для продакшена в целом — базовый файл плюс слой собственных правок.

Как получить актуальный файл

Полный процесс установки с нуля — в отдельной статье про установку Sentry self-hosted на VPS. Здесь — только то, что касается самого файла:

cd /opt
git clone https://github.com/getsentry/self-hosted.git sentry
cd sentry
git checkout 24.9.1   # берите конкретный тег, не master
./install.sh

После install.sh в каталоге /opt/sentry появляется рабочий docker-compose.yml — это не шаблон для ручного заполнения, а полностью собранный файл с проставленными версиями образов, сетями и volume'ами, синхронизированными с конкретным релизом. Именно его вы дальше и держите под git внутри своей инфраструктуры — как обычный конфиг сервера, а не как временный артефакт установки.

git -C /opt/sentry diff HEAD~1 -- docker-compose.yml   # что изменилось после апдейта

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Структура сгенерированного файла: что там на самом деле

Фрагмент реальной структуры (сокращённо, без полных версий образов — они меняются от релиза к релизу):

services:
  redis:
    image: redis:...
    restart: unless-stopped
    volumes:
      - sentry-redis:/data

  postgres:
    image: getsentry/postgres-exporter... # либо официальный postgres-образ
    restart: unless-stopped
    environment:
      - POSTGRES_HOST_AUTH_METHOD=trust
    volumes:
      - sentry-postgres:/var/lib/postgresql/data

  kafka:
    image: confluentinc/cp-kafka:...
    restart: unless-stopped
    depends_on:
      - zookeeper

  clickhouse:
    image: clickhouse/clickhouse-server:...
    restart: unless-stopped
    ulimits:
      nofile:
        soft: 262144
        hard: 262144
    volumes:
      - sentry-clickhouse:/var/lib/clickhouse

  web:
    image: getsentry/sentry:...
    restart: unless-stopped
    depends_on:
      - postgres
      - redis
      - kafka
    env_file: .env
    volumes:
      - sentry-data:/data

  nginx:
    image: nginx:...
    restart: unless-stopped
    ports:
      - "9000:80"
    depends_on:
      - web

Смысл в том, что этот файл не рассчитан на построчное редактирование руками — при следующем ./install.sh (например, при обновлении версии) он перезапишется целиком, и любая ваша правка внутри него исчезнет. Официальная и единственная безопасная точка кастомизации — файл .env рядом (переменные SENTRY_*, порты, retention) и отдельный docker-compose.override.yml, который Docker Compose подхватывает автоматически и накладывает поверх основного файла, не трогая оригинал.

Свои правки через docker-compose.override.yml

Override-файл — стандартный механизм Compose: docker compose up сам подхватывает docker-compose.override.yml из той же папки и мёржит его с основным файлом по именам сервисов. Это ровно тот слой, где живут все ваши изменения — без риска потерять их при апдейте Sentry. Общий подход к разным окружениям через такие слои разобран в статье про Docker Compose profiles.

Пример — ограничение памяти под ClickHouse и Kafka (часто первое, что требуется на VPS с 8 ГБ RAM), плюс перенос порта веб-интерфейса на нестандартный:

# /opt/sentry/docker-compose.override.yml
services:
  clickhouse:
    mem_limit: 3g
    environment:
      - CLICKHOUSE_MAX_MEMORY_USAGE=2800000000

  kafka:
    mem_limit: 1.5g
    environment:
      - KAFKA_HEAP_OPTS=-Xmx768m -Xms768m

  nginx:
    ports:
      - "127.0.0.1:9000:80"   # закрываем прямой доступ снаружи

После правки docker-compose.override.yml пересобирать ничего не нужно — просто:

cd /opt/sentry
docker compose up -d
docker compose config   # показывает итоговый файл после мёржа — удобно для проверки

docker compose config — команда, которую стоит держать в привычке при работе с override-слоями: она печатает результирующий YAML после объединения всех файлов, и по нему сразу видно, применилась ли ваша правка так, как вы задумывали, ещё до запуска контейнеров.

Свой reverse proxy вместо встроенного nginx

Стандартный docker-compose.yml от Sentry сам поднимает nginx-контейнер и слушает порт наружу. Если на сервере уже есть общий реверс-прокси для нескольких сервисов — логичнее не держать второй nginx только ради Sentry, а завести его в общую docker-сеть и убрать проброс портов у встроенного nginx через тот же override:

# docker-compose.override.yml
networks:
  proxy-net:
    external: true

services:
  nginx:
    ports: []          # убираем прямой проброс наружу
    networks:
      - default
      - proxy-net
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.sentry.rule=Host(`sentry.example.com`)"
      - "traefik.http.routers.sentry.entrypoints=websecure"
      - "traefik.http.routers.sentry.tls.certresolver=letsencrypt"
      - "traefik.http.services.sentry.loadbalancer.server.port=80"

Это тот же принцип, что описан в статье Traefik как reverse proxy для докера — контейнер подключается к внешней сети прокси по имени, и Traefik сам находит его по labels, без ручной прописи портов и без дублирования SSL-терминации в двух местах.

Ресурсы и типичные ошибки первого запуска

Ориентир по серверу для честного запуска всего стека — минимум 4 vCPU и 8 ГБ RAM, комфортно — от 16 ГБ; это не измеренный бенчмарк, а порог, ниже которого Kafka и ClickHouse начинают конкурировать за память и валиться в перезапуск по кругу. Диск — от 60 ГБ, с ростом по мере накопления событий в ClickHouse.

Что настроено не такСимптомГде чинить
vm.max_map_count не увеличенClickHouse/Kafka не стартуют, max virtual memory areas ... too lowsysctl -w vm.max_map_count=262144 на хосте
Правки внесены прямо в docker-compose.ymlПравки пропадают после ./install.sh при обновленииПеренести в docker-compose.override.yml
Нет mem_limit у ClickHouse/KafkaOOM-килы контейнеров под нагрузкой на слабом VPSЗадать лимиты в override (пример выше)
Два nginx/reverse proxy слушают один портbind: address already in use при стартеУбрать проброс портов у встроенного nginx, завести в сеть общего прокси
Забыт .env после git checkout на новый тегweb не стартует, ругается на отсутствующие переменные./install.sh заново применяет и досоздаёт .env, не трогая существующие значения

Диагностика при проблемах со стартом — стандартная связка команд:

docker compose ps
docker compose logs --tail 100 clickhouse
docker compose logs --tail 100 snuba-consumer
docker compose config   # проверить итоговый файл после override

Если контейнеры регулярно упираются в лимиты и непонятно, что именно ест ресурс сервера в целом, а не только в рамках стека Sentry — общий подход к лимитам разобран в статье про ресурсы и лимиты CPU и памяти в Docker.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли просто скопировать чей-то docker-compose.yml для Sentry из интернета и запустить?

Не стоит. Версии сервисов в файле жёстко привязаны к конкретному релизу Sentry, и файл из чужого репозитория почти наверняка окажется рассинхронизирован с версией, которую вы разворачиваете — получите падающие миграции ClickHouse или воркеры, которые не могут разобрать формат сообщений в Kafka. Берите файл только через официальный install.sh под нужный тег.

Что делать, если я уже правил docker-compose.yml напрямую, а теперь нужно обновление?

Сохраните ваши изменения (git diff покажет их, если файл под git), перенесите их в docker-compose.override.yml, затем откатите основной файл к чистому состоянию перед ./install.sh — иначе установщик может отказаться накатывать обновление поверх изменённого файла.

Нужен ли docker-compose.override.yml, если я ничего не меняю в конфигурации?

Нет, без override файл работает как есть — он нужен только тогда, когда требуется что-то поверх стандартного поведения: свои лимиты памяти, порты, сеть для внешнего прокси.

Почему нельзя просто урезать файл, убрав Kafka и ClickHouse ради экономии ресурсов?

В версиях Sentry после перехода на архитектуру Snuba эти сервисы обязательны для обработки событий — без них не поднимется даже веб-интерфейс. Урезанные конфигурации без них существовали только в очень старых релизах (9.x), которые давно не получают обновлений безопасности.

Как проверить, что override действительно применился, а не проигнорирован?

Команда docker compose config печатает итоговый YAML после мёржа всех файлов — ищите в выводе именно те значения, которые задавали в override, а не значения по умолчанию из основного файла.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →