Docker для Node.js
Практическое руководство по контейнеризации Node.js-приложения: от написания Dockerfile до запуска с docker-compose и публикации образа.
Зачем нужно
Docker позволяет упаковать Node.js-приложение вместе с нужной версией Node, переменными окружения и зависимостями в один образ. Разработчики и серверы запускают идентичную среду — исчезает проблема «у меня Node 18, на сервере Node 20». Образ легко версионируется и откатывается.
Где используется
- Express / Fastify API: запуск в контейнере на VPS
- Next.js: standalone-сборка внутри Docker
- Node.js + PostgreSQL: связка через docker-compose для локальной разработки
- Воспроизводимая среда для CI — GitHub Actions запускает тесты в Docker
Основной контент
Production Dockerfile для Node.js
# syntax=docker/dockerfile:1
FROM node:20-alpine AS base
WORKDIR /app
# Зависимости отдельным слоем — кэшируется!
FROM base AS deps
COPY package*.json() ./
RUN npm ci --omit=dev
# Сборка (для TypeScript проектов)
FROM base AS builder
COPY package*.json() ./
RUN npm ci
COPY . .
RUN npm run build # tsc → dist/
# Финальный минимальный образ
FROM base AS runner
ENV NODE_ENV=production
RUN addgroup -S nodejs && adduser -S nodeuser -G nodejs
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY package*.json() ./
USER nodeuser
EXPOSE 3000
CMD ["node", "dist/index.js"]
.dockerignore
node_modules
.git
.env
.env.*
dist
*.log
coverage
.DS_Store
README.md
docker-compose для разработки
# docker-compose.yml
services:
api:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules
environment:
NODE_ENV: development
DATABASE_URL: postgres://user:pass@db:5432/devdb
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: devdb
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 5s
retries: 5
volumes:
pgdata:
Команды для работы
# Сборка образа
docker build -t myapp:latest .
# Запуск всего стека
docker compose up -d
# Логи
docker compose logs -f api
# Перезапуск только одного сервиса
docker compose restart api
# Пересборка после изменений в Dockerfile
docker compose up --build
# Очистка
docker compose down -v # -v удаляет volumes
Обработка сигналов (graceful shutdown)
// server.js — важно для Docker
process.on('SIGTERM', () => {
console.log('SIGTERM received, shutting down gracefully');
server.close(() => {
process.exit(0);
});
});
Частые ошибки
- Не указан
.dockerignore:node_modulesхоста копируется внутрь образа и перетираетnpm ci COPY . .доRUN npm ci— любое изменение кода сбрасывает кэш зависимостей- Приложение запускается как PID 1 без обработки сигналов — контейнер не завершается корректно (используй
CMD ["node", "..."], неnpm start) - Версия Node не закреплена:
node:alpine— движущийся тег, может сломать сборку
Связанные темы
- _MOC DevOps
- Что такое Docker
- Docker -- образы и контейнеры
- Docker -- для разработки vs для продакшна
- Docker Compose