SonarQube в Docker Compose: готовый файл
Подключить статический анализ кода в проект — задача на бумаге простая: скачал образ, поднял контейнер, готово. На практике SonarQube падает при первом запуске из-за лимитов ядра, PostgreSQL требует отдельного тюнинга, а без токена и правильно настроенного Quality Gate анализ либо не запускается из CI, либо просто зелёный светофор без смысла. Ниже — рабочий docker-compose.yml, который поднимается с первого раза, и разбор всех мест, где можно споткнуться.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что нужно серверу для SonarQube
SonarQube Community Edition тянет за собой встроенный Elasticsearch, и именно он диктует требования к серверу — не сам Sonar. Минимум, с которым стоит начинать:
- RAM: 4 ГБ — это разумный минимум для стабильной работы на небольшом проекте или паре проектов. На 2 ГБ Elasticsearch либо не стартует, либо начинает падать по OOM при первом же крупном анализе.
- CPU: 2 ядра хватает для одного-двух проектов с редкими сборками; для команды с активным CI лучше 4.
- Диск: SSD обязателен — Elasticsearch активно пишет индекс, на HDD анализ крупного проекта может растянуться на десятки минут вместо секунд. Под данные закладывайте от 20 ГБ с запасом на рост истории анализов.
- Ядро Linux: нужны свежие лимиты
vm.max_map_countиfs.file-max— без них контейнер SonarQube не пройдёт стартовые проверки Elasticsearch и уйдёт в перезапуск по кругу.
Если создаёте сервер заново под эту задачу, берите конфигурацию не ниже 4 ГБ RAM / 2 vCPU — на меньшем железе вы будете бороться с падениями Elasticsearch, а не настраивать анализ кода.
Перед первым запуском правим лимиты ядра на хосте:
sudo tee -a /etc/sysctl.conf <<'EOF'
vm.max_map_count=524288
fs.file-max=131072
EOF
sudo sysctl -p
Это правится один раз на хосте, не в контейнере — контейнер использует лимиты ядра хост-системы, как бы вы ни настраивали ulimits внутри compose-файла.
docker-compose.yml для SonarQube и PostgreSQL
С 2020 года SonarQube официально поддерживает в качестве базы только PostgreSQL (поддержка MySQL и Oracle Embedded удалена), так что берём связку из двух сервисов. Создайте директорию под проект:
mkdir -p ~/sonarqube && cd ~/sonarqube
И файл docker-compose.yml:
services:
db:
image: postgres:16
container_name: sonarqube-db
restart: unless-stopped
environment:
POSTGRES_USER: sonar
POSTGRES_PASSWORD: change_me_strong_password
POSTGRES_DB: sonarqube
volumes:
- sonarqube_db_data:/var/lib/postgresql/data
networks:
- sonarnet
sonarqube:
image: sonarqube:community
container_name: sonarqube
restart: unless-stopped
depends_on:
- db
environment:
SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonarqube
SONAR_JDBC_USERNAME: sonar
SONAR_JDBC_PASSWORD: change_me_strong_password
ports:
- "9000:9000"
volumes:
- sonarqube_data:/opt/sonarqube/data
- sonarqube_extensions:/opt/sonarqube/extensions
- sonarqube_logs:/opt/sonarqube/logs
- sonarqube_temp:/opt/sonarqube/temp
ulimits:
nofile:
soft: 131072
hard: 131072
nproc:
soft: 8192
hard: 8192
networks:
- sonarnet
networks:
sonarnet:
volumes:
sonarqube_db_data:
sonarqube_data:
sonarqube_extensions:
sonarqube_logs:
sonarqube_temp:
Пара моментов, которые стоит поправить под себя перед запуском:
- Тег
sonarqube:communityтянет актуальный community-релиз — Docker Hub сам подставляет последнюю стабильную сборку под этим алиасом. Если хотите зафиксировать версию (что разумно для продакшена, чтобы обновление не прилетело незаметно на очередномdocker compose pull), посмотрите точные теги на странице образа в Docker Hub и подставьте конкретный номер вместоcommunity. - Пароль
change_me_strong_passwordзамените на свой в обоих местах — уdbи уsonarqubeони должны совпадать. ulimitsвнутри compose дублируют системные — они не заменяют правку sysctl на хосте, а дополняют её на уровне контейнера.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНастройка sysctl и первый запуск
Если правки sysctl уже применены, поднимаем стек:
docker compose up -d
docker compose logs -f sonarqube
Первый старт занимает от одной до нескольких минут — SonarQube инициализирует схему базы и поднимает встроенный Elasticsearch. В логе вы увидите примерно такую последовательность: Web Server startup → Compute Engine, и в самом конце SonarQube is operational. До этой строки лезть в веб-интерфейс бессмысленно, он ещё не отдаёт полноценный ответ.
Типичная причина падения на этом шаге — как раз забытый vm.max_map_count. В логе это выглядит как ошибка Elasticsearch про max virtual memory areas vm.max_map_count [65530] is too low. Если видите такое — проверьте, что sysctl применился именно на хосте (sysctl vm.max_map_count), а не только записан в файл, и перезапустите контейнер.
Первый вход, смена пароля, Quality Gate
Открываем http://IP-сервера:9000. Логин и пароль по умолчанию — admin / admin, система сразу попросит сменить пароль при первом входе. Дальше несколько шагов настройки, которые стоит сделать сразу, а не откладывать:
- Administration → Security → Users — создайте отдельного технического пользователя для CI вместо использования admin-токена.
- My Account → Security → Generate Tokens — сгенерируйте токен под этим техническим пользователем, тип "Global Analysis Token" или привязанный к конкретному проекту. Токен показывается один раз, сохраните его сразу в секреты CI.
- Quality Gates — по умолчанию активен профиль "Sonar way", он разумен как стартовая точка (покрытие новым кодом, дублирование, количество багов и уязвимостей на новом коде). Менять его стоит только осознанно, когда команда уже понимает, какие метрики реально важны именно для вашего проекта.
- Administration → General Settings → Server base URL — укажите реальный адрес сервера (с https, если настроили обратный прокси), иначе ссылки в отчётах и уведомлениях будут вести на
localhost.
Подключение SonarQube к CI
Дальше SonarQube без CI — просто дорогая игрушка, весь смысл в автоматическом анализе на каждый коммит или merge request.
GitLab CI. Добавьте job в .gitlab-ci.yml, используя официальный образ сканера:
sonarqube-check:
image:
name: sonarsource/sonar-scanner-cli:latest
entrypoint: [""]
variables:
SONAR_HOST_URL: "https://sonar.example.com"
SONAR_TOKEN: "$SONAR_TOKEN"
script:
- sonar-scanner -Dsonar.projectKey=my-project -Dsonar.sources=.
only:
- merge_requests
- main
SONAR_TOKEN кладём в CI/CD Variables проекта как protected и masked переменную, не в код. Подробнее про сам раннер и его настройку — в статье про настройку GitLab CI/CD на VPS.
Jenkins. Ставим плагин SonarQube Scanner, в Manage Jenkins → System добавляем сервер SonarQube (URL + токен как credential), и в Jenkinsfile:
stage('SonarQube Analysis') {
steps {
withSonarQubeEnv('sonarqube-server') {
sh 'sonar-scanner -Dsonar.projectKey=my-project'
}
}
}
stage('Quality Gate') {
steps {
timeout(time: 5, unit: 'MINUTES') {
waitForQualityGate abortPipeline: true
}
}
}
Для waitForQualityGate нужен настроенный webhook — в SonarQube это Administration → Configuration → Webhooks, URL вида http://jenkins:8080/sonarqube-webhook/. Без webhook Jenkins не получит статус Quality Gate и шаг просто зависнет до таймаута. Если Jenkins у вас поднят отдельно, обзор установки есть в статье про настройку Jenkins на VPS.
Если SonarQube и раннер CI живут в разных docker-compose стеках на одном хосте, проще всего подключить их к общей внешней сети Docker (docker network create ci-net, и в обоих compose-файлах прописать external: true), тогда сканер обращается к SonarQube по имени контейнера, а не по внешнему IP.
HTTPS, бэкапы и обновление версии
По умолчанию SonarQube отдаёт HTTP на 9000 порту — для рабочего использования это стоит спрятать за обратным прокси с TLS-сертификатом, а порт 9000 наружу не светить вообще (в compose уберите ports и оставьте только внутреннюю сеть, доступ — через прокси). Если уже используете Traefik для других сервисов на сервере, логика та же, что описана в статье про Traefik как reverse proxy для Docker — добавляете лейблы на сервис sonarqube вместо публикации порта.
Бэкап состоит из двух частей, и обе обязательны:
# дамп базы
docker exec sonarqube-db pg_dump -U sonar sonarqube > sonarqube_db_$(date +%F).sql
# данные и расширения (плагины, если ставили)
docker run --rm -v sonarqube_sonarqube_data:/data -v $(pwd):/backup \
alpine tar czf /backup/sonarqube_data_$(date +%F).tar.gz -C /data .
Без дампа базы бэкап volume'ов бесполезен — вся история анализов, пользователи и настройки живут в PostgreSQL, а не в файлах SonarQube.
Обновление версии — момент, где стоит быть осторожным. SonarQube не всегда поддерживает прыжок через несколько major-версий за один шаг миграции базы; перед апгрейдом всегда смотрите официальные release notes на предмет пути обновления именно с вашей версии, и обязательно снимайте бэкап базы перед docker compose pull && docker compose up -d. Миграция схемы БД запускается автоматически при старте новой версии и в норме занимает от секунд до пары минут в зависимости от объёма накопленной истории — если анализов и проектов много, процесс может быть заметно дольше, ориентируйтесь по логам, а не по секундомеру.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли использовать SQLite или H2 вместо PostgreSQL?
Нет, встроенная база H2 в SonarQube — только для локальной оценки продукта, для неё явно отключена поддержка апгрейдов и она не годится для продакшена. Для любого реального использования нужен PostgreSQL.
Сколько проектов выдержит SonarQube на 4 ГБ RAM?
Зависит от размера кодовой базы и частоты анализов, а не от количества проектов как такового — небольшая команда с редкими сборками спокойно уложится, активный CI с параллельными анализами крупных монолитов потребует больше памяти. Ориентируйтесь по логам Elasticsearch и Compute Engine на предмет OOM, а не по абстрактному числу проектов.
Почему анализ из CI падает с ошибкой авторизации, хотя токен верный?
Чаще всего дело в SONAR_HOST_URL — если сканер обращается к SonarQube не по тому адресу (например, по внешнему IP вместо имени контейнера в общей docker-сети, и наружу порт закрыт), запрос вообще не доходит до сервера, а ошибка на стороне сканера маскируется под проблему авторизации.
Нужен ли отдельный сервер под SonarQube, или можно поставить рядом с GitLab/Jenkins?
Технически можно на одном хосте, но Elasticsearch внутри SonarQube довольно прожорлив по памяти, и совместно с GitLab или Jenkins на слабой конфигурации вы получите конкуренцию за RAM и нестабильные сборки. Для команды с активным CI разумнее развести SonarQube на отдельный сервер.
Как перенести SonarQube на новый сервер?
Дамп PostgreSQL плюс архив volume sonarqube_data (там хранятся плагины и часть индексов) — переносите оба на новый хост, поднимаете тот же docker-compose.yml, восстанавливаете дамп в свежий контейнер db до первого старта sonarqube.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →