Интеграция Docker
Docker позволяет упаковать приложение вместе со всеми зависимостями в образ, а запускать — в контейнере. Контейнер — это изолированный процесс, использующий ядро ОС хоста. В отличие от виртуальной машины, здесь не используется отдельное гостевое ядро, поэтому контейнеры запускаются быстро и занимают меньше ресурсов.
Но наше приложение не всегда будет состоять из одного контейнера. Как мы уже ранее упоминали, возможно появится необходимость подключения базы данных или прокси-сервера для корректного запуска вашего ПО. В этом случае используется Docker Compose — инструмент, который описывает мультиконтейнерное приложение в одном YAML‑файле (сервисы, сети, тома) и позволяет поднять всё одной командой docker compose up. Сейчас используется Compose v2 (встроен в Docker CLI как плагин docker compose).
В прошлой версии Docker Compose v3 (не спрашивайте почему 2 идет после 3 - честно не знаю) в качестве основной команды использовался
docker-compose, сейчас дефис уже не нужен.
Установка Docker
Формально есть несколько способов поставить Docker на каждую из платформ, здесь рассмотрим только самые классические и удобные.
Windows 10/11: Docker Desktop + WSL 2
- Скачайте и установите Docker Desktop for Windows. Во время установки выберите опцию с включением WSL 2 (Windows Subsystem For Linux). После установки включите опцию Use WSL 2 based engine в Settings → General.
- (При необходимости) Установите и обновите сам WSL 2 по инструкции Microsoft, затем в Docker Desktop включите интеграцию с выбранным дистрибутивом WSL (Settings → Resources → WSL Integration).
- Проверьте установку:
Сообщение Hello from Docker! означает, что всё работает.
docker --version docker compose version docker run hello-world
Если будете хранить исходники внутри файловой системы WSL 2 (например,
/home/<user>/projects/...) — это немного ускорит bind‑mount (процесс монтирования) при старте. У Docker Desktop есть официальные рекомендации по производительности WSL 2. ([Docker Documentation][6])
macOS: Docker Desktop for Mac
-
Скачайте Docker Desktop для macOS (отдельные сборки для Apple Silicon и Intel) и установите по инструкции. ([Docker Documentation][8])
-
Проверьте:
docker --version docker compose version docker run hello-worldСообщение Hello from Docker! подтверждает корректную установку.
Docker Desktop для macOS также включает Compose.
Linux: Скрипт get-docker.sh
Можно установить docker при помощи готового автоматического скрипта, который автоматически определит необходимые версии пакетов и зависимости исходя из вашей системы:
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.shПосле установки:
# Разрешим текущему пользователю работать с docker без sudo
sudo groupadd docker 2>/dev/null || true
sudo usermod -aG docker $USER
newgrp docker
# Проверка
docker --version
docker run hello-worldДобавление в группу docker фактически даёт root‑права к демону.
Root доступ на самом деле серьезная угроза для безопасности. В этой области достаточно часто находят CVE высокого уровня опасности, поэтому можете изучить альтернативный вариант — rootless mode. ([Docker Documentation][10]). Или рассмотреть альтернативный вариант - использовать Podman вместо docker.
Базовые команды Docker и Compose
В принципе для базового взаимодействия с Docker достаточно будет запомнить всего несколько команд, а потом их список уже можно будет расширять по мере того как вам потребуется какая-то дополнительная специфика.
- Сборка образа:
docker build -t myapp:dev .— собирает образ по Dockerfile. По умолчанию используется BuildKit/Buildx. - Запуск контейнера:
docker run --rm -p 8080:80 myapp:dev— запускает контейнер, пробрасывая порт. По этому порту потом можно обратиться к содержимому контейнера из основной хост системы. - Список контейнеров:
docker ps(только запущенные) илиdocker ps -a(все). - Логи/доступ внутрь:
docker logs <container>иdocker exec -it <container> sh— посмотреть вывод и попасть в shell конкретного контейнера.
Но как мы с вами уже и сказали, чаще всего наше взаимодействие будет е напрямую с docker, а с его плагином, который позволит объединить несколько контейнеров в единую сеть, чтобы они могли выступать в качестве компонентов / ресурсов нашей единой информационной системы.
При использовании Compose (v2) вы скорее всего будете использовать следующий набор основных команд:
- Поднять приложение:
docker compose up/ в фоне-d/ форс‑сборка--build. - Остановить и убрать всё созданное:
docker compose down. - Состояние/логи/выполнить команду:
docker compose ps,docker compose logs -f,docker compose exec.
Раньше в compose файлах еще использовался ключ
version, но после перехода на Compose v2 он был помечен как depreciated.
Также для объединения несколько файлов конфигураций можно использовать концепцию объединения (override), которая описана в документации Docker Compose. (Docker Documentation). Пример с её использованием мы рассмотрим чуть позже.
Dockerfile
Прежде чем мы что-то сможем запустить нам нужно написать инструкции каким образом наш проект в принципе должен быть запущен. Для этого используется Dockerfile — текстовый рецепт сборки образа. Строится послойно, выполняя инструкции сверху вниз. Файл должен начинаться с FROM (кроме глобальных ARG/директив парсера).
Минимальный набор инструкций, который вам необходимо узнать и познакомиться:
| Инструкция | Назначение / пример |
|---|---|
FROM <image>[:tag] |
Базовый образ. FROM node:24-alpine |
WORKDIR <path> |
Рабочий каталог для последующих команд. WORKDIR /app |
COPY <src> <dest> |
Копирование файлов в образ. COPY package*.json . |
ADD |
Как COPY, но с распаковкой архивов/URL; используйте COPY по умолчанию. |
RUN <cmd> |
Команда на этапе сборки. RUN npm ci |
ENV k v / ARG k=v |
Переменные окружения и аргументы сборки. |
EXPOSE <port> |
Документация порта (для людей/инструментов). |
CMD ["..."] |
Команда по умолчанию при запуске контейнера. |
ENTRYPOINT ["..."] |
Исполняемый процесс PID 1, сочетается с CMD. Чаще всего используется для запуска кастомных скриптов при старте контейнера |
HEALTHCHECK ... |
Проверка здоровья контейнера (опционально). |
LABEL |
Метаданные образа. |
Но кроме самого Dockerfile при сборке еще очень часто (почти всегда) необходим еще один файл - .dockerignore (похож на .gitignore - с ним вы уже должны быть знакомы). Он исключает папки/файлы из контекста сборки — ускоряет и снижает размер образа. Для Node‑проекта обычно игнорируют node_modules, dist, .git, *.log, .env* и т. п. (Docker Documentation)
Dockerfile для нашего проекта
В dev‑режиме Vite слушает порт 5173 и по умолчанию биндится на localhost (это вы могли заметить, когда после написания npm run dev вам необходимо перейти в браузере по маршруту http://localhost:51173, чтобы открыть и просмотреть базовую страницу). В контейнере кроме этого нам нужно будет явно включить прослушивание на всех интерфейсах (--host 0.0.0.0) и зафиксировать порт в самом Vite strictPort: true, чтобы при возникновении конфликта Vite не попробовал «перескочить» на соседние порты.
Примерная структура того что мы с вами добавим:
- …
Порт зафиксируем опцией strictPort, чтобы Vite не «перепрыгивал», если 5173 занят:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
host: true, // эквивалент "0.0.0.0"
port: 5173, // порт по умолчанию
strictPort: true // если занят — не переключаться автоматически
}
})Подробнее изучить опции server.host, –host и –strictPort можете в официальных руководствах Vite (Vite).
.dockerignore:
node_modules
dist
.git
.vscode
.DS_Store
*.log
.env*Dockerfile — собираем dev‑контейнер на Node 24 Alpine (в сборках вы практически всегда будете видеть Alpine, т.к. это один из самых легковесных Linux образов и размер финального контейнера с его использованием получится минимальный):
# Dockerfile
# ---- базовые зависимости
FROM node:24-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
# ---- dev: Vite + HMR
FROM node:24-alpine AS dev
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
# Копируем остальной код
COPY . .
# Открываем порт dev-сервера
EXPOSE 5173
# Запускаем Vite
CMD ["npm","run","dev"]services:
frontend:
build:
context: .
dockerfile: Dockerfile
target: dev
ports:
- "5173:5173" # хост:контейнер
volumes:
- .:/app # код хоста внутрь контейнера
- /app/node_modules # анонимный том, чтобы не затирать node_modules
environment:
- WATCHPACK_POLLING=trueЗапуск dev‑окружения:
docker compose -f docker-compose.dev.yml up --buildПри сборке проекта под Windows можете попробовать сохранить проект внутри WSL (например,
\\wsl.localhost\Ubuntu\home\...↔/home/...) — это ускоряет горячую перезагрузку и работу файловой системы с bind‑mount.
Собираем в prod
В продакшне нам нужен минимальный образ с уже собранными статическими файлами. Для этого используем multi‑stage build: отдельный этап «builder» собирает dist/, а финальный — на nginx:alpine — только раздаёт статику.
Dockerfile (дополненный):
# наше прошлое содержимое
# ...
# ---- build: собираем статическую дистрибуцию
FROM node:24-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# ---- prod: nginx + статика
FROM nginx:1.27-alpine AS prod
# Замена стандартного конфига NGINX
RUN rm -f /etc/nginx/conf.d/default.conf
COPY ./nginx/nginx.conf /etc/nginx/conf.d/app.conf
# Копируем результаты сборки
COPY --from=build /app/dist/ /usr/share/nginx/html/
EXPOSE 80nginx/nginx.conf — конфиг Nginx для SPA:
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# Кэш для статических файлов
location ~* \.(?:js|css|svg|png|jpg|jpeg|gif|ico|woff2?)$ {
expires 7d;
add_header Cache-Control "public, max-age=604800, immutable";
try_files $uri =404;
}
# SPA fallback: все неизвестные пути -> index.html
location / {
try_files $uri $uri/ /index.html;
}
}Также не забудем создать и свой docker-compose.yml файл для prod сборки:
services:
web:
build:
context: .
dockerfile: Dockerfile
target: prod
ports:
- "80:80"Запуск теперь соответственно будет проводиться командой docker compose -f docker-compose.yml up -d.
Как можно улучшить приведенную сверху конфигурацию? Ранее мы уже упоминали про механизм override (перезаписи), его можно применить тут, чтобы задать одну базовую конфигурацию и перезаписывать её в зависимости от активного режима (dev/prod). Создадим файл
compose.base.yml:services: web: build: context: . dockerfile: DockerfileА теперь создадим его вариации, которые будут запускаться в зависимости от активного режима.
# compose.dev.yml services: web: build: target: dev ports: - "5173:5173" volumes: - .:/app - /app/node_modules environment: - WATCHPACK_POLLING=trueИ prod вариант:
# compose.prod.yml services: web: build: target: prod ports: - "80:80"Теперь запуск тестовой сборки можно производить при помощи команды:
docker compose -f compose.base.yml -f compose.dev.yml up -d --build, а в prod режиме имя второго файла изменится наcompose.prod.yml. Основное преимущество такого подхода, что мы получаем возможность централизованно менять базовую конфигурацию в едином источнике правды, а не в каждом из файлов по отдельности.
Еще стоит посмотреть
- Что такое контейнеры и Docker: Docker Overview / Concepts. (Docker Documentation)
- Compose — обзор, спецификация, установка: Compose overview, file reference, install. (Docker Documentation)
- Установка: Docker Desktop (Windows/macOS), WSL 2 backend и best practices, convenience script для Linux. (Docker Documentation)
- Dockerfile reference, .dockerignore, multi‑stage builds: официальные референсы. (Docker Documentation)
- Vite server options (порт/хост): официальные опции
server.port,server.host. (vitejs) - Nginx: статика/
try_files, reverse‑proxy/proxy_pass. (NGINX Documentation)