Пошук уроків, статей та іншого контенту
Запустите PostgreSQL у контейнері, підключите його до застосунку та збережете дані через volume.
У цьому уроці ми:
запустимо PostgreSQL у Docker-контейнері;
збережемо дані в іменованому volume;
підключимо до бази даних застосунок на Node.js;
налаштуємо спільну Docker-мережу через Docker Compose;
перевіримо, що дані не зникають після перезапуску контейнера.
Для прикладів потрібні встановлені Docker і Docker Compose.
docker runPostgreSQL можна запустити однією командою:
docker run -d \
--name lessons-postgres \
-e POSTGRES_DB=app_db \
-e POSTGRES_USER=app_user \
-e POSTGRES_PASSWORD=secret_password \
-p 5432:5432 \
-v postgres_data:/var/lib/postgresql/data \
postgres:16Параметри команди:
-d — запуск у фоновому режимі;
--name lessons-postgres — ім’я контейнера;
POSTGRES_DB — назва бази даних, яку буде створено під час першого запуску;
POSTGRES_USER — користувач бази даних;
POSTGRES_PASSWORD — пароль користувача;
-p 5432:5432 — доступ до PostgreSQL через порт хоста;
-v postgres_data:/var/lib/postgresql/data — підключення volume до каталогу з даними PostgreSQL;
postgres:16 — образ PostgreSQL версії 16.
Перевірити стан контейнера можна командою:
docker psПідключитися до PostgreSQL всередині контейнера:
docker exec -it lessons-postgres \
psql -U app_user -d app_dbКоманда docker exec запускає psql усередині вже запущеного контейнера.
Вийти з psql можна командою:
\qКонтейнер має власну файлову систему. Якщо видалити контейнер без volume, дані, записані лише всередині контейнера, будуть втрачені.
У PostgreSQL дані зберігаються в каталозі:
/var/lib/postgresql/dataПід час запуску ми підключили іменований volume:
-v postgres_data:/var/lib/postgresql/dataТепер Docker зберігає дані volume окремо від контейнера.
Можна видалити контейнер:
docker rm -f lessons-postgresА потім створити його знову з тим самим volume:
docker run -d \
--name lessons-postgres \
-e POSTGRES_DB=app_db \
-e POSTGRES_USER=app_user \
-e POSTGRES_PASSWORD=secret_password \
-p 5432:5432 \
-v postgres_data:/var/lib/postgresql/data \
postgres:16База даних і записи в ній залишаться.
Переглянути список volume:
docker volume lsВидалити volume можна окремо:
docker volume rm postgres_dataЦя команда видаляє всі дані PostgreSQL, які зберігаються у volume.
Для застосунку з кількома сервісами зручніше використовувати Docker Compose. Створимо такий проєкт:
postgres-docker/
├── compose.yaml
├── app/
│ ├── Dockerfile
│ ├── package.json
│ └── index.jscompose.yamlservices:
db:
image: postgres:16
environment:
POSTGRES_DB: app_db
POSTGRES_USER: app_user
POSTGRES_PASSWORD: secret_password
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app_user -d app_db"]
interval: 5s
timeout: 5s
retries: 5
app:
build: ./app
environment:
DB_HOST: db
DB_PORT: 5432
DB_NAME: app_db
DB_USER: app_user
DB_PASSWORD: secret_password
depends_on:
db:
condition: service_healthy
volumes:
postgres_data:У цьому файлі описано два сервіси:
db — контейнер PostgreSQL;
app — контейнер Node.js-застосунку.
db і app автоматично опиняться в одній Docker-мережі. Тому застосунок може звертатися до бази за ім’ям сервісу:
dbУсередині Docker-мережі не потрібно використовувати localhost. Значення localhost у контейнері означає саме цей контейнер, а не інший сервіс.
Секція healthcheck перевіряє, чи готовий PostgreSQL приймати підключення. Умова:
condition: service_healthyзапускає app після того, як перевірка db завершиться успішно.
app/package.json{
"name": "postgres-docker-app",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"pg": "^8.13.1"
}
}Пакет pg — клієнт PostgreSQL для Node.js.
app/DockerfileFROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY index.js ./
CMD ["npm", "start"]Dockerfile:
використовує Node.js;
встановлює робочу директорію /app;
копіює опис залежностей;
встановлює пакет pg;
копіює код застосунку;
запускає застосунок.
app/index.jsimport pg from "pg";
const { Pool } = pg;
const pool = new Pool({
host: process.env.DB_HOST,
port: Number(process.env.DB_PORT),
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
});
async function main() {
const client = await pool.connect();
try {
// Створюємо таблицю, якщо її ще немає
await client.query(`
CREATE TABLE IF NOT EXISTS notes (
id SERIAL PRIMARY KEY,
text TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
`);
// Додаємо тестовий запис
await client.query(
"INSERT INTO notes (text) VALUES ($1)",
["Запис із Node.js-застосунку"]
);
const result = await client.query(
"SELECT id, text, created_at FROM notes ORDER BY id"
);
console.log("Записи в базі даних:");
console.table(result.rows);
} finally {
client.release();
await pool.end();
}
}
main().catch((error) => {
console.error("Помилка підключення до PostgreSQL:", error);
process.exitCode = 1;
});Застосунок отримує параметри підключення через змінні середовища:
DB_HOST=db;
DB_PORT=5432;
DB_NAME=app_db;
DB_USER=app_user;
DB_PASSWORD=secret_password.
Порт 5432 тут є внутрішнім портом PostgreSQL у Docker-мережі. Застосунок звертається до сервісу db, а не до порту хоста.
Перейдіть до каталогу проєкту:
cd postgres-dockerЗапустіть сервіси:
docker compose up --buildПараметр --build змушує Docker зібрати образ застосунку перед запуском.
У виведенні з’явиться таблиця із записами:
Записи в базі даних:
┌─────────┬────┬──────────────────────────────────────┬──────────────────────────┐
│ (index) │ id │ text │ created_at │
├─────────┼────┼──────────────────────────────────────┼──────────────────────────┤
│ 0 │ 1 │ 'Запис із Node.js-застосунку' │ 2026-09-02T10:00:00.000Z │
└─────────┴────┴──────────────────────────────────────┴──────────────────────────┘Застосунок виконається й завершить роботу, а контейнер PostgreSQL продовжить працювати.
Переглянути стан сервісів:
docker compose psПереглянути журнали PostgreSQL:
docker compose logs dbЗупинити сервіси:
docker compose downКоманда docker compose down видаляє контейнери, але не видаляє іменований volume postgres_data.
Запустити проєкт знову:
docker compose upПід час наступного запуску застосунок додасть ще один запис. Попередній запис залишиться в базі, оскільки дані зберігаються у volume.
Після запуску Compose можна підключитися до бази даних:
docker compose exec db psql -U app_user -d app_dbВиконати SQL-запит:
SELECT id, text, created_at
FROM notes
ORDER BY id;Щоб завершити сесію:
\qЯкщо потрібно повністю видалити контейнери разом із даними, використовуйте:
docker compose down -vПараметр -v видаляє volume, тому після наступного запуску PostgreSQL створить порожню базу даних заново.
Якщо Node.js-застосунок запускається не в контейнері, а безпосередньо на комп’ютері, він має підключатися до PostgreSQL через опублікований порт:
import pg from "pg";
const { Client } = pg;
const client = new Client({
host: "localhost",
port: 5432,
database: "app_db",
user: "app_user",
password: "secret_password",
});
await client.connect();
const result = await client.query("SELECT NOW()");
console.log(result.rows[0]);
await client.end();Тут використовується localhost, тому що застосунок працює на хості. Для застосунку в іншому контейнері потрібно використовувати ім’я сервісу db.
Коли і PostgreSQL, і застосунок працюють у Docker Compose, підключення виглядає так:
Node.js-контейнер
|
| host: db, port: 5432
v
PostgreSQL-контейнер
|
v
volume postgres_dataКоли застосунок працює на хості:
Node.js на комп’ютері
|
| host: localhost, port: 5432
v
PostgreSQL-контейнерlocalhost між контейнерамиНеправильно:
DB_HOST=localhostЯкщо застосунок працює в окремому контейнері, localhost вказує на контейнер застосунку.
Правильно:
DB_HOST=dbdb — це назва сервісу PostgreSQL у compose.yaml.
Якщо PostgreSQL запущено без volume, наприклад:
services:
db:
image: postgres:16дані не матимуть окремого постійного сховища. Для збереження даних потрібно додати volume:
volumes:
- postgres_data:/var/lib/postgresql/dataі оголосити його в кінці файлу:
volumes:
postgres_data:Запущений контейнер не завжди означає, що PostgreSQL уже готовий приймати підключення. Саме тому в Compose використовується healthcheck і залежність:
depends_on:
db:
condition: service_healthyКоманда:
docker compose down -vвидаляє не лише контейнери, а й дані PostgreSQL. Використовуйте її лише тоді, коли потрібно почати роботу з чистою базою.
У Compose запис:
ports:
- "5432:5432"означає:
порт хоста:порт контейнераПерший порт використовується для підключення з комп’ютера. Між контейнерами використовується внутрішній порт 5432 і ім’я сервісу db.
PostgreSQL можна запускати в контейнері з образом postgres.
Початкові параметри бази задаються через POSTGRES_DB, POSTGRES_USER і POSTGRES_PASSWORD.
Дані PostgreSQL потрібно зберігати у volume, підключеному до /var/lib/postgresql/data.
У Docker Compose сервіси звертаються один до одного за іменами, наприклад db.
Для підключення з контейнера використовується db:5432.
Для підключення з хоста використовується localhost:5432.
docker compose down зберігає volume, а docker compose down -v видаляє його разом із даними.
Перевірка готовності PostgreSQL допомагає не запускати застосунок раніше, ніж база почне приймати підключення.