← Назад к вопросам

Сталкивался ли с Docker

1.6 Junior🔥 121 комментариев
#DevOps и инфраструктура

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Опыт работы с Docker

Да, я активно использую Docker в своей работе. Это критически важный инструмент для современного backend-разработчика. Расскажу как я его применяю.

Основные концепции

Docker — это контейнеризация приложений. Я упаковываю приложение вместе со всеми зависимостями в образ, который гарантированно работает везде: на локальной машине, в CI/CD, на сервере.

# Основные компоненты Docker

# 1. Dockerfile — рецепт как собрать образ
# 2. Image — готовый образ (бинарник)
# 3. Container — запущенный образ (процесс)
# 4. Registry — хранилище образов (Docker Hub, GitHub Registry)

Dockerfile для Node.js приложения

# Используем официальный образ Node
FROM node:20-alpine

# Устанавливаем рабочую директорию
WORKDIR /app

# Копируем package файлы
COPY package*.json ./

# Устанавливаем зависимости
RUN npm ci --only=production

# Копируем исходный код
COPY . .

# Выстраиваем приложение (если нужно)
RUN npm run build

# Открываем порт
EXPOSE 3000

# Запускаем приложение
CMD ["node", "dist/server.js"]

Почему alpine?

  • Размер: 40MB против 150MB для ubuntu
  • Безопасность: минимум зависимостей
  • Скорость: быстрее скачивается и загружается

Docker Compose для локальной разработки

# docker-compose.yml
version: '3.9'

services:
  # Node приложение
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: development
      DATABASE_URL: postgresql://user:pass@postgres:5432/db
    volumes:
      - .:/app
      - /app/node_modules
    depends_on:
      - postgres
      - redis
    command: npm run dev

  # PostgreSQL
  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: db
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  # Redis для кэша
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  postgres_data:

Команды которые я использую:

# Запустить все сервисы
docker compose up

# Запустить в background
docker compose up -d

# Остановить
docker compose down

# Удалить volumes (очистить БД)
docker compose down -v

# Посмотреть логи
docker compose logs -f app

# Запустить команду в контейнере
docker compose exec app npm test

Multi-stage build для production

Этот подход уменьшает размер финального образа.

# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: Production
FROM node:20-alpine
WORKDIR /app

# Копируем только prod зависимости
COPY package*.json ./
RUN npm ci --only=production

# Копируем собранное приложение из builder
COPY --from=builder /app/dist ./dist

EXPOSE 3000
CMD ["node", "dist/server.js"]

Результат: образ в 2-3 раза меньше т.к. не содержит dev-зависимостей и исходный код.

Оптимизация Dockerfile

# Плохо: все в одном слое, кэш не используется
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build

# Хорошо: слои оптимизированы для кэша
FROM node:20-alpine
WORKDIR /app

# Зависимости меняются редко
COPY package*.json ./
RUN npm ci --only=production

# Исходный код меняется часто
COPY . .
RUN npm run build
CMD ["node", "dist/server.js"]

Почему это важно? Docker использует слои. Если я меняю исходный код, переиспользуются слои с зависимостями. Если я меняю зависимости, пересчитываются только нужные слои.

Health checks

FROM node:20-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .

# Health check — Docker проверит жив ли контейнер
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
  CMD node -e "require('http').get('http://localhost:3000/health', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})"

EXPOSE 3000
CMD ["node", "dist/server.js"]
// server.ts — добавляю health check endpoint
app.get('/health', (req, res) => {
  res.json({ status: 'ok', timestamp: new Date() });
});

Примеры команд

# Собрать образ
docker build -t my-app:1.0 .

# Запустить контейнер
docker run -d -p 3000:3000 --name app my-app:1.0

# Посмотреть логи
docker logs -f app

# Зайти в контейнер
docker exec -it app /bin/sh

# Остановить
docker stop app

# Удалить
docker rm app

# Залить на Docker Hub
docker tag my-app:1.0 myusername/my-app:1.0
docker push myusername/my-app:1.0

Лучшие практики

  1. Используй alpine образы — меньше размер, безопаснее
  2. Pinned versions — не используй latest в production
  3. Multi-stage builds — уменьшай размер образа
  4. WORKDIR первым — помогает документации
  5. Не запускай от root — создай пользователя
# Правильно
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001
USER nodejs
CMD ["node", "dist/server.js"]
  1. Минимизируй слои — используй && для объединения команд
# Плохо
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*

# Хорошо
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
  1. Используй .dockerignore — исключай ненужные файлы
node_modules
npm-debug.log
.git
.gitignore
README.md
.env

Integration с CI/CD

# GitHub Actions пример
name: Build and Push Docker Image

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Build image
        run: docker build -t my-app:${{ github.sha }} .
      
      - name: Run tests in Docker
        run: docker run my-app:${{ github.sha }} npm test
      
      - name: Login to registry
        run: echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
      
      - name: Push image
        run: |
          docker tag my-app:${{ github.sha }} myusername/my-app:latest
          docker push myusername/my-app:latest

Networking в Docker Compose

services:
  app:
    environment:
      # Обращаюсь к postgres по имени сервиса
      DATABASE_URL: postgresql://user:pass@postgres:5432/db
      # Redis по имени
      REDIS_URL: redis://redis:6379

Docker автоматически создаёт сеть и разрешает обращение по имени сервиса.

Debugging в контейнере

# Зайти в shell контейнера
docker compose exec app /bin/sh

# Или с bash
docker compose exec app bash

# Запустить команду
docker compose exec app npm test
docker compose exec app node -e "console.log('test')"

# Посмотреть переменные окружения
docker compose exec app env

Мой workflow

  1. Разработка: docker compose up для запуска зависимостей
  2. Тестирование: docker compose exec app npm test
  3. Сборка: docker build на CI
  4. Push: на Docker Hub или GitHub Registry
  5. Deployment: docker pull и docker run на сервере

Дocker позволяет гарантировать что приложение работает одинаково везде. Это экономит время на debug production issues и делает разработку предсказуемой.