Пошук уроків, статей та іншого контенту
Запуск, налаштування та робота з PostgreSQL у Docker-контейнері.
Docker-контейнер із PostgreSQL ізолює базу даних від операційної системи та спрощує:
встановлення однакової версії PostgreSQL для всієї команди;
запуск і зупинку бази даних;
підключення бази до застосунку в окремій Docker-мережі;
перенесення конфігурації між середовищами;
збереження даних у Docker volume.
Контейнер сам по собі є тимчасовим. Якщо видалити контейнер без окремого сховища, дані бази також будуть втрачені. Тому для PostgreSQL потрібно використовувати volume.
docker runПереконайтеся, що Docker встановлено та запущено:
docker --versionЗапустімо контейнер PostgreSQL:
docker run --name app-postgres \
-e POSTGRES_USER=app_user \
-e POSTGRES_PASSWORD=app_password \
-e POSTGRES_DB=app_db \
-p 5432:5432 \
-v app-postgres-data:/var/lib/postgresql/data \
-d postgres:16Параметри команди:
--name app-postgres — ім’я контейнера;
-e POSTGRES_USER=app_user — користувач, який буде створений під час першої ініціалізації;
-e POSTGRES_PASSWORD=app_password — пароль цього користувача;
-e POSTGRES_DB=app_db — база даних, яка буде створена автоматично;
-p 5432:5432 — доступ до PostgreSQL через порт хоста 5432;
-v app-postgres-data:/var/lib/postgresql/data — збереження даних у named volume;
-d — запуск у фоновому режимі;
postgres:16 — офіційний образ PostgreSQL версії 16.
Перевірити стан контейнера можна так:
docker psУ стовпці STATUS контейнер має бути в стані Up.
Переглянути журнали PostgreSQL:
docker logs app-postgresЩоб стежити за новими повідомленнями в реальному часі:
docker logs -f app-postgresУ контейнері вже доступна утиліта psql. Підключитися до бази можна через docker exec:
docker exec -it app-postgres \
psql -U app_user -d app_dbПісля підключення можна виконати SQL-запит:
SELECT version();Або перевірити поточну базу та користувача:
SELECT current_database(), current_user;Щоб вийти з psql, виконайте:
\qПідключення з комп’ютера через локальний клієнт psql має такі параметри:
Host: localhost
Port: 5432
Database: app_db
User: app_user
Password: app_passwordРядок підключення має вигляд:
postgresql://app_user:app_password@localhost:5432/app_dbЯкщо порт 5432 на хості вже зайнятий, PostgreSQL можна опублікувати на іншому порту:
docker run --name app-postgres \
-e POSTGRES_USER=app_user \
-e POSTGRES_PASSWORD=app_password \
-e POSTGRES_DB=app_db \
-p 55432:5432 \
-v app-postgres-data:/var/lib/postgresql/data \
-d postgres:16У цьому випадку:
усередині контейнера PostgreSQL як і раніше слухає порт 5432;
з хоста підключатися потрібно через порт 55432;
рядок підключення буде таким:
postgresql://app_user:app_password@localhost:55432/app_dbЗупинити контейнер:
docker stop app-postgresЗапустити вже створений контейнер знову:
docker start app-postgresПерезапустити контейнер:
docker restart app-postgresВидалити контейнер:
docker rm app-postgresВидалення контейнера не видаляє named volume app-postgres-data, тому дані залишаються.
Подивитися доступні volumes:
docker volume lsВидалити volume:
docker volume rm app-postgres-dataВидалення volume безповоротно видаляє всі дані PostgreSQL, які в ньому зберігаються.
Для проєкту з кількома сервісами зручніше використовувати Docker Compose. Створіть файл compose.yaml:
services:
db:
image: postgres:16
container_name: app-postgres
restart: unless-stopped
environment:
POSTGRES_USER: app_user
POSTGRES_PASSWORD: app_password
POSTGRES_DB: app_db
ports:
- "5432:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:Запустіть сервіс:
docker compose up -dПеревірте його стан:
docker compose psПерегляньте журнали:
docker compose logs -f dbПідключіться до бази:
docker compose exec db psql -U app_user -d app_dbЗупиніть сервіси:
docker compose downКоманда docker compose down видаляє контейнери, але не видаляє volumes. Дані залишаться в postgres-data.
Щоб видалити також volumes, потрібно явно вказати параметр -v:
docker compose down -v.envПаролі не варто дублювати безпосередньо у файлі Compose. Зручно винести змінні в .env:
POSTGRES_USER=app_user
POSTGRES_PASSWORD=app_password
POSTGRES_DB=app_db
POSTGRES_PORT=5432Оновлений compose.yaml:
services:
db:
image: postgres:16
container_name: app-postgres
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
ports:
- "${POSTGRES_PORT}:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:Docker Compose автоматично читає .env у поточному каталозі та підставляє значення у файл Compose.
Файл .env із реальними паролями не слід додавати до Git. Його зазвичай додають до .gitignore:
.envДля командної роботи можна створити .env.example без реальних секретів:
POSTGRES_USER=app_user
POSTGRES_PASSWORD=change_me
POSTGRES_DB=app_db
POSTGRES_PORT=5432Офіційний образ PostgreSQL виконує SQL- та shell-скрипти з каталогу /docker-entrypoint-initdb.d/ під час першої ініціалізації порожнього data-каталогу.
Створіть структуру:
.
├── compose.yaml
└── initdb
└── 001-schema.sqlФайл initdb/001-schema.sql:
CREATE TABLE IF NOT EXISTS users (
id BIGSERIAL PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
INSERT INTO users (email, name)
VALUES ('olena@example.com', 'Olena')
ON CONFLICT (email) DO NOTHING;Додайте каталог до сервісу:
services:
db:
image: postgres:16
container_name: app-postgres
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
ports:
- "${POSTGRES_PORT}:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
- ./initdb:/docker-entrypoint-initdb.d:ro
volumes:
postgres-data:Після запуску перевірте таблиці:
docker compose exec db \
psql -U app_user -d app_db \
-c "SELECT id, email, name FROM users;"Скрипти з initdb не запускаються щоразу при старті контейнера. Вони виконуються лише тоді, коли каталог даних порожній.
Якщо потрібно повторити ініціалізацію в навчальному або локальному середовищі, видаліть volume та створіть його знову:
docker compose down -v
docker compose up -dЯкщо застосунок також працює в Docker Compose, йому не потрібно підключатися до бази через localhost.
Усередині контейнера:
localhost вказує на поточний контейнер;
для підключення до PostgreSQL потрібно використовувати ім’я сервісу db;
портом буде внутрішній порт PostgreSQL 5432, а не порт, опублікований на хості.
Приклад compose.yaml із застосунком:
services:
db:
image: postgres:16
environment:
POSTGRES_USER: app_user
POSTGRES_PASSWORD: app_password
POSTGRES_DB: app_db
volumes:
- postgres-data:/var/lib/postgresql/data
app:
image: my-app:latest
environment:
DATABASE_URL: postgresql://app_user:app_password@db:5432/app_db
depends_on:
- db
volumes:
postgres-data:У цьому прикладі db — це DNS-ім’я сервісу в мережі Compose.
Якщо застосунок запущено безпосередньо на хості, використовується localhost:
postgresql://app_user:app_password@localhost:5432/app_dbЯкщо застосунок працює в іншому контейнері, використовується ім’я сервісу:
postgresql://app_user:app_password@db:5432/app_dbdepends_on визначає порядок запуску контейнерів, але не гарантує, що PostgreSQL уже готовий приймати підключення. Для цього можна додати healthcheck:
services:
db:
image: postgres:16
environment:
POSTGRES_USER: app_user
POSTGRES_PASSWORD: app_password
POSTGRES_DB: app_db
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app_user -d app_db"]
interval: 5s
timeout: 5s
retries: 10
app:
image: my-app:latest
environment:
DATABASE_URL: postgresql://app_user:app_password@db:5432/app_db
depends_on:
db:
condition: service_healthy
volumes:
postgres-data:Утиліта pg_isready перевіряє, чи готовий сервер PostgreSQL приймати підключення.
Перевірити, чи контейнер запущений:
docker compose psПеревірити журнали:
docker compose logs dbПеревірити стан PostgreSQL командою pg_isready:
docker compose exec db \
pg_isready -U app_user -d app_dbУспішна перевірка має повідомити, що сервер приймає підключення.
Переглянути змінні оточення контейнера:
docker inspect app-postgresНе публікуйте результат цієї команди у відкритому доступі, оскільки він може містити конфіденційні значення.
Перевірити змонтовані сховища:
docker inspect app-postgres \
--format '{{json .Mounts}}'Для резервної копії окремої бази використовуйте pg_dump усередині контейнера:
docker compose exec -T db \
pg_dump -U app_user -d app_db > backup.sqlФайл backup.sql буде створений на хості.
Відновити його можна так:
cat backup.sql | docker compose exec -T db \
psql -U app_user -d app_dbПараметр -T вимикає псевдотермінал. Це важливо для коректної передачі SQL-файлу через стандартний ввід.
Резервна копія не замінює volume:
volume потрібен для щоденної роботи контейнера;
backup потрібен для відновлення після помилок, пошкодження або втрати даних.
Для локального проєкту послідовність команд може бути такою:
# Запуск PostgreSQL у фоновому режимі
docker compose up -d
# Перевірка стану сервісу
docker compose ps
# Перегляд журналів
docker compose logs -f db
# Підключення до бази
docker compose exec db psql -U app_user -d app_db
# Зупинка контейнерів без видалення даних
docker compose downПовторний запуск:
docker compose up -dДані буде завантажено з volume, тому створені таблиці та записи збережуться.
localhost між контейнерамиНеправильно:
postgresql://app_user:app_password@localhost:5432/app_dbЯкщо застосунок працює в іншому контейнері, localhost посилається на контейнер застосунку. Використовуйте ім’я сервісу Compose:
postgresql://app_user:app_password@db:5432/app_dbКоманда:
docker compose down -vвидаляє не лише контейнери, а й volumes. Для звичайної зупинки використовуйте:
docker compose downPOSTGRES_DB після першого запускуЗмінні POSTGRES_USER, POSTGRES_PASSWORD і POSTGRES_DB застосовуються під час першої ініціалізації порожнього volume.
Якщо volume вже містить базу, зміна цих змінних не перейменує існуючу базу й не змінить пароль автоматично.
Для локального середовища можна переініціалізувати базу:
docker compose down -v
docker compose up -dУ робочому середовищі дані потрібно змінювати контрольовано через SQL, міграції або процедури адміністрування.
Контейнер PostgreSQL може бути запущений, але ще не готовий приймати з’єднання. Використовуйте healthcheck, а сам застосунок має коректно обробляти тимчасову недоступність бази.
Якщо PostgreSQL запущено без volume, дані зберігаються лише у файловій системі контейнера. Після видалення контейнера вони можуть бути втрачені.
latestТег latest може вказувати на різні версії образу в різний час. Для передбачуваного середовища краще вказувати конкретну основну версію, наприклад:
image: postgres:16Оновлення версії PostgreSQL потрібно виконувати окремо та перевіряти сумісність даних і застосунку.
PostgreSQL можна запустити в Docker через docker run або Docker Compose.
Для збереження даних потрібно підключити volume до /var/lib/postgresql/data.
З хоста база доступна через localhost і опублікований порт.
З іншого контейнера підключення виконується через ім’я сервісу, наприклад db.
SQL-скрипти з /docker-entrypoint-initdb.d/ виконуються лише під час першої ініціалізації порожнього volume.
docker compose down зберігає дані, а docker compose down -v видаляє volumes.
Для надійного запуску варто використовувати healthcheck і регулярні резервні копії.