Привет, Хабр!
Меня зовут Андрей Жуйков, я руководитель направления СУБД компании «Диасофт».
Контейнеры давно стали стандартом современной разработки. Согласно отчету Docker State of Application Development 2025, они используются примерно в 92% IT-организаций и фактически стали универсальным способом упаковки и запуска приложений независимо от платформы и окружения. Это тот случай, когда инфраструктура перестает мешать и начинает экономить время.
Именно поэтому Digital Q.DataBase доступна, в том числе, в виде Docker-образа. Это позволяет за несколько минут попробовать Oracle- и MS SQL-совместимую СУБД на Windows, Linux и macOS, ограничившись несколькими командами, без сложной установки и длительного онбординга. Полноценная рабочая среда готова к использованию сразу после старта контейнера.
Мы предоставляем бесплатную полнофункциональную версию Digital Q.DataBase с единственным ограничением до 8 ядер vCPU. Скачать ее можно на сайте https://database.diasoft.ru, нажав кнопку «Скачать бесплатно». Далее предлагается два варианта загрузки с регистрацией личного кабинета и без нее. Для быстрого старта можно выбрать вариант без регистрации.
В результате вы получаете архив tar.gz с PDF-мануалами, примерами T-SQL и PL/SQL-скриптов, release notes текущей версии и еще одним tar.gz с Docker-образом на базе Ubuntu 22.04.3 LTS. Образ уже содержит серверный и клиентский пакеты СУБД, а пользователю доступны сервер базы данных, терминальные SQL-клиенты для трех диалектов, Мастер переноса и Мастер сравнения БД.
По сути, после того как вы скачали архив и подготовили директорию, для запуска Digital Q.DataBase достаточно четырех команд: загрузить Docker-образ (load), запустить контейнер (run), при необходимости подправить pg_hba.conf и перезапустить его для применения изменений (restart).

