Skip to content

Основы Docker: Лучшие практики

При работе с Docker существует ряд общепринятых лучших практик, которые помогут вам оптимизировать ваши образы, контейнеры и процессы разработки.

1. Dockerfile

  • Используйте минимальные базовые образы: Начинайте с небольших базовых образов (например, alpine-based), чтобы уменьшить размер и повысить безопасность ваших итоговых образов.
  • Мультистейдж сборки (Multi-stage builds): Используйте несколько стадий в Dockerfile для сборки приложения и копирования только необходимых артефактов в финальный образ. Это значительно уменьшает размер образа.
  • Кэширование слоев: Располагайте инструкции в Dockerfile таким образом, чтобы максимально эффективно использовать кэширование слоев Docker. Наименее часто меняющиеся инструкции должны идти первыми.
  • Избегайте установки ненужного программного обеспечения: Устанавливайте только те пакеты и инструменты, которые действительно необходимы для работы вашего приложения.
  • Запускайте процессы от непривилегированного пользователя: Используйте инструкцию USER для запуска процессов внутри контейнера от непривилегированного пользователя, а не от root.
  • Явно указывайте теги образов: Всегда указывайте конкретные теги версий вместо latest, чтобы обеспечить воспроизводимость сборок.
  • Очищайте за собой: Удаляйте временные файлы и каталоги, созданные в процессе сборки, в том же слое Dockerfile.
  • Используйте .dockerignore: Создайте файл .dockerignore для исключения ненужных файлов и каталогов из контекста сборки, что ускорит процесс сборки и уменьшит размер образа.
  • Сортируйте многострочные аргументы: При использовании RUN apt-get install -y ... или подобных команд, сортируйте список пакетов для лучшей читаемости и предотвращения дублирования.
  • Ограничивайте количество слоев: Хотя слои полезны для кэширования, чрезмерное их количество может увеличить размер образа. Старайтесь объединять связанные команды в один слой с помощью &&.

Пример мультистейдж-сборки

dockerfile
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:1.27-alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80

Пример .dockerignore

txt
node_modules
dist
.git
.env
npm-debug.log

2. Образы Docker

  • Регулярно обновляйте базовые образы: Следите за обновлениями безопасности базовых образов и пересобирайте свои образы при необходимости.
  • Сканируйте образы на уязвимости: Используйте инструменты для сканирования образов на наличие известных уязвимостей.
  • Подписывайте образы (Docker Content Trust): Используйте Docker Content Trust для обеспечения целостности и подлинности ваших образов.
  • Управляйте секретами: Не храните секреты (пароли, ключи API) непосредственно в образах. Используйте Docker Secrets или другие безопасные методы управления секретами.
  • Используйте специфичные теги: Давайте вашим образам понятные и информативные теги, отражающие версию приложения или другие важные параметры.
  • Удаляйте неиспользуемые образы: Регулярно очищайте локальное хранилище от неиспользуемых образов с помощью docker image prune.

3. Контейнеры Docker

  • Используйте именованные контейнеры: Давайте контейнерам понятные имена для облегчения управления и отслеживания.
  • Ограничивайте ресурсы контейнеров: Используйте флаги --memory, --cpu-shares и другие для ограничения ресурсов, потребляемых контейнерами, чтобы предотвратить монополизацию ресурсов хост-машины.
  • Используйте тома для постоянного хранения данных: Не храните важные данные внутри слоев контейнера. Используйте тома для обеспечения сохранности данных независимо от жизненного цикла контейнера.
  • Настраивайте health checks: Определяйте health checks для ваших контейнеров, чтобы Docker мог отслеживать их состояние и автоматически перезапускать нездоровые контейнеры.
  • Используйте сети Docker: Создавайте пользовательские сети Docker для изоляции контейнеров и управления их взаимодействием. Избегайте использования сети host в production.
  • Ограничивайте порты: Публикуйте только те порты, которые действительно необходимы для взаимодействия с контейнером.
  • Настраивайте логирование: Используйте подходящие драйверы логирования для сбора и управления логами контейнеров. Рассмотрите возможность централизованного логирования.
  • Удаляйте остановленные контейнеры: Регулярно очищайте остановленные контейнеры с помощью docker container prune.
  • Используйте --restart always (с осторожностью): Настройте политику перезапуска контейнеров в соответствии с требованиями вашего приложения, но будьте внимательны с always, чтобы избежать бесконечных циклов перезапуска.

4. Docker Compose

  • Используйте явные версии Compose: Указывайте версию формата файла docker-compose.yml.
  • Определяйте зависимости между сервисами: Используйте depends_on для указания порядка запуска сервисов.
  • Используйте переменные окружения: Конфигурируйте сервисы с помощью переменных окружения, а не жестко закодированных значений.
  • Определяйте тома и сети на верхнем уровне: Это делает конфигурацию более читаемой и удобной для повторного использования.
  • Используйте файлы .env: Храните переменные окружения в файле .env (который следует добавить в .dockerignore).
  • Избегайте links (в пользу пользовательских сетей): Используйте пользовательские сети для взаимодействия между сервисами, так как links являются устаревшим функционалом.
  • Используйте healthcheck в определениях сервисов: Настройте проверки состояния сервисов для оркестрации и мониторинга.
  • Разделяйте конфигурацию для разных сред: Используйте файлы docker-compose.override.yml для переопределения конфигурации в разных средах (например, разработка, тестирование, production).

Профили Compose для разных сценариев

Профили позволяют включать сервисы только по необходимости (например, поднимать админку или мониторинг отдельной командой).

yaml
services:
  app:
    build: .
    ports:
      - "3000:3000"

  adminer:
    image: adminer
    profiles: ["debug"]
    ports:
      - "8080:8080"
bash
docker compose up -d
docker compose --profile debug up -d

5. Безопасность

  • Следуйте принципу наименьших привилегий: Предоставляйте контейнерам и процессам внутри них только необходимые привилегии.
  • Ограничивайте возможности контейнеров: Используйте seccomp, AppArmor и SELinux для ограничения системных вызовов и доступа к ресурсам.
  • Регулярно сканируйте образы и контейнеры на уязвимости.
  • Настройте безопасное управление секретами.
  • Ограничивайте доступ к Docker Daemon.
  • Используйте TLS для защиты Docker Daemon Socket при удаленном управлении.
  • Настройте сетевые политики для контроля взаимодействия между контейнерами.

6. Мониторинг и логирование

  • Настройте централизованное логирование: Перенаправляйте логи контейнеров в централизованную систему для агрегации и анализа.
  • Используйте структурированные логи: Форматируйте логи в структурированном формате (например, JSON).
  • Включите достаточную информацию в логи (временные метки, уровни логирования и т.д.).
  • Настройте мониторинг ресурсов Docker-хоста и контейнеров.
  • Используйте инструменты мониторинга (например, Prometheus, Grafana, cAdvisor).
  • Настройте оповещения о проблемах с производительностью или состоянием контейнеров.

7. Общие рекомендации

  • Изучите основы Docker: Понимание основных концепций Docker (образы, контейнеры, сети, тома) является ключевым для эффективной работы.
  • Следуйте документации: Обращайтесь к официальной документации Docker для получения актуальной информации и лучших практик.
  • Используйте контроль версий для Dockerfile и docker-compose.yml: Храните файлы конфигурации Docker в системе контроля версий (например, Git).
  • Автоматизируйте процессы: Автоматизируйте сборку, тестирование и развертывание Docker-контейнеров с помощью CI/CD пайплайнов.
  • Будьте в курсе обновлений: Следите за новыми возможностями и рекомендациями в экосистеме Docker.
  • Сообщество: Участвуйте в сообществе Docker, обменивайтесь опытом и узнавайте о лучших практиках от других пользователей.

Следование этим лучшим практикам поможет вам создавать более надежные, безопасные и масштабируемые контейнеризованные приложения с использованием Docker. Помните, что выбор конкретных практик может зависеть от ваших специфических требований и контекста проекта.