Docker произвёл революцию в том, как мы собираем, доставляем и запускаем приложения. Глубокое понимание Docker — за пределами базовых команд — отделяет эффективные DevOps-процессы от болезненных сессий отладки. В этом руководстве рассматриваются ключевые команды Docker и лучшие практики для production с точки зрения старшего разработчика.
Почему важно мастерство Docker
Глубокие знания Docker позволяют:
- Эффективная разработка: быстрая итерация с контейнерами
- Единообразные окружения: один и тот же контейнер везде
- Оптимизация ресурсов: более компактные образы, более быстрые развёртывания
- Навыки отладки: быстрое выявление проблем
- Готовность к production: настройка безопасности и производительности
Основные команды
Жизненный цикл контейнера
# Запуск контейнера в фоновом режиме
docker run -d --name my-app nginx:latest
# Запуск с пробросом порта
docker run -d -p 8080:80 nginx:latest
# Запуск с пробросом нескольких портов
docker run -d -p 8080:80 -p 3000:3000 my-app
# Запуск с переменными окружения
docker run -d -e NODE_ENV=production -e API_KEY=secret my-app
# Запуск с ограничениями ресурсов
docker run -d --cpus=0.5 --memory=256m my-app
# Запуск в интерактивном режиме
docker run -it ubuntu:latest bash
# Запуск с удалением при выходе
docker run --rm -it python:3.11 python
Управление контейнерами
# Список запущенных контейнеров
docker ps
# Список всех контейнеров (включая остановленные)
docker ps -a
# Пользовательский формат вывода
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}"
# Остановить контейнер
docker stop my-app
# Запустить остановленный контейнер
docker start my-app
# Перезапустить контейнер
docker restart my-app
# Удалить контейнер
docker rm my-app
# Принудительно удалить запущенный контейнер
docker rm -f my-app
# Удалить все остановленные контейнеры
docker rm $(docker ps -aq -f status=exited)
Выполнение команд в контейнерах
# Выполнить команду в запущенном контейнере
docker exec my-app ls -la
# Интерактивная оболочка
docker exec -it my-app bash
docker exec -it my-app sh # Для образов на базе Alpine
# Выполнить от имени конкретного пользователя
docker exec -u root -it my-app bash
# Выполнить с переменной окружения
docker exec -e DEBUG=true my-app npm test
# Получить контейнер по шаблону имени
docker exec -it $(docker ps -aqf "name=my-app") bash
Логи и мониторинг
# Просмотреть логи
docker logs my-app
# Следовать логам (streaming)
docker logs -f my-app
# Показать последние N строк
docker logs --tail 100 my-app
# Показать логи с временными метками
docker logs -t my-app
# Показать логи, начиная с временной метки
docker logs --since 2024-01-01T00:00:00 my-app
# Использование ресурсов контейнером
docker stats
# Статистика конкретного контейнера
docker stats my-app --no-stream
# Просмотреть детали контейнера
docker inspect my-app
# Получить конкретное поле
docker inspect --format '{{.NetworkSettings.IPAddress}}' my-app
Управление образами
Сборка образов
# Сборка из Dockerfile в текущем каталоге
docker build -t my-app .
# Сборка с конкретным Dockerfile
docker build -f Dockerfile.prod -t my-app:prod .
# Сборка с аргументами сборки
docker build --build-arg NODE_VERSION=18 -t my-app .
# Сборка без кэша
docker build --no-cache -t my-app .
# Сборка с целевой стадией (multi-stage)
docker build --target builder -t my-app:builder .
# Присвоить тег образу
docker tag my-app:latest my-registry.com/my-app:v1.0.0
Управление образами
# Список образов
docker images
# Список с размером
docker images --format "{{.Repository}}:{{.Tag}} - {{.Size}}"
# Удалить образ
docker rmi my-app:latest
# Удалить неиспользуемые образы
docker image prune
# Удалить все неиспользуемые образы (не только dangling)
docker image prune -a
# Скачать (pull) образ
docker pull nginx:alpine
# Отправить (push) образ
docker push my-registry.com/my-app:v1.0.0
Volumes и хранение данных
Управление volumes
# Создать именованный volume
docker volume create my-data
# Список volumes
docker volume ls
# Просмотреть volume
docker volume inspect my-data
# Удалить volume
docker volume rm my-data
# Удалить неиспользуемые volumes
docker volume prune
Монтирование volumes
# Именованный volume
docker run -v my-data:/app/data my-app
# Bind mount (путь хоста)
docker run -v /host/path:/container/path my-app
# Bind mount текущего каталога
docker run -v $(pwd):/app my-app
# Монтирование только для чтения
docker run -v /host/path:/container/path:ro my-app
# Volumes из другого контейнера
docker run --volumes-from data-container my-app
Сеть
Управление сетями
# Список сетей
docker network ls
# Создать сеть
docker network create my-network
# Создать bridge-сеть с подсетью
docker network create --driver bridge --subnet 172.20.0.0/16 my-network
# Подключить контейнер к сети
docker network connect my-network my-app
# Отключить от сети
docker network disconnect my-network my-app
# Просмотреть сеть
docker network inspect my-network
Сетевое взаимодействие контейнеров
# Запуск в конкретной сети
docker run --network my-network my-app
# Запуск в host network (без изоляции)
docker run --network host my-app
# Связать контейнеры (устаревшее, вместо этого используйте сети)
docker run --link db:database my-app
Лучшие практики Dockerfile
Оптимизированный Dockerfile
# Используйте теги конкретных версий
FROM node:20-alpine AS builder
# Задать рабочий каталог
WORKDIR /app
# Сначала копировать файлы зависимостей (кэширование слоёв)
COPY package*.json ./
# Установить зависимости
RUN npm ci --only=production
# Скопировать исходный код
COPY . .
# Собрать приложение
RUN npm run build
# Стадия production
FROM node:20-alpine AS production
# Создать пользователя без root
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001
WORKDIR /app
# Скопировать только необходимые файлы из builder
COPY --from=builder --chown=nextjs:nodejs /app/dist ./dist
COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./
# Переключиться на пользователя без root
USER nextjs
# Открыть порт
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
# Запустить приложение
CMD ["node", "dist/index.js"]
Оптимизация слоёв
# ПЛОХО: создаёт много слоёв
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y git
RUN rm -rf /var/lib/apt/lists/*
# ХОРОШО: один слой, очистка включена
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
git && \
rm -rf /var/lib/apt/lists/*
Multi-stage для более компактных образов
# Стадия сборки со всеми dev-зависимостями
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o main .
# Минимальный production-образ
FROM alpine:3.18
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/main .
CMD ["./main"]
Обслуживание системы
Команды очистки
# Удалить все остановленные контейнеры
docker container prune
# Удалить неиспользуемые образы
docker image prune
# Удалить неиспользуемые volumes
docker volume prune
# Удалить неиспользуемые сети
docker network prune
# Радикальный вариант: удалить всё неиспользуемое
docker system prune
# Включая volumes и все образы
docker system prune -a --volumes
# Показать использование диска
docker system df
# Подробное использование диска
docker system df -v
Операции с базами данных
Резервное копирование MySQL/PostgreSQL
# Резервное копирование MySQL из контейнера
docker exec my-mysql mysqldump -u root -ppassword dbname > backup.sql
# Восстановление MySQL в контейнер
cat backup.sql | docker exec -i my-mysql mysql -u root -ppassword dbname
# Резервное копирование PostgreSQL
docker exec my-postgres pg_dump -U postgres dbname > backup.sql
# Восстановление PostgreSQL
cat backup.sql | docker exec -i my-postgres psql -U postgres dbname
Развёртывание в production
Docker Compose для production
version: '3.8'
services:
app:
image: my-app:${VERSION:-latest}
deploy:
replicas: 3
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
Лучшие практики безопасности
# Не запускайте от root
USER 1001
# Используйте COPY вместо ADD (более предсказуемо)
COPY requirements.txt .
# Не храните секреты в образах
# Используйте --secret или переменные окружения во время выполнения
# Сканируйте на уязвимости
# docker scan my-app:latest
Ключевые выводы
- Используйте конкретные теги: никогда не используйте
latest в production - Оптимизируйте слои: объединяйте команды RUN, упорядочивайте по частоте изменений
- Multi-stage сборки: разделяйте окружения сборки и runtime
- Пользователи без root: лучшая практика безопасности
- Health checks: включайте самовосстановление orchestrator
- Регулярно выполняйте очистку: предотвращайте проблемы с дисковым пространством
Мастерство Docker приходит с пониманием как команд, так и базовых концепций — практикуйте эти паттерны, пока они не станут для вас естественными.