Сначала загружаем Docker-образ из локального файла. Образ не тянется из registry, а импортируется напрямую, что типично для офлайн-поставок и enterprise-дистрибуций, где важно контролировать версию и не зависеть от внешних репозиториев.
sudo docker load -i docker-qdatabase64xid-17-17.4.25110901-ubuntu22_x86_64.tar.gz
Loaded image: qdatabase_docker:latest
Проверяем, что образ успешно загрузился и доступен локально.
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
qdatabase_docker latest 6bc296d4622c 2 weeks ago 1.49GB
После этого выполняем запуск одной командой. Образ собран под архитектуру amd64, поэтому платформа указывается явно. На системах с arm64, например на Apple Silicon, этот параметр можно задать опционально, чтобы избежать предупреждений. Далее задается фиксированное имя, включается автоматический рестарт, увеличивается объем shared memory для корректной работы СУБД, пробрасываются порты и данные выносятся в Docker volume.
sudo docker run -it --platform=linux/amd64 --restart always --name=qdatabase-17 --shm-size=1g \--env="DISPLAY" --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" \-p 5445:5445 -p 1433:1433 -p 1521:1521 \-v qdb_data:/var/lib/qdatabase-17/data qdatabase_docker
Порты пробрасываются с соответствием один к одному между хостом и контейнером. Это позволяет подключаться к базе по PostgreSQL, MS SQL и Oracle-протоколам без нестандартных настроек. Если на вашем хосте порт 5445 по какой-то причине занят, можно указать любой другой свободный порт, например 5459. При этом порт службы внутри контейнера при необходимости настраивается в файле postgresql.conf.
Далее проверяем, что контейнер запущен и какие порты опубликованы (можно обычный docker ps).
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
NAMES STATUS PORTSqdatabase-17 Up 53 seconds 0.0.0.0:1433->1433/tcp, [::]:1433->1433/tcp, 0.0.0.0:1521->1521/tcp, [::]:1521->1521/tcp, 0.0.0.0:5445->5445/tcp, [::]:5445->5445/tcp
Дополнительно смотрим фактический проброс портов.
sudo docker port qdatabase-17
1433/tcp -> 0.0.0.0:14331433/tcp -> [::]:14331521/tcp -> 0.0.0.0:15211521/tcp -> [::]:15215445/tcp -> 0.0.0.0:54455445/tcp -> [::]:5445
После запуска смотрим, где расположен основной конфигурационный файл сервера.
docker exec -it qdatabase-17 bash -lc 'qsql -U qdbadmin -d qdb -c "SHOW config_file;"'
config_file--------------------------------------------/var/lib/qdatabase-17/data/postgresql.conf(1 row)
Этот файл содержит ключевые параметры работы СУБД, включая настройки памяти, процессов и портов.
Далее проверяем, сколько vCPU видит система внутри контейнера:
docker exec -it qdatabase-17 bash -lc 'grep -c ^processor /proc/cpuinfo'
8
Это важно, поскольку бесплатная версия поддерживает до 8 vCPU включительно. Если система видит большее количество ядер, СУБД может уйти в циклический перезапуск. В этом случае в каталоге /var/log/qdatabase-17/появляются логи с сообщением Digital Q.DataBase: License not initialized, reason: Core count violation.
Чтобы этого избежать, число vCPU необходимо ограничить на уровне Docker Engine или виртуальной машины, например в Docker Desktop через настройки General → Resources → CPU limit = 8. В конце статьи приведена отдельная команда для проверки и диагностики этой ситуации.
После этого проверяем файл сетевых правил доступа.
docker exec -it qdatabase-17 bash -lc 'qsql -U qdbadmin -d qdb -c "SHOW hba_file;"'
hba_file----------------------------------------/var/lib/qdatabase-17/data/pg_hba.conf(1 row)
Открываем файл pg_hba.conf для редактирования и временно разрешаем подключения с любых адресов. Это делается только для тестов и демо.
docker exec -it qdatabase-17 bash -lc 'nano /var/lib/qdatabase-17/data/pg_hba.conf'
В моем случае последние три строки разрешают доступ для всех подключений:
docker exec -it qdatabase-17 bash -lc 'tail -n 3 /var/lib/qdatabase-17/data/pg_hba.conf'
# allow allhost all all 0.0.0.0/0 md5hostallall ::/0 md5
После этого перезапускаем контейнер, чтобы база перечитала конфигурацию и применила новые сетевые настройки.
docker restart qdatabase-17
Теперь заходим внутрь контейнера и начинаем проверку работы СУБД в разных диалектах.
sudo docker exec -it qdatabase-17 /bin/bashroot@ec348e89381b:/#
PostgreSQL-диалект
Сначала подключаемся к базе Digital Q.DataBase в родном PostgreSQL-диалекте PL/pgSQL под пользователем qdbadmin и выполняем базовые операции. Digital Q.DataBase полностью поддерживает нативный PL/pgSQL, поэтому начинать логично именно с него. Да, нам гораздо интереснее PL/SQL и T-SQL, но для первой проверки возьмем простой набор команд, который одинаково удобно выполнять и в консоли, и в DBeaver.
qsql -U qdbadmin qdb;qsql (17.4)Type "help" for help.qdb=#
CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(50) NOT NULL, email VARCHAR(100) UNIQUE, age INTEGER, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
CREATE TABLE
Командой ALTER ROLE мы можем в любой момент поменять пароль пользователя. Дефолтовый пароль: qdbadmin
qdb=# SELECT * FROM users;id | name | email | age | created_at ----+------+-------+-----+------------(0 rows)
qdb=# \dt List of relations Schema | Name | Type | Owner --------+-------+-------+---------- public | users | table | qdbadmin(1 row)
qdb=# DROP TABLE users;DROP TABLE
qdb=# ALTER ROLE qdbadmin WITH PASSWORD 'qdbadmin';ALTER ROLE
qdb=# \q
Microsoft-диалект

