Docker для Node.js с PostgreSQL

Важно: все команды выполняйте из корня проекта, если иначе не указано.
Зачем использовать Docker
Docker позволяет упаковать приложение и все зависимости в образ, который будет одинаково работать на локальной машине, в CI или в облаке. Контейнеры минимизируют проблему “у меня работает на моей машине” и стандартизируют окружения.
Краткое определение: контейнер — это изолированный рантайм для вашего приложения и его зависимостей, упакованный в образ.
Что включает пример
В этом руководстве вы найдёте:
- Пример простого Node.js REST API с тремя маршрутами.
- Конфигурацию подключения к PostgreSQL через knex/pg.
- Скрипты миграции и наполнения (migrate.js, seed.js).
- Dockerfile для приложения и docker-compose.yml для запуска приложения + базы в одной сети.
- Команды для сборки, запуска, тестирования и публикации образа.
Требования
- Установленный Docker и Docker Compose (или Docker Desktop).
- Node.js и npm для локальной разработки (для тестов вне контейнера).
- Аккаунт на Docker Hub для публикации образов (опционально).
Примечание: для Windows рекомендуется включить WSL2 и использовать Docker Desktop для стабильной работы.

Создаём Node.js REST API
- Инициализируйте проект npm и установите зависимости:
npm install morgan pg knex- Пояснение пакетов:
- pg — драйвер для PostgreSQL.
- knex — query builder для удобной работы с SQL.
- morgan — логирование HTTP-запросов для отладки.
- Создайте файл index.js и вставьте следующий код:
const express = require("express")
const morgan = require("morgan")
const app = express()
const db = require('./db')
const PORT = process.env.PORT || 5000
app.use(morgan('dev'))
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.get('/', (req, res) => res.send('Hello World!' ))
app.get('/users', async (req, res) => {
const users = await db.select().from('users')
res.json(users)
})
app.post('/users', async (req, res) => {
const user = await db('users').insert({ name: req.body.name }).returning('*')
res.json(user)
})
app.listen(PORT, () => console.log(`Server up at PORT:${PORT}`))Важно: код выше рассчитан на работу с таблицей users в схеме public PostgreSQL.
Настройка подключения к базе
Создайте файл db.js в корне проекта со следующим содержимым:
const knex = require('knex')
module.exports = knex({
client: 'postgres',
connection: {
host: 'db',
user: 'testUser',
password: 'mypassword123',
database: 'testUser',
},
})Здесь host: ‘db’ соответствует имени сервиса базы в docker-compose.yml.
Совет по безопасности: не храните пароли в коде в продакшне — используйте переменные окружения или Docker secrets.
Скрипты миграции и наполнения
Создайте папку scripts и два файла: migrate.js и seed.js.
migrate.js:
const db = require('../db');
(async () => {
try {
await db.schema.dropTableIfExists('users')
await db.schema.withSchema('public').createTable('users', (table) => {
table.increments()
table.string('name')
})
console.log('Created users table!')
process.exit(0)
} catch (err) {
console.log(err)
process.exit(1)
}
})()seed.js:
const db = require('../db');
(async () => {
try {
await db('users').insert({ name: 'Test User1' })
await db('users').insert({ name: 'Test User2' })
console.log('Added dummy users!')
process.exit(0)
} catch (err) {
console.log(err)
process.exit(1)
}
})()Добавьте в package.json команды:
"scripts": {
"start": "node index.js",
"migrate": "node scripts/migrate.js",
"seed": "node scripts/seed.js"
},Пояснение: npm run migrate и npm run seed выполнятся внутри контейнера или локально для инициализации данных.
Dockerfile
Создайте Dockerfile в корне проекта с таким содержимым:
FROM node:16.3.0-alpine3.13
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8000
CMD [ "node", "index.js" ]Разбор инструкций:
- FROM — базовый образ Node.js (alpine — лёгкий).
- WORKDIR — рабочая директория внутри контейнера.
- COPY package*.json ./ — копирует package.json + package-lock.json (если есть) для кеширования npm install.
- RUN npm install — устанавливает зависимости при сборке образа.
- COPY . . — копирует исходники.
- EXPOSE — декларативно указывает порт (в этом Dockerfile указан 8000, а в приложении слушается 5000; проверьте согласованность или используйте env PORT).
- CMD — команда запуска приложения.
Важно: приведённый Dockerfile объявляет EXPOSE 8000, тогда как приложение по умолчанию использует 5000. Согласуйте PORT через переменную окружения, чтобы избежать несоответствий.
docker-compose.yml
Создайте docker-compose.yml в корне проекта:
version: '3.9'
services:
server:
build: .
ports:
- '5000:5000'
depends_on:
- db
db:
image: 'postgres'
ports:
- '4321:5432'
environment:
POSTGRES_PASSWORD: 'mypassword123'
POSTGRES_USER: 'testUser'
volumes:
- data:/var/lib/postgresql/data
volumes:
data:Разъяснение:
- server собирается из локального Dockerfile.
- db использует официальный образ postgres.
- ports у db пробрасывает порт 5432 контейнера на 4321 хоста (полезно для локального доступа к БД).
- volumes сохраняет данные PostgreSQL между перезапусками.
Совет: для разработки указывайте переменные окружения через .env файл и docker-compose поддерживает ссылку на него.
Сборка и запуск
Сборка и запуск в фоне:
docker-compose up -dВы увидите вывод создания контейнеров и их запуск.

