Открываю новый цикл статей: будем разбираться в администрировании PostgreSQL с нуля, от установки до репликации, и в первом уроке поднимем сервер в официальном Docker-образе 🐧.
🖐️Эй!
Подписывайтесь на наш телеграм @r4ven_me📱, чтобы не пропустить новые публикации на сайте😉. А если есть вопросы или желание пообщаться по тематике - заглядывайте в Вороний чат @r4ven_me_chat🧐. Также в блоге теперь доступно соавторство 🐧🐧🐧.
Предисловие
Подобные материалы принято начинать с определения и исторической справки. Будем придерживаться данной традиции.
Что такое СУБД и что такое PostgreSQL
СУБД (система управления базами данных) - программное обеспечение, которое хранит структурированные данные, обеспечивает к ним конкурентный доступ, следит за целостностью и отвечает на запросы через язык SQL. Проще говоря - надёжный посредник между вашими данными и приложениями, которым эти данные нужны.
PostgreSQL - свободная объектно-реляционная СУБД, которую разрабатывает международное открытое сообщество (лицензия PostgreSQL, близкая по духу к MIT/BSD). Среди open-source СУБД она выделяется, пожалуй, самой богатой функциональностью “из коробки” - полноценные транзакции, гибкая система типов, JSON, полнотекстовый поиск, десятки видов индексов и механизм расширений, через который в базу можно добавить практически что угодно, от геоданных (PostGIS) до векторного поиска (pgvector).
Немного истории
История начинается в 1986 году в университете Беркли: Майкл Стоунбрейкер, уже создавший к тому моменту СУБД Ingres, запускает исследовательский проект Postgres - “Post-Ingres”, попытку сделать СУБД с поддержкой пользовательских типов данных и правил. В 1994 году проект обзавёлся собственным интерпретатором SQL и получил имя Postgres95, а в 1996-м, с переходом на открытую модель разработки, был переименован в PostgreSQL - чтобы явно отразить поддержку SQL. С тех пор вышло почти три десятка мажорных версий, а сам проект живёт по предсказуемому годовому циклу релизов.
Вклад российских разработчиков
Отдельно стоит отметить, что в развитии PostgreSQL заметный след оставили и российские разработчики. Олег Бартунов и Фёдор (Теодор) Сигаев из МГУ - авторы инфраструктуры GiST- и GIN-индексов, полнотекстового поиска (tsearch2), типа hstore и ряда других расширений, без которых сложно представить современный PostgreSQL. Александр Коротков - действующий член PostgreSQL Core Team (это высший руководящий орган проекта из считанных человек), внёс значительный вклад в планировщик запросов и индексные методы доступа. А выросшая из той же научной группы компания Postgres Professional - один из крупнейших корпоративных контрибьюторов проекта, поддерживающий собственную сборку Postgres Pro и регулярно отправляющий патчи в апстрим.
PostgreSQL сегодня - это стандартный де-факто выбор и для собственной инфраструктуры, и для облачных сервисов, а администрировать его, рано или поздно приходится любому Linux-админу, даже если в штате есть отдельный DBA. Этот цикл статей призван улучшить взаимопонимание между разными специалистами, чтобы они могли разговаривать на “одном языке”.
Также это способ для меня (и, надеюсь, для вас) узнать/освежить знания о том, как устроен PostgreSQL изнутри, как его настраивать, обслуживать, бэкапить и реплицировать - при этом не забывая и про сам язык SQL, потому что без него администрирование СУБД довольно бессмысленно.
Формат будет такой: каждый урок - отдельная статья, от простого к сложному. Ориентировочно пройдёмся по установке, работе с psql и графическими клиентами, архитектуре и MVCC, конфигурированию, обслуживанию (VACUUM, WAL), хранению данных, системному каталогу, мониторингу, правам доступа, бэкапам и репликации. По ходу дела что-то наверняка добавится или сократится.
Первое отличие от классических курсов: рабочим стендом будет не “живой” PostgreSQL, установленный из пакетов прямо на хост, а официальный образ в Docker. Во-первых, это ближе к тому, как PostgreSQL реально разворачивают в 2026 году. Во-вторых, для учебных целей это просто удобнее: сломали кластер экспериментом - снесли volume и подняли заново за 10 секунд, без переустановки системы.
📝 Установку и настройку самого Docker Engine я подробно разбирал в отдельной статье - если Docker ещё не установлен, начните с неё.
Примеры данных для практики (таблицы, запросы, домашние задания 😀) будут строиться вокруг вымышленной инфраструктуры - что-то в духе учёта серверов и дата-центров условной хостинг-компании. Базу назвал просто raven. Саму схему таблиц покажу в одном из следующих уроков, когда дойдём до CREATE TABLE.
Структура СУБД PostgreSQL

Вводные данные
ПО, используемое в статье:
| ПО | Версия |
|---|---|
| Debian (хост) | 13 |
| Docker Engine | 28 |
| PostgreSQL (образ) | 18 |
| psql (образ) | 18 |
| DBeaver Community | 26 |
Все команды выполняются на Linux-хосте с уже установленным Docker Engine и плагином docker compose. Дистрибутив хоста непринципиален - контейнер ведёт себя одинаково что на Debian, что на любом другом Linux, в этом и смысл контейнеризации.
Подготовка окружения
Проверяем, что Docker и Compose-плагин на месте:
sudo docker version
sudo docker compose versionСоздаём директорию проекта:
sudo install -m 700 -d /etc/compose/postgresВыбор образа PostgreSQL
На Docker Hub официальный образ postgres собирается в двух основных вариантах: обычный, на базе Debian, и -alpine, на базе Alpine Linux. Alpine-вариант заметно легче, но использует musl вместо glibc, из-за чего периодически возникают проблемы с локалями и коллациями - а нам ещё предстоит урок про табличные пространства и низкоуровневое хранение, где эти нюансы важны. Поэтому для курса беру обычный образ, без -alpine.
Тег версии - 18, актуальная стабильная ветка PostgreSQL на момент написания статьи. Если к моменту, когда вы это читаете, вышла 19 - в рамках учебного стенда можно смело брать её, принципиальной разницы для наших уроков не будет.
Запуск PostgreSQL в Docker Compose
Создаём compose-файл:
sudo vim /etc/compose/postgres/compose.yamlНаполняем:
---
# https://hub.docker.com/_/postgres
networks:
postgres_net:
name: postgres_net
driver: bridge
driver_opts:
com.docker.network.bridge.name: br-postgres
volumes:
postgres_data:
name: postgres_data
services:
postgres:
image: postgres:18
container_name: postgres
restart: unless-stopped
stop_grace_period: 1m
cpus: 2
mem_limit: 2G
hostname: postgres
env_file: ./.env
networks:
- postgres_net
ports:
- "127.0.0.1:5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s📝 Обратите внимание на удвоенные $$ в healthcheck - переменные POSTGRES_USER и POSTGRES_DB подставляются уже внутри контейнера через env_file, а не самим Compose при чтении файла, поэтому доллар нужно экранировать другим долларом (такой синтаксис).
Порт 5432 публикуем только на 127.0.0.1 - для учебного стенда этого достаточно, а наружу базу лучше не светить без крайней необходимости.
Создаём env-файл:
sudo vim /etc/compose/postgres/.envНаполняем:
# https://hub.docker.com/_/postgres
TZ=Europe/Moscow
POSTGRES_USER=ivan
POSTGRES_PASSWORD=r4ven_me
POSTGRES_DB=raven
PGDATA=/var/lib/postgresql/data/pgdataГде:
TZ- таймзона контейнера;POSTGRES_USER- суперпользователь кластера, создаётся при первой инициализации;POSTGRES_PASSWORD- его пароль;POSTGRES_DB- база данных, которая будет создана по умолчанию (в ней и будем работать весь курс);PGDATA- подкаталог внутри volume для файлов кластера. Без негоinitdbпри первом запуске иногда ругается на служебныйlost+found, который Docker может создавать в корне тома.
📝 В боевом окружении пароль обязательно нужно задавать сложный, например, сгенерировать через openssl rand -hex 16. Но это учебный стенд, который вы поднимаете локально у себя, поэтому оставляю простой и предсказуемый пароль r4ven_me - так удобнее сверяться с примерами в статьях, не подглядывая каждый раз в свой .env.
☝️ Переменные окружения POSTGRES_* применяются только при первой инициализации кластера, то есть когда volume с данными ещё пустой. Если вы поменяете пароль в .env уже после первого запуска, сам PostgreSQL об этом не узнает - придётся менять пароль изнутри через ALTER ROLE либо пересоздавать volume.
Запускаем стек:
sudo docker compose -f /etc/compose/postgres/compose.yaml up -d
sudo docker compose -f /etc/compose/postgres/compose.yaml logs -f
💡 Для выхода из режима просмотра логов нажмите Ctrl+c.
Проверяем:
sudo docker compose -f /etc/compose/postgres/compose.yaml psЕсли всё нормально, увидим примерно такой вывод:

Сразу же настроим автозапуск и управление нашей СУБД с помощью Systemd:
sudo tee /etc/compose/postgres/postgres.service << EOF
[Unit]
Description=PostgreSQL course lab service
Requires=docker.service
After=docker.service
[Service]
Restart=always
RestartSec=5
User=root
Group=root
WorkingDirectory=/etc/compose/postgres
ExecStart=/usr/bin/docker compose up --remove-orphans
ExecStop=/usr/bin/docker compose down
[Install]
WantedBy=multi-user.target
EOFsudo chmod 600 /etc/compose/postgres/postgres.service
sudo ln -vs /etc/compose/postgres/postgres.service /etc/systemd/system
sudo systemctl daemon-reload
sudo systemctl enable --now postgres
sudo systemctl status postgres
Теперь сервисом postgres можно управлять утилитой systemctl, а журнал сервиса с помощью journalctl:
sudo systemctl stop postgres
sudo systemctl start postgres
sudo systemctl restart postgres
sudo systemctl status postgres
sudo journalctl -fu postgresПроверка подключения
Смотреть на СУБД можно двумя способами - через консольный psql и через графический клиент. В следующем уроке разберём оба инструмента подробно, а пока просто убедимся, что сервер живой и отвечает.
Через psql
psql уже есть внутри образа, отдельно ставить ничего не нужно - выполняем его прямо в контейнере:
sudo docker compose -f /etc/compose/postgres/compose.yaml exec postgres psql -U ivan -d raven -c "SELECT version();"Если всё нормально, увидим примерно такой вывод:

