SonarQube на сервере: частые ошибки и решения
SonarQube — не просто линтер: под капотом у него встроенный Elasticsearch, отдельная PostgreSQL и своя JVM с жёсткими требованиями к лимитам ОС. Поэтому даже опытные админы спотыкаются на первом же запуске: сервис падает сразу после старта, не хватает памяти, CI зависает на анализе. Ниже — конкретные ошибки, которые чаще всего встречаются на VPS, и рабочие решения без танцев с бубном.
Содержание
- Архитектура SonarQube и почему она спотыкается на сервере
- Ошибка vm.max_map_count: Elasticsearch не запускается
- Нехватка памяти: OOM killer и настройка heap
- PostgreSQL: подключение, кодировка и права
- Развёртывание в Docker Compose и reverse proxy через nginx
- Интеграция с CI: токены, вебхуки и зависшие quality gate
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Архитектура SonarQube и почему она спотыкается на сервере
SonarQube с версии 7.x — это три внутренних процесса в одной JVM-обвязке: app (супервизор), web (интерфейс на Tomcat) и search node — встроенный Elasticsearch, куда пишутся результаты анализа. Отдельно живёт база данных: SonarQube официально поддерживает только PostgreSQL (начиная с 9.x-веток H2 и MySQL выпилены совсем).
Из этой связки вытекают почти все проблемы на сервере:
- Elasticsearch внутри SonarQube требует те же системные лимиты, что и обычный ES-кластер —
vm.max_map_count, file descriptors, ulimit по процессам. - Три JVM-процесса (или минимум два — web и search) съедают память отдельно друг от друга, и OOM killer чаще всего убивает именно search node, а не web.
- PostgreSQL должен быть доступен на момент старта
web-процесса — если соединение не установилось за таймаут, SonarQube уходит в CrashLoop.
Официальный минимум — 2 ядра CPU и 4 ГБ RAM для маленькой команды; для реальной работы с несколькими проектами и параллельным CI закладывайте от 4 ГБ на саму SonarQube плюс отдельно ресурсы под PostgreSQL и раннеры. На 2 ГБ RAM SonarQube стартует нестабильно и падает при первом же крупном скане.
Ошибка vm.max_map_count: Elasticsearch не запускается
Самая частая причина, по которой SonarQube вообще не поднимается — сообщение в логах:
Elasticsearch did not exit normally - check the logs at ...
max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
Это лимит ядра на количество memory-mapped областей на процесс — стандартное требование Elasticsearch, и SonarQube здесь не исключение. Фикс временный (до перезагрузки):
sudo sysctl -w vm.max_map_count=262144
И постоянный — добавить в /etc/sysctl.conf (или отдельный файл /etc/sysctl.d/99-sonarqube.conf):
vm.max_map_count=262144
fs.file-max=131072
Применить без перезагрузки:
sudo sysctl --system
Вторая по частоте ошибка из той же серии — про лимиты процессов и открытых файлов:
The maximum number of processes for user is too low
The SonarQube search node hasn't been able to start...
Правится в /etc/security/limits.conf:
sonarqube - nofile 65536
sonarqube - nproc 4096
Если SonarQube запущена как systemd-сервис — этого может быть недостаточно, systemd игнорирует limits.conf по умолчанию. Добавьте лимиты прямо в unit-файл:
[Service]
LimitNOFILE=65536
LimitNPROC=4096
и перечитайте конфигурацию: sudo systemctl daemon-reload && sudo systemctl restart sonarqube.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНехватка памяти: OOM killer и настройка heap
Если в dmesg или journalctl -k находите строку вроде Out of memory: Killed process ... (java), значит ядро прибило одну из JVM SonarQube по нехватке RAM. Проверить это можно быстро:
dmesg -T | grep -i "killed process"
По умолчанию SonarQube выделяет под каждый процесс фиксированный heap, который можно и нужно подстраивать под реальный объём сервера — правки вносятся в sonar.properties (обычно /opt/sonarqube/conf/sonar.properties или примонтированный конфиг в Docker):
sonar.web.javaOpts=-Xmx1G -Xms256m
sonar.ce.javaOpts=-Xmx1G -Xms256m
sonar.search.javaOpts=-Xmx1G -Xms1G -XX:MaxDirectMemorySize=256m
Ориентир по памяти (это именно ориентир — у вас будет зависеть от числа проектов и языков в анализе):
| Компонент | Мин. heap | Комфортный heap |
|---|---|---|
| web | 512 МБ | 1 ГБ |
| compute engine (ce) | 512 МБ | 1–2 ГБ |
| search (Elasticsearch) | 512 МБ | 1–2 ГБ |
| PostgreSQL | — | 512 МБ – 1 ГБ |
Итого на сервер с запасом под ОС и CI-раннер стоит закладывать от 6–8 ГБ RAM, если SonarQube анализирует несколько проектов параллельно. Если бюджет ограничен и памяти категорически не хватает — временно спасает своп, но это костыль: под нагрузкой своп резко просаживает скорость индексации в Elasticsearch, лучше сразу проверить, чего не хватает серверу и вырасти по тарифу.
PostgreSQL: подключение, кодировка и права
Вторая по частоте причина падений — база данных. Типичная ошибка в логах web процесса:
org.postgresql.util.PSQLException: FATAL: password authentication failed for user "sonar"
или
Caused by: java.net.ConnectException: Connection refused
Порядок действий, который закрывает 90% таких случаев. Создайте базу и пользователя с нужной кодировкой (SonarQube требует UTF8 и локаль, поддерживающую C collation для части таблиц):
CREATE ROLE sonar WITH LOGIN PASSWORD 'сложный_пароль';
CREATE DATABASE sonarqube OWNER sonar ENCODING 'UTF8' LC_COLLATE 'C' LC_CTYPE 'C' TEMPLATE template0;
GRANT ALL PRIVILEGES ON DATABASE sonarqube TO sonar;
Пропишите доступ в sonar.properties:
sonar.jdbc.username=sonar
sonar.jdbc.password=сложный_пароль
sonar.jdbc.url=jdbc:postgresql://127.0.0.1:5432/sonarqube
Если PostgreSQL стоит на отдельном сервере или в соседнем контейнере — проверьте pg_hba.conf: строка host sonarqube sonar 0.0.0.0/0 scram-sha-256 (замените маску на реальную подсеть) и что listen_addresses в postgresql.conf не ограничен localhost. Общие грабли с самим PostgreSQL и его тюнингом на сервере разобраны отдельно в статье про настройку PostgreSQL на VPS — там же про частые ошибки подключения и права ролей.
Отдельно стоит следить за ростом базы: SonarQube хранит историю всех анализов, и на активных проектах таблица issues растёт быстро. Настройте retention (Administration → Configuration → General → Housekeeping) — по умолчанию история хранится дольше, чем реально нужно для дашбордов.
Развёртывание в Docker Compose и reverse proxy через nginx
На практике проще всего поднимать SonarQube и PostgreSQL вместе через Docker Compose — так меньше проблем с системными лимитами (их выставляете один раз на хосте, а не на каждом процессе). Рабочий минимальный docker-compose.yml:
services:
sonarqube:
image: sonarqube:lts-community
depends_on:
- db
environment:
SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonarqube
SONAR_JDBC_USERNAME: sonar
SONAR_JDBC_PASSWORD: сложный_пароль
ulimits:
nofile:
soft: 65536
hard: 65536
nproc: 4096
volumes:
- sonarqube_data:/opt/sonarqube/data
- sonarqube_extensions:/opt/sonarqube/extensions
- sonarqube_logs:/opt/sonarqube/logs
ports:
- "127.0.0.1:9000:9000"
restart: unless-stopped
db:
image: postgres:16
environment:
POSTGRES_USER: sonar
POSTGRES_PASSWORD: сложный_пароль
POSTGRES_DB: sonarqube
volumes:
- postgresql_data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
sonarqube_data:
sonarqube_extensions:
sonarqube_logs:
postgresql_data:
vm.max_map_count из раздела выше всё равно нужно выставить на хосте — контейнер этот лимит не переопределяет, он общий для ядра. Порт 9000 намеренно проброшен только на 127.0.0.1: наружу отдаём через nginx с SSL, а не голый HTTP.
Конфиг reverse proxy:
server {
listen 443 ssl http2;
server_name sonar.example.com;
ssl_certificate /etc/letsencrypt/live/sonar.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/sonar.example.com/privkey.pem;
client_max_body_size 50m;
location / {
proxy_pass http://127.0.0.1:9000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}
proxy_read_timeout увеличен намеренно — крупные проекты долго отдают результаты анализа, и дефолтные 60 секунд нередко режут соединение ошибкой таймаута. Общие грабли с настройкой nginx как прокси разобраны в статье nginx как reverse proxy: частые ошибки.
Интеграция с CI: токены, вебхуки и зависшие quality gate
Когда сама SonarQube поднята и работает, следующая волна ошибок — уже на стороне CI. Самая частая — раннер падает с 401 Unauthorized или You're not authorized to run analysis. Причина почти всегда одна: токен сгенерирован под пользователем, у которого нет прав Execute Analysis на конкретный проект, либо токен истёк (в новых версиях можно ставить срок жизни токена).
Токен создаётся в My Account → Security и передаётся в CI как секретная переменная, а не хардкодится в .gitlab-ci.yml:
sonarqube-check:
stage: test
image: sonarsource/sonar-scanner-cli:latest
variables:
SONAR_HOST_URL: "https://sonar.example.com"
SONAR_TOKEN: "$SONAR_TOKEN"
script:
- sonar-scanner -Dsonar.projectKey=my-project
only:
- merge_requests
- main
Если сборка виснет на этапе Waiting for the analysis report to be processed и в итоге падает по таймауту — почти всегда это либо перегруженный Compute Engine (не хватает heap sonar.ce.javaOpts, см. раздел про память), либо не настроен вебхук для quality gate: сканер ждёт ответа от SonarQube через sonar.qualitygate.wait=true, а вебхук не долетает, потому что SonarQube стоит за прокси и не может достучаться до раннера, или наоборот. Проверяйте доступность в обе стороны: раннер должен видеть SONAR_HOST_URL, а сама SonarQube — уметь достучаться до CI по вебхуку (Administration → Configuration → Webhooks), если вы используете sonar.qualitygate.wait.
Общие принципы настройки CI-раннера на сервере — в статье про GitLab CI Runner: частые ошибки и решения; если у вас Jenkins вместо GitLab — логика та же, разница только в том, где хранится токен.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Сколько реально нужно RAM для SonarQube на сервере?
Официальный минимум — 4 ГБ, но это тесно уже для одного среднего проекта. Для стабильной работы с несколькими репозиториями и параллельным CI закладывайте 6–8 ГБ: 2–3 ГБ под heap процессов SonarQube и остаток под PostgreSQL, ОС и CI-раннер.
Можно ли использовать вместо PostgreSQL встроенную H2?
Нет, начиная с современных веток SonarQube H2 поддерживается только для тестового локального запуска разработчика и явно не рекомендуется для сервера — данные не переживут перезапуск в промышленной эксплуатации, а сама СУБД не рассчитана на нагрузку.
Почему после обновления версии SonarQube перестал стартовать?
Чаще всего — несовместимая версия Java (проверьте требуемую JVM в release notes конкретной версии) или незавершённая миграция базы: посмотрите logs/ce.log и logs/web.log, там обычно явно написано, на каком шаге миграции застряло.
Нужен ли SonarQube отдельный сервер или можно на том же, где крутится CI?
Можно на одном, если ресурсов хватает с запасом, но лучше разносить — Compute Engine и Elasticsearch создают заметную нагрузку на CPU в моменты анализа, и она будет конкурировать с самими сборками CI за ресурсы.
Как понять, что упало — web, ce или search?
Смотрите отдельные логи в logs/: sonar.log — общий супервизор, web.log, ce.log, es.log. Именно es.log чаще всего содержит причину при проблемах с vm.max_map_count и памятью.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →