## Зачем нужен Dockerfile `Dockerfile` - текстовый файл с инструкциями (по одной на строку, логически сверху вниз). Демон Docker читает их и строит образ **слоями**, почти каждая инструкция добавляет слой. Сборка: ``` docker build -t имя:тег -f Dockerfile /путь/к/контексту ``` **Контекст** - каталог, из которого разрешено брать файлы для `COPY`/`ADD` (часто `.`). Список исключений — в `.dockerignore` в корне контекста. ## Общие правила файла 1. **Имя по умолчанию** - `Dockerfile` в корне контекста; другой файл: `docker build -f ./docker/prod.Dockerfile .` 2. **Комментарии** - строка, начинающаяся с `#`. 3. **Продолжение строки** - обратный слэш `\` в конце строки. 4. **Регистр** - инструкции принято писать **ЗАГЛАВНЫМИ** (`FROM`, `RUN`…), Docker это не требует, просто читается легче. 5. **Первый этап** должен начинаться с **`FROM`** (кроме редких случаев с `ARG` до первого `FROM`). ## Parser directives (только в самом верху файла) Их максимум две, только **до** любых комментариев и инструкций (после пустых строк тоже нельзя вставлять мусор сверху). `# syntax=docker/dockerfile:1` - Включить современный фронтенд Dockerfile (BuildKit, расширенный синтаксис `RUN --mount=...`). ## Сводная таблица инструкций | Инструкция | Назначение (кратко) | |------------|---------------------| | `FROM` | Базовый образ (начало этапа / stage). | | `RUN` | Выполнить команду **при сборке** (новый слой). | | `CMD` | **По умолчанию** команда/аргументы при **запуске** контейнера (переопределяется `docker run ...`). | | `ENTRYPOINT` | «Точка входа» при запуске; с `CMD` задаёт аргументы по умолчанию. | | `COPY` | Копирование из контекста (или из другого stage) в образ. | | `ADD` | Как `COPY` + tar и URL (реже нужен). | | `WORKDIR` | Текущий каталог для последующих инструкций. | | `ENV` | Переменные окружения в образе (и при сборке для следующих строк). | | `ARG` | Переменные **только на время сборки** (`docker build --build-arg`). | | `EXPOSE` | Документация портов (не публикует на хост само по себе). | | `VOLUME` | Объявить точку монтирования тома по умолчанию. | | `USER` | Пользователь для следующих `RUN` и для процесса при запуске. | | `LABEL` | Метаданные ключ=значение. | | `STOPSIGNAL` | Какой сигнал послать при `docker stop`. | | `HEALTHCHECK` | Как проверять живость контейнера. | | `SHELL` | Какая оболочка для **shell-формы** `RUN`/`CMD`/`ENTRYPOINT`. | | `ONBUILD` | Зарегистрировать инструкцию «выполнить позже», когда от этого образа соберут дочерний (редко). | Ниже - что писать, какие есть параметры и на что обратить внимание. ## `FROM` - базовый образ **Синтаксис:** ```dockerfile FROM [--platform=linux/amd64] image[:tag|@digest] [AS name] ``` | Элемент | Смысл | |---------|--------| | `image:tag` | Репозиторий и тег (`nginx:1.27-alpine`). Лучше фиксировать тег или digest. | | `AS name` | Имя этапа для **multi-stage** и для `COPY --from=name`. | | `--platform=...` | Целевая платформа образа (multi-arch / кросс-сборка). | Каждый новый `FROM` начинает **новый этап**; предыдущие слои остаются в цепочке сборки, в финальный образ попадает только последний этап (если не копировать из предыдущих через `COPY --from`). ## `RUN` - команды на этапе сборки Две формы записи: **Shell-форма** (через `/bin/sh -c` в Linux, если не переопределён `SHELL`): ```dockerfile RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* ``` **Exec-форма** (без оболочки, нет подстановок `$VAR` шелла, если не передать через оболочку явно): ```dockerfile RUN ["apt-get", "update"] ``` Часто объединяют команды в **одну** строку `&&`, чтобы меньше слоёв и не оставлять кэш пакетов в отдельном слое. **BuildKit:** кэш зависимостей, секреты, примонтировать каталог хоста только на время `RUN`: ```dockerfile # syntax=docker/dockerfile:1 RUN --mount=type=cache,target=/root/.cache/pip \ pip install -r requirements.txt ``` Типы `type=` включают `cache`, `bind`, `secret`, `ssh` и др. [документация BuildKit mounts](https://docs.docker.com/build/buildkit/). ## `WORKDIR` - рабочий каталог ```dockerfile WORKDIR /app ``` Создаёт каталог, если его нет. Влияет на последующие `RUN`, `COPY`, `CMD`, `ENTRYPOINT` в **exec-форме** относительно пути (часть команд всё равно лучше указывать абсолютно). Можно несколько раз - каждый раз новый путь. ## `COPY` - файлы в образ ```dockerfile COPY [--chown=user:group] [--chmod=755] ... COPY ["--chown=user:group", "src с пробелом", "/dest/"] ``` | Параметр | Смысл | |----------|--------| | `src` | Путь **относительно контекста** сборки (не выше контекста). | | `dest` | Файл или каталог в образе (обычно абсолютный путь). | | `--chown` | Владелец скопированных файлов (uid:gid или имя). | | `--chmod` | Права на файлы (новые версии BuildKit). | | `--from=stage\|index` | Копировать не из контекста, а из **другого этапа** или **именованного образа** (`COPY --from=nginx:alpine /etc/nginx/nginx.conf /tmp/`). | Несколько `src` - последний аргумент должен быть **каталогом** с `/` на конце. ## `ADD` - расширенное копирование ```dockerfile ADD [--chown=user:group] [--chmod=755] ... ``` Поведение как у `COPY`, плюс: - локальный **`src` в виде tar** - может **распаковаться** в `dest`. - **`src` как URL** — скачать файл. Для обычных файлов предпочитают **`COPY`**. ## `ENV` - переменные окружения ```dockerfile ENV KEY=value ENV KEY=value OTHER=val2 ENV KEY="значение с пробелами" ``` - Доступны в последующих инструкциях Dockerfile и **в запущенном контейнере**. - Одна форма `ENV A=B C=D` задаёт несколько переменных. - Значения можно подставлять в строках как `$KEY` или `${KEY}`. ## `ARG` - переменные только при сборке ```dockerfile ARG VERSION=1.0 ARG GIT_COMMIT ``` - Значение снаружи: `docker build --build-arg GIT_COMMIT=$(git rev-parse HEAD)`. - **`ARG` до первого `FROM`** может участвовать только в самом `FROM` (версия базового образа). - После `FROM` переменные `ARG` нужно **объявить снова**, если они нужны в этом этапе. - **Не храните секреты в `ARG`** без BuildKit secrets: значения могут попасть в историю слоёв (`docker history`). ## `EXPOSE` - какие порты «слушает» приложение ```dockerfile EXPOSE 80 EXPOSE 80/tcp 443/tcp EXPOSE 53/udp ``` Это **метаданные** и подсказка для `docker run -P`. Порт на хост не открывается, пока не укажете `-p` или Compose `ports:`. ## `VOLUME` - каталог для данных вне слоя записи ```dockerfile VOLUME ["/data"] VOLUME /var/log/app ``` Объявляет точку, куда при запуске без явного `-v` Docker может подставить **анонимный том**. Часто для данных БД или логов. **Не путать** с явным монтированием в `docker run -v`. ## `USER` - под каким UID/GID работать ```dockerfile USER nginx USER 1000:1000 ``` Все последующие `RUN` и процесс по умолчанию при старте — от этого пользователя (если не переопределить в `docker run -u`). ## `LABEL` - метаданные образа ```dockerfile LABEL maintainer="you@example.com" LABEL version="1.0" description="My app" ``` Пары ключ–значение; удобно для OCI-аннотаций (`org.opencontainers.image.*`), реестров, политик. ## `CMD` - что выполнять при запуске по умолчанию Три формы: ```dockerfile CMD ["executable", "param1", "param2"] CMD ["param1", "param2"] CMD command param1 param2 ``` | Форма | Смысл | | ----------------------------------- | --------------------------------------------------------------------------------------- | | **Exec** `["exe", "a"]` | Прямой запуск, PID 1 = `exe`, сигналы доходят нормально. | | **Exec как аргументы к ENTRYPOINT** | Если задан `ENTRYPOINT`, `CMD` даёт только аргументы по умолчанию. | | **Shell** `CMD a && b` | Через `sh -c`; PID 1 = shell - для сигналов и таймаутов остановки хуже, чем exec-форма. | **Переопределение:** `docker run image ls` заменит `CMD` на `ls` (если не трогать `ENTRYPOINT`). В файле допустима **одна** инструкция `CMD` (если несколько, то последняя выполняется). ## `ENTRYPOINT` - фиксированная «обёртка» запуска ```dockerfile ENTRYPOINT ["docker-entrypoint.sh"] ENTRYPOINT exec java -jar app.jar ``` - **Exec-форма** — как с `CMD`, хорошо для PID 1. - **Shell-форма** — через `sh -c`. Частый паттерн: `ENTRYPOINT` = скрипт или бинарник, `CMD` = аргументы по умолчанию. Тогда `docker run myimage --help` передаёт `--help` в entrypoint. ## `STOPSIGNAL` - сигнал остановки ```dockerfile STOPSIGNAL SIGTERM ``` Какой сигнал послать процессу при `docker stop` (по умолчанию обычно `SIGTERM`, потом `SIGKILL`). Нужен редко (например, для JVM или nginx с graceful shutdown). ## `HEALTHCHECK` - проверка «жив ли» контейнер ```dockerfile HEALTHCHECK [OPTIONS] CMD command ``` **OPTIONS:** | Опция | Смысл | |--------|--------| | `--interval=DURATION` | Как часто (по умолчанию 30s). | | `--timeout=DURATION` | Таймаут одной проверки (default 30s). | | `--start-period=DURATION` | «Прогрев»: неудачи не считаются failure (default 0s). | | `--retries=N` | Сколько подряд неуспехов → `unhealthy` (default 3). | `CMD` здесь - команда проверки (часто `curl`/`wget` к localhost или скрипт). `HEALTHCHECK NONE` - отключить наследованный healthcheck от базового образа. ## `SHELL` - оболочка для shell-форм ```dockerfile SHELL ["powershell", "-command"] SHELL ["/bin/bash", "-c"] ``` Меняет команду для **shell-формы** `RUN`, `CMD`, `ENTRYPOINT` на Windows/Linux. ## `ONBUILD` - отложенная инструкция для «дочерних» образов ```dockerfile ONBUILD COPY . /app/src ``` Выполнится **не при сборке этого образа**, а когда **другой** Dockerfile сделает `FROM` этого образа. Сейчас редко используют (Compose/build args проще отследить). ## Многоэтапная сборка (`FROM ... AS` + `COPY --from`) Несколько блоков `FROM ... AS builder` / `FROM ... AS production`. Из «тяжёлого» этапа в «лёгкий» переносят только артефакты: ```dockerfile FROM node:22-alpine AS build WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM nginx:alpine COPY --from=build /app/dist /usr/share/nginx/html ``` Имена этапов - в `AS`; копирование - `COPY --from=build` или `--from=0` (индекс этапа). ## `COPY` vs `ADD` — что выбрать | Задача | Инструкция | | ----------------------------------- | --------------------------------------------------------------- | | Файлы/папки из контекста в образ | **`COPY`** | | Распаковать локальный `.tar` в слой | `ADD` (или `COPY` + `RUN tar`) | | Скачать по URL | лучше `RUN curl`/`wget` с проверкой checksum; `ADD URL` — редко | ## `.dockerignore` В корне **контекста** — шаблоны путей, которые **не отправляются** демону при сборке и недоступны для `COPY`/`ADD`: ``` .git node_modules .env *.md ``` ## Сборка и просмотр слоёв ``` docker build -t my-web:1.0 -f Dockerfile . docker history my-web:1.0 ``` ## Готовый пример в репозитории Рабочие `Dockerfile` с `COPY`, `EXPOSE`, `HEALTHCHECK` и т.д. — в `docker/examples/multi-service/` (`web`, `api`, `proxy`). Связка с Compose — в части **4**. ## Документация Полный список инструкций, edge cases и актуальные флаги [Dockerfile reference](https://docs.docker.com/reference/dockerfile/).