Через DBeaver
В качестве графического клиента в этом курсе буду использовать DBeaver Community - он открытый, бесплатный, кроссплатформенный и умеет практически всё, что нужно для администрирования PostgreSQL. Скачиваем нужную версию, устанавливаем и запускаем.
Далее создаём новое подключение к нашей БД (New Database Connection → PostgreSQL), указав следующие параметры:
Host-127.0.0.1(или адрес вашего сервера, если Docker крутится не локально);Port-5432;Database-raven;Username-ivan;Password-r4ven_me(или что вы указали вPOSTGRES_PASSWORD, посмотреть можно так:grep POSTGRES_PASSWORD ./.env).


📝 Если у вас отсутствуют драйверы для PostgreSQL, то бобёр любезно скачает их из интернета (maven.org).
Проверяем подключение кнопкой Test Connection...:

Затем открываем SQL-редактор и выполняем тот же запрос, что и в psql:

SELECT version();
SELECT current_date;💡 Если в скрипте запросов несколько (разделены символом ;), то для выполнения конкретного из них выделите его мышью и после нажмите кнопку запуска (оранжевый треугольник).

Отлично! Сервер поднят, доступен и из консоли, и из GUI - можно двигаться дальше.
📝 Начиная с этого урока SQL-операторы буду писать в верхнем регистре (SELECT, FROM, WHERE и так далее) - это негласный, но общепринятый в SQL стиль, который отделяет ключевые слова языка от имён таблиц, столбцов и функций. Для PostgreSQL регистр ключевых слов не имеет значения, это чисто вопрос читаемости. А вот мета-команды самого psql (те, что начинаются на \) по традиции остаются строчными - это уже не SQL, а отдельный язык самого клиента.
Сброс окружения для экспериментов
Отдельно стоит сказать про то, как быстро вернуть стенд в чистое состояние - за курс наверняка захочется не раз всё сломать намеренно и начать заново:
sudo systemctl stop postgres
sudo systemctl disable postgres
sudo docker image rm postgres:18
sudo docker volume rm postgres_data
sudo docker network rm postgres_net
sudo rm -rf /etc/compose/postgres⚠️ docker volume rm необратимо удаляет все данные внутри кластера, включая всё, что вы успели создать за прошлые уроки. Используйте, только когда осознанно хотите начать с чистого листа.
Возможные проблемы
- порт 5432 уже занят
Error response from daemon: driver failed programming external connectivity on endpoint postgres: Bind for 127.0.0.1:5432 failed: port is already allocatedЧаще всего это значит, что на хосте уже крутится “живой” PostgreSQL, установленный из пакетов. Либо остановите его, либо смените порт публикации в compose.yaml, например на 127.0.0.1:5433:5432 (не забудьте поменять порт и в подключении DBeaver).
- password authentication failed for user “ivan”
Если вы меняли POSTGRES_PASSWORD в .env уже после первого запуска - это ожидаемо, см. предупреждение выше про инициализацию кластера. Проще всего либо поменять пароль изнутри (ALTER ROLE ivan WITH PASSWORD '...'), либо, если данные ещё не жалко, пересоздать volume.
Послесловие
Ожидаемо несложный первый шаг, но фундамент важный - весь курс будет крутиться вокруг этого контейнера. Благо пересобрать учебный стенд просто.
В следующем уроке подробно разберём утилиту psql, а заодно освоимся в графический клиент DBeaver уже более предметно.
В качестве внеклассной работы рекомендую посмотреть очень интересное интервью с Иваном Панченко, сооснователем компании Postgres Pro. В видео речь идёт об идеологии open source, вкладе наших соотечественников в развитие проекта Postgres, сравнение с Oracle и многое другое. Очень интересно следить за ходом мыслей Ивана, в плане использования модели открытого ПО для бизнеса. Ну и конечно же интересно слушать про различные нюансы этой модели, а также про историю развития СУБД.
В общем рекомендую 👍.
Длительность видео больше полутора часа, но смотрится на одном дыхании 😌.
Спасибо, что читаете. Успехов в изучении PostgreSQL! 🐧
Используемые материалы
- Официальный образ PostgreSQL на Docker Hub
- Документация PostgreSQL
- Моя статья по установке Docker Engine на Debian
- DBeaver Community Edition
👨💻Ну и…
Не забывайте про нашу телегу📱и чат 💬
Или может хотите стать соавтором? Тогда клик сюда🔗
Всех благ✌️
That should be it. If not, check the logs 🙂



Комментарии