Теперь самое время попробовать T-SQL. Подключимся через консоль, создадим базу qdb_demo_sales, а затем настроим к ней соединение в DBeaver по порту 1433 и продолжим работу уже в привычном интерфейсе.
tsql -H localhost -p 1433 -U qdbadmin -P qdbadmin -D master
locale is "C"
locale charset is "ANSI_X3.4-1968"
using default charset "ISO-8859-1"
Setting master as default database in login packet
Changed database context to 'master'.
1>
IF DB_ID('qdb_demo_sales') IS NOT NULLBEGIN ALTER DATABASE qdb_demo_sales SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE qdb_demo_sales;END;GO
CREATE DATABASE qdb_demo_sales;
GO
Выходим (через exit) и далее создаем таблицу продаж. Цена хранится в UnitPrice, количество в Quantity, а сумма сделки и месяц продажи рассчитываются автоматически через вычисляемые колонки. Это позволяет не дублировать бизнес-логику в каждом запросе и сразу готовить данные для аналитики.
USE qdb_demo_sales;GO
CREATE TABLE dbo.Sales ( SaleID INT IDENTITY(1,1) PRIMARY KEY, ProductType NVARCHAR(50) NOT NULL, ProductName NVARCHAR(150) NOT NULL, SaleDate DATE NOT NULL, Quantity INT NOT NULL CHECK (Quantity > 0), UnitPrice DECIMAL(12,2) NOT NULL CHECK (UnitPrice >= 0), TotalAmount AS (Quantity * UnitPrice), SaleMonth AS (FORMAT(SaleDate, 'yyyy-MM')));GO
После этого загружаем тестовые данные. В примере используются продажи iPhone за 2025 год с ценами в рублях.
INSERT INTO dbo.Sales (ProductType, ProductName, SaleDate, Quantity, UnitPrice) VALUES(N'Электроника', N'iPhone 15 Pro Max 256GB', '2025-01-10', 2, 129990.00),(N'Электроника', N'iPhone 15 Pro 128GB', '2025-01-22', 1, 109990.00)(N'Электроника', N'iPhone 15 128GB', '2025-02-05', 3, 89990.00),(N'Электроника', N'iPhone 14 Plus 128GB', '2025-03-12', 1, 79990.00),(N'Электроника', N'iPhone SE (3rd Gen) 64GB', '2025-05-18', 4, 37990.00),(N'Электроника', N'iPhone 15 Pro Max 512GB', '2025-11-08', 1, 149990.00);GO
Теперь, не меняя структуру данных и не создавая временных таблиц, мы строим итоговый аналитический отчет одним SQL-запросом.
Через CTE в одном месте задается период анализа, в других считаются ключевые показатели, определяется самый продаваемый товар и месяц с максимальной выручкой.
WITH base AS ( SELECT * FROM dbo.Sales WHERE SaleDate BETWEEN CAST('2025-01-01' AS DATE) AND CAST('2025-12-31' AS DATE)),kpi AS ( SELECT COUNT(*) AS количество_продаж, SUM(TotalAmount) AS выручка, AVG(TotalAmount) AS средний_чек, MAX(TotalAmount) AS максимальная_продажа, MIN(TotalAmount) AS минимальная_продажа FROM base),top_product AS ( SELECT TOP (1) ProductName AS топ_товар, SUM(TotalAmount) AS выручка_топ_товара FROM base GROUP BY ProductName ORDER BY SUM(TotalAmount) DESC),top_month AS ( SELECT TOP (1) SaleMonth AS лучший_месяц, SUM(TotalAmount) AS выручка_лучшего_месяца FROM base GROUP BY SaleMonth ORDER BY SUM(TotalAmount) DESC)SELECT k.количество_продаж, k.выручка, k.средний_чек, k.максимальная_продажа, k.минимальная_продажа, p.топ_товар, p.выручка_топ_товара, m.лучший_месяц, m.выручка_лучшего_месяцаFROM kpi kCROSS JOIN top_product pCROSS JOIN top_month m;GO


В результате мы получаем полноценный аналитический отчет поверх реальных данных, написанный в привычном T-SQL-стиле. Все это выполняется в одном контейнере Digital Q.DataBase, который одновременно поддерживает PostgreSQL, MS SQL Server и Oracle-диалекты.
Для работы с TDS-диалектом достаточно настроить DBeaver или SSMS. Если клиент запускается с нуля, максимум, что потребуется, – это автоматически скачать драйвер одной кнопкой.
Далее указываем хост, порт 1433 и учётные данные по умолчанию qdbadmin:qdbadmin.
Oracle-диалект

Oracle-диалект тестируется иначе. Подключение через DBeaver здесь не используется, так как TNS недоступен.
Зато Oracle-совместимый SQL стабильно проверяется напрямую внутри контейнера через qclient, без внешних драйверов и дополнительной настройки.
Подключаемся к Oracle-диалекту:
qclient qdb://SYSDBA:SYSDBA@localhost:1521/qdbora
Теперь давайте напишем небольшой пример без таблиц и вспомогательных объектов, чтобы сосредоточиться именно на возможностях языка и системных пакетов. В этом скрипте используются DBMS_ASSERT, DBMS_RANDOM, UTL_CALL_STACK и DBMS_LOB, которые позволяют проверить корректность имен, сгенерировать данные и поработать с CLOB. Такой пример удобно запускать прямо из консоли и использовать как быстрый smoke-test Oracle-диалекта.
SET SERVEROUTPUT ON
DECLARE v_name VARCHAR2(128); v_num NUMBER; v_clob CLOB; v_buf VARCHAR2(4000); v_len NUMBER := 4000;BEGIN DBMS_OUTPUT.PUT_LINE('== QDB Oracle-диалект: mini demo ==');
v_name := DBMS_ASSERT.SIMPLE_SQL_NAME('products_demo'); DBMS_OUTPUT.PUT_LINE('DBMS_ASSERT: ' || v_name);
v_num := TRUNC(DBMS_RANDOM.VALUE(1, 100)); DBMS_OUTPUT.PUT_LINE('DBMS_RANDOM: ' || TO_CHAR(v_num));
DBMS_OUTPUT.PUT_LINE('UTL_CALL_STACK.SUBPROGRAM(1): ' || UTL_CALL_STACK.SUBPROGRAM(1));
DBMS_LOB.CREATETEMPORARY(v_clob, TRUE); DBMS_LOB.WRITE(v_clob, LENGTH('Hello from DBMS_LOB'), 1, 'Hello from DBMS_LOB'); DBMS_LOB.READ(v_clob, v_len, 1, v_buf); DBMS_OUTPUT.PUT_LINE('DBMS_LOB: ' || v_buf); DBMS_LOB.FREETEMPORARY(v_clob);
DBMS_OUTPUT.PUT_LINE('== OK ==');END;/
Проверка SQL-имен через DBMS_ASSERT, генерация случайных значений с DBMS_RANDOM, доступ к стеку вызовов через UTL_CALL_STACK и работа с CLOB через DBMS_LOB.
== QDB Oracle-диалект: mini demo ==DBMS_ASSERT: products_demoDBMS_RANDOM: 54UTL_CALL_STACK.SUBPROGRAM(1): __anonymous_blockDBMS_LOB: Hello from DBMS_LOB== OK ==
PL/SQL procedure successfully completed.
Напоминаю, что внутри дистрибутива, будь то Docker-контейнер или deb-пакеты для Astra Linux, есть папка samples. В ней собраны примеры как для T-SQL, так и для PL/SQL, которые позволяют быстро начать работу и сразу протестировать возможности нашей СУБД. Эти примеры дают понятный и удобный порог входа и помогают быстрее разобраться с функциональностью платформы.

