Docker: образы и контейнеры

Image (образ) — неизменяемый шаблон файловой системы; container (контейнер) — запущенный изолированный процесс на основе этого образа.

Зачем нужно

Понимание разницы между образом и контейнером — основа работы с Docker. Образ строится один раз и хранится в registry; из одного образа можно запустить сколько угодно контейнеров. Слоевая система образов позволяет переиспользовать общие части и ускоряет сборку.

Где используется

  • Сборка образа в CI и публикация в Docker Hub / GitHub Container Registry
  • Запуск нескольких контейнеров из одного образа (horizontal scaling)
  • Хранение версий образов по тегам для возможности rollback

Основной контент

Слоевая архитектура образов

FROM node:20-alpine     ← базовый слой (скачивается из registry)
WORKDIR /app            ← добавляет слой
COPY package*.json() ./   ← добавляет слой (кэшируется если не изменился)
RUN npm ci              ← добавляет слой (самый долгий, кэшируется!)
COPY . .                ← добавляет слой
CMD ["node", "index.js"] ← мета-данные, не добавляет слой

Каждый слой кэшируется. Если package.json не изменился — npm ci не перезапускается.

Многоэтапная сборка (multi-stage build)

# Этап 1: сборка
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json() ./
RUN npm ci
COPY . .
RUN npm run build      # компиляция TypeScript

# Этап 2: минимальный production-образ
FROM node:20-alpine AS production
WORKDIR /app
COPY package*.json() ./
RUN npm ci --omit=dev  # только production зависимости
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/index.js"]
docker build --target production -t myapp:prod .

Управление образами

# Список образов с деталями
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"

# Тегирование
docker tag myapp:latest myuser/myapp:1.2.3
docker tag myapp:latest myuser/myapp:latest

# Публикация в Docker Hub
docker login
docker push myuser/myapp:1.2.3
docker push myuser/myapp:latest

# Удаление неиспользуемых образов
docker image prune -a

Управление контейнерами

# Запуск с именем и политикой перезапуска
docker run -d \
  --name api \
  --restart unless-stopped \
  -p 3000:3000 \
  myapp:latest

# Просмотр ресурсов
docker stats

# Копирование файлов из контейнера
docker cp api:/app/logs/app.log ./app.log

# Inspect: все метаданные контейнера
docker inspect api

.dockerignore

node_modules
.git
.env
*.log
dist
.DS_Store

Частые ошибки

  • Не использовать multi-stage builds: production-образ содержит devDependencies и исходники TypeScript (раздувает размер в 5-10 раз)
  • Копировать всё приложение до npm ci: теряется кэш слоёв — npm ci запускается при любом изменении кода
  • Запускать контейнер от root-пользователя в продакшне — риск безопасности

Связанные темы

Ресурсы