Dockerfile: основы
Что такое Dockerfile
Dockerfile — текстовый файл с инструкциями, как собрать образ. Читается сверху вниз. Каждая инструкция создаёт слой.
Структура
FROM ubuntu:22.04
RUN apt update && apt install -y nginx
COPY nginx.conf /etc/nginx/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Основные инструкции
FROM — базовый образ
Первая строка любого Dockerfile.
FROM ubuntu:22.04
FROM php:8.5-fpm-alpine
FROM node:22-alpine
FROM nginx:1.25-alpine
Правило: выбирай минимальный образ. Alpine — 5-50 МБ, slim — 100-200 МБ, полный — 300+ МБ.
RUN — выполнить команду
При сборке.
RUN apt update
RUN apt install -y git curl
Склеивай в одну строку для меньшего числа слоёв:
RUN apt update && \
apt install -y git curl unzip && \
apt clean && rm -rf /var/lib/apt/lists/*
rm -rf /var/lib/apt/lists/* — чистит кеш apt. Экономит десятки МБ.
COPY — скопировать файлы
Из контекста сборки в образ.
COPY composer.json composer.lock ./
COPY . .
COPY ./config /app/config
Первый аргумент — откуда (относительно контекста), второй — куда.
ADD — как COPY, но с фишками
Умеет распаковывать архивы и качать по URL:
ADD https://example.com/file.tar.gz /tmp/
ADD archive.tar.gz /app/
Правило: используй COPY по умолчанию. ADD — только если нужны распаковка или URL.
WORKDIR — рабочая папка
WORKDIR /var/www/html
Все последующие RUN/CMD/COPY работают относительно неё. Создаётся, если нет.
ENV — переменные окружения
ENV APP_ENV=production
ENV NODE_ENV=production
Доступны во время сборки и в контейнере.
ARG — аргументы сборки
ARG PHP_VERSION=8.5
FROM php:${PHP_VERSION}-fpm
Отличие от ENV: ARG — только во время сборки, ENV — и в контейнере.
Передаётся:
docker build --build-arg PHP_VERSION=8.4 .
EXPOSE — документировать порт
EXPOSE 80
EXPOSE 3000
Не открывает порт! Только документирует. Порт открывается через -p при docker run.
CMD — команда по умолчанию
Запускается при старте контейнера. Может быть переопределена при docker run.
CMD ["php-fpm"]
CMD ["nginx", "-g", "daemon off;"]
CMD ["node", "server.js"]
Exec-форма (массив): без shell.
Shell-форма (строка): через /bin/sh -c.
Правильно: exec-форма.
ENTRYPOINT — точка входа
Как CMD, но не переопределяется при docker run (без --entrypoint).
ENTRYPOINT ["docker-php-entrypoint"]
CMD ["php-fpm"]
Паттерн: ENTRYPOINT — программа, CMD — аргументы.
USER — от какого пользователя
USER www-data
Для безопасности: не работай от root. Создай пользователя:
RUN adduser --disabled-password --gecos '' app
USER app
HEALTHCHECK — проверка здоровья
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost/health || exit 1
Docker будет периодически проверять. Полезно для оркестраторов.
LABEL — метаданные
LABEL maintainer="you@example.com"
LABEL version="1.0.0"
Порядок инструкций и кеш
Docker кеширует каждый слой. Если слой не изменился — берётся из кеша.
Правило: сначала то, что меняется редко.
Плохо:
COPY . /app # копируем ВСЁ
RUN composer install # при любом изменении — заново
Хорошо:
COPY composer.json composer.lock /app/ # только composer
RUN composer install # кешируется
COPY . /app # остальное в конце
Теперь при изменении кода composer install не запустится — возьмётся из кеша.
.dockerignore
Файл в корне, как .gitignore. Указывает, что не отправлять в образ.
.git
.gitignore
node_modules
vendor
storage/logs
storage/framework/cache
.env
.env.*
*.md
.DS_Store
.idea
.vscode
docker-compose.yml
Dockerfile
Плюс: меньше контекст → быстрее сборка. Меньше размер образа.
Пример: минимальный Dockerfile
FROM nginx:1.25-alpine
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Собери:
docker build -t my-nginx .
-t — имя и тег. . — текущая папка (контекст).
Запусти:
docker run -d -p 8080:80 my-nginx
Сборка с тегом
docker build -t my-app:1.0.0 .
docker build -t my-app:latest .
docker build -t my-app:1.0.0 -t my-app:latest .
Просмотр истории образа
docker history my-app
Показывает все слои и их размер. Видно, где раздуто.
Многоступенчатая сборка (multi-stage)
Идея: собираем в одном образе, запускаем в другом, минимальном.
# Этап сборки
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Финальный этап — только готовое
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
Плюс: финальный образ в разы меньше. Без node, без исходников, без dev-зависимостей.
Для: Node.js, React, Next.js, Go, Rust.
Проверка синтаксиса
Линтер — hadolint:
docker run --rm -i hadolint/hadolint < Dockerfile
Показывает ошибки и антипаттерны.
Управление кешем
docker build --no-cache -t my-app . # без кеша
docker builder prune # очистить кеш
docker buildx prune # для buildx
Частые ошибки
1. COPY . . до RUN composer install — кеш ломается.
2. Нет .dockerignore — в образ попадают .git, node_modules.
3. Много слоёв RUN — размер растёт. Склеивай через &&.
4. Не чистят apt-кеш — лишние 50-100 МБ.
5. Запуск от root — небезопасно. Используй USER.
6. Полный базовый образ — 1 ГБ вместо 50 МБ. Используй alpine/slim.
Итог
Минимум:
FROM— базовый образWORKDIR— рабочая папкаCOPY— файлыRUN— команды сборкиCMD— что запустить
Правила:
- Копируй
composer.jsonдоCOPY . . - Всегда
.dockerignore - Multi-stage для фронта
- Alpine для экономии
Дальше — Dockerfile для Laravel.