Тестирование API
Выполните миграцию внутри запущенного контейнера сервера (имя контейнера может отличаться):
docker exec docker_node-server-1 npm run migrateВы должны увидеть логи создания таблицы.

Альтернативный способ: напрямую запустить migrate как одноразовый сервис в docker-compose:
migrate:
build: .
command: npm run migrate
depends_on:
- dbЭто удобно для CI.
Публикация образа на Docker Hub
- Зарегистрируйтесь на Docker Hub и создайте репозиторий.
- Авторизуйтесь в терминале:
docker login- Пометьте образ (tag) в формате
/ :
docker tag / - Запушьте образ:
docker push / Примечание: используйте CI/CD для автоматической сборки и публикации образов из ветки main.
Практические рекомендации и варианты
Когда Docker не лучший выбор
- Очень мелкие скрипты, запускающиеся однократно на локальной машине — добавление контейнера может быть избыточно.
- Жёсткие требования к аппаратным ресурсам или драйверам хоста (например, GPU на специфическом ПО) — лучше использовать нативные установки или специальные контейнерные технологии.
Альтернативы и экосистема
- Podman — бесcистемный аналог Docker, может работать rootless.
- Kubernetes — если нужно оркестрирование нескольких сервисов в продакшне.
- Docker Desktop / Rancher Desktop — удобные GUI-решения для локальной разработки.
Ментальные модели
- Образ = снимок файловой системы + метаданные.
- Контейнер = запущенный экземпляр образа.
- Compose = набор сервисов, настроенных как единый стек.
Порядок действий для проверки (SOP)
- git pull && npm install (локально).
- docker-compose build.
- docker-compose up -d.
- docker exec
npm run migrate. - docker exec
npm run seed. - Тестировать endpoints через curl/Postman.
Проверочный список ролей
Разработчик:
- Код валидируется eslint/jest.
- Добавлены миграции и seed.
DevOps/Инженер релиза:
- Есть Dockerfile и docker-compose.yml.
- CI собирает образ и пушит на Docker Registry.
QA:
- Тестовые сценарии на доступность endpoint, корректность статусов и данных.
Тестовые сценарии и команды
Проверить GET /users:
curl -s http://localhost:5000/users | jqДобавить пользователя:
curl -X POST http://localhost:5000/users -H 'Content-Type: application/json' -d '{"name":"Новый пользователь"}'Критерии приёмки
- Сервер отвечает на / со статусом 200 и текстом Hello World!.
- GET /users возвращает массив пользователей после миграции и seed.
- POST /users добавляет запись и возвращает вставленного пользователя.
Безопасность и конфиденциальность
- Не храните учётные данные в публичных репозиториях.
- Для секретов в продакшне используйте Docker secrets, HashiCorp Vault или переменные окружения в CI.
- Для персональных данных учитывайте требования локального законодательства и GDPR: храните минимально необходимые данные, документируйте основания обработки и срок хранения.
Отладка и типичные проблемы
Проблема: контейнер сервера не может подключиться к БД.
- Проверьте имя хоста в db.js — должно совпадать с именем сервиса в docker-compose (db).
- Убедитесь, что db контейнер поднят: docker-compose ps.
Проблема: порт не доступен.
- Проверяйте соответствие EXPOSE в Dockerfile и проброса портов в docker-compose.
Проблема: npm install долго выполняется при сборке.
- Используйте COPY package*.json + RUN npm install до копирования всего кода, чтобы кешировать слои.
Локальные нюансы и рекомендации для России
- Для доступа к Docker Hub может понадобиться настройка прокси или подключение через альтернативные зеркала в корпоративных сетях.
- Для приватных реестров используйте GitLab Container Registry, AWS ECR или GitHub Packages, если политика компании ограничивает публичный Docker Hub.
Заключение
Docker делает развёртывание и воспроизводимость окружений простыми и предсказуемыми. В этом руководстве показан базовый путь упаковки Node.js приложения с PostgreSQL и лучшие практики для разработки, тестирования и деплоя.
Ключевые шаги:
- Подготовьте приложение и миграции.
- Напишите Dockerfile и docker-compose.yml.
- Соберите, запустите, мигрируйте и тестируйте.
- Публикуйте образы в реестр в рамках CI/CD.
Важно: проверяйте настройки портов и секретов перед деплоем в продакшен.
Подготовьте следующий шаг: добавить Dockerfile для продакшен-сборки с multi-stage, добавить healthchecks и readiness probes, а при масштабировании — перенести на Kubernetes.
Похожие материалы
Несколько аккаунтов Skype: Multi Skype Launcher
Журнал для работы: повысить продуктивность
Персональные звуки уведомлений на Android
Скачивание шоу Hulu для офлайн‑просмотра
Microsoft Start: персонализированная новостная лента