Files
docker/docs/3. Dockerfile - сборка образа и COPY.md
T
2026-05-04 12:07:58 +03:00

339 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Зачем нужен 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] <src> ... <dest>
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] <src> ... <dest>
```
Поведение как у `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/).