Лицензия и отладка
Если контейнер с Digital Q.DataBase не запускается, одна из частых причин – ограничение лицензии по количеству ядер.
Лицензия ограничивает число процессорных ядер, на которых может работать продукт, и неважно, физические это ядра или виртуальные. В Docker и виртуальных машинах учитываются vCPU, то есть логические процессоры, которые видит операционная система. Проверка выполняется по данным ОС, в том числе через файл /proc/cpuinfo.
Чтобы быстро понять, в этом ли проблема, можно запустить отладочный контейнер и посмотреть, сколько CPU реально доступно внутри:
docker run --rm -it --name qdb-debug \--platform linux/amd64 \--entrypoint bash \qdatabase_docker -lc '/opt/qdatabase-17/start_qdb1.sh >/dev/null 2>&1 &sleep 8
echo "===== CPU VISIBILITY ====="echo -n "nproc: "nprocecho -n "/proc/cpuinfo processors: "grep -c ^processor /proc/cpuinfo
echo
echo "===== CORE COUNT VIOLATION ====="
grep -RIn "Core count violation" /var/log/qdatabase-17 | head -n 5
'
Если в выводе видно, что система видит больше ядер, чем разрешено лицензией, и в логах присутствует сообщение Core count violation, значит причина найдена. Решение простое: зайти в настройки Docker Desktop, открыть раздел General или Resources, выставить CPU limit в значение, укладывающееся в лицензию, например, 8 ядер, нажать Apply & Restart и перезапустить контейнер.
После примен��ния этих настроек ограничение по ядрам больше не нарушается, лицензия инициализируется корректно.
===== CPU VISIBILITY =====
nproc: 10
/proc/cpuinfo processors: 10
===== CORE COUNT VIOLATION =====
/var/log/qdatabase-17/postgresql-09.log:1:2026-02-09 18:47:21.144 MSK 22 @ from [vxid: txid:0] [] [] LOG:
Q.DataBase: License not initialized, reason: Core count violation.

Мастера
О том, как работают наши мастера переноса и сравнения БД, читайте предыдущую статью.
Для запуска мастеров в контейнере достаточно подготовить YAML-файлы конфигурации: отдельно описать подключение к исходной БД (source.yaml) и к целевой Digital Q.DataBase (target.yaml), а при выборочном переносе – добавить файл с перечнем объектов (cs.yaml).
Команды переноса и сравнения выполняются внутри уже запущенного контейнера, поэтому сначала открываем терминал контейнера через docker exec, а затем запускаем нужный бинарник из каталога /opt/qdb/bin.
Такой подход удобен тем, что не нужно поднимать дополнительные контейнеры: сервер и утилиты уже находятся в одном окружении, а конфиги можно хранить на хосте и передавать внутрь (например, через volume) или создавать прямо в контейнере.
После переноса мастер сравнения запускается тем же способом – через docker exec и команду сравнения с YAML-конфигом.
Зайти в контейнерsudo docker exec -it qdatabase-17 /bin/bash
Пример: полный перенос
/opt/qdb/bin/mssql_migrator -config-source source.yaml -config-target target.yaml -scope all -target-action new
Пример: частичный перенос
/opt/qdb/bin/mssql_migrator -config-source source.yaml -config-target target.yaml -scope custom -object-file cs.yaml -target-action new
Пример: сравнение
/opt/qdb/bin/db_compare_mssql -config compare.yaml
Вывод
Digital Q.DataBase в Docker позволяет за четыре команды проверить совместимость с PostgreSQL, T-SQL и Oracle-диалектом без отдельной установки и сложных окружений. Все ключевые сценарии, от аналитических запросов до миграции и smoke-тестов, выполняются в одном контейнере и сразу дают нужный результат.