From def936c2a20360119390d102f6542452e6f26092 Mon Sep 17 00:00:00 2001 From: chase Date: Mon, 4 May 2026 11:57:56 +0300 Subject: [PATCH] push --- ...r Engine — установка и основные команды.md | 4 + docs/3. Dockerfile — сборка образа и COPY.md | 380 ++++++++++++------ 2 files changed, 271 insertions(+), 113 deletions(-) diff --git a/docs/2. Docker Engine — установка и основные команды.md b/docs/2. Docker Engine — установка и основные команды.md index dbb94f9..35a1187 100644 --- a/docs/2. Docker Engine — установка и основные команды.md +++ b/docs/2. Docker Engine — установка и основные команды.md @@ -54,6 +54,7 @@ docker run -it --rm debian:bookworm-slim bash ``` Установка образа: + Мы указали `bash` в команде, по этому зашли в интерактивный терминал: @@ -123,6 +124,7 @@ docker exec -it my-nginx sh Обновим страницу в браузере - должен отобразиться новый html. + Скопировать **из** контейнера на хост: @@ -151,6 +153,7 @@ docker exec nginx-vol sh -c 'echo vol > /usr/share/nginx/html/index.html' `docker exec nginx-vol sh -c 'echo vol > /usr/share/nginx/html/index.html'` - выполняем команду ВНУТРИ контейнера `nginx-vol` через "sh -c" и передать ему команду `echo`. + Коротко, что мы сделали: @@ -185,6 +188,7 @@ docker run -d --name nginx-bind -p 8082:80 -v ~/docker-html:/usr/share/nginx/htm Теперь поменяем в нашей локальной папке файл и посмотрим что будет: + Всё работает. diff --git a/docs/3. Dockerfile — сборка образа и COPY.md b/docs/3. Dockerfile — сборка образа и COPY.md index 835942e..450e30e 100644 --- a/docs/3. Dockerfile — сборка образа и COPY.md +++ b/docs/3. Dockerfile — сборка образа и COPY.md @@ -1,162 +1,316 @@ ## Зачем нужен Dockerfile -`Dockerfile` — это **рецепт** сборки образа: от какого базового образа начать, какие пакеты установить, какие файлы скопировать, какую команду запускать по умолчанию. Команда сборки: +`Dockerfile` - текстовый файл с инструкциями (по одной на строку, логически сверху вниз). Демон Docker читает их и строит образ **слоями**, почти каждая инструкция добавляет слой. +Сборка: ``` -docker build -t my-app:1.0 -f Dockerfile /path/to/context +docker build -t имя:тег -f Dockerfile /путь/к/контексту ``` -**Контекст сборки** — каталог, который вы передаёте последним аргументом (часто `.`). В образ попадают только файлы из контекста (по правилам `.dockerignore`). +**Контекст** - каталог, из которого разрешено брать файлы для `COPY`/`ADD` (часто `.`). Список исключений — в `.dockerignore` в корне контекста. ---- +## Общие правила файла -## Минимальный Dockerfile и сборка +1. **Имя по умолчанию** - `Dockerfile` в корне контекста; другой файл: `docker build -f ./docker/prod.Dockerfile .` +2. **Комментарии** - строка, начинающаяся с `#`. +3. **Продолжение строки** - обратный слэш `\` в конце строки. +4. **Регистр** - инструкции принято писать **ЗАГЛАВНЫМИ** (`FROM`, `RUN`…), Docker это не требует, просто читается легче. +5. **Первый этап** должен начинаться с **`FROM`** (кроме редких случаев с `ARG` до первого `FROM`). -Готовый вариант каталога **web** лежит в репозитории: `docker/examples/multi-service/web/` — можно собирать оттуда (`docker build -t my-web:1.0 ./web` из корня `multi-service`). Ниже — пошагово «с нуля»: +## Parser directives (только в самом верху файла) -``` -mkdir -p ~/learn-docker/web && cd ~/learn-docker/web -``` +Их максимум две, только **до** любых комментариев и инструкций (после пустых строк тоже нельзя вставлять мусор сверху). -Содержимое `Dockerfile` (ниже — максимально «говорящий» вариант с комментариями; в реальном файле комментарии допустимы): +`# 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 -# Синтаксис Dockerfile (опционально, для BuildKit features) # syntax=docker/dockerfile:1 +RUN --mount=type=cache,target=/root/.cache/pip \ + pip install -r requirements.txt +``` -# Базовый образ: лучше фиксировать мажорную версию и по возможности slim/alpine -FROM nginx:1.27-alpine +Типы `type=` включают `cache`, `bind`, `secret`, `ssh` и др. [документация BuildKit mounts](https://docs.docker.com/build/buildkit/). -# Метаданные (удобно в docker inspect / реестрах) -LABEL org.opencontainers.image.title="Demo static site" -LABEL org.opencontainers.image.description="Nginx with baked-in HTML from COPY" +## `WORKDIR` - рабочий каталог -# Переменные на этапе сборки (не попадают в runtime автоматически как ENV) -ARG BUILD_DATE=unknown -LABEL build-date="${BUILD_DATE}" +```dockerfile +WORKDIR /app +``` -# Переменные окружения внутри контейнера при запуске -ENV NGINX_ENTRYPOINT_QUIET_LOGS=1 +Создаёт каталог, если его нет. Влияет на последующие `RUN`, `COPY`, `CMD`, `ENTRYPOINT` в **exec-форме** относительно пути (часть команд всё равно лучше указывать абсолютно). +Можно несколько раз - каждый раз новый путь. -# Рабочая директория для последующих инструкций -WORKDIR /usr/share/nginx/html +## `COPY` - файлы в образ -# Копирование файлов ИЗ контекста сборки В образ (ключевой способ «положить файлы в образ») -COPY ./html/ /usr/share/nginx/html/ +```dockerfile +COPY [--chown=user:group] [--chmod=755] ... +COPY ["--chown=user:group", "src с пробелом", "/dest/"] +``` -# Права (nginx в alpine часто от uid 101 — для продакшена уточняйте образ) -RUN chown -R nginx:nginx /usr/share/nginx/html +| Параметр | Смысл | +|----------|--------| +| `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 - -# Healthcheck — Docker помечает контейнер unhealthy при ошибках (оркестраторы могут рестартовать) -HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ - CMD wget -qO- http://127.0.0.1/ || exit 1 - -# Команда по умолчанию наследуется от nginx; при необходимости переопределяем: -# CMD ["nginx", "-g", "daemon off;"] +EXPOSE 80/tcp 443/tcp +EXPOSE 53/udp ``` -Папка `html/index.html`: +Это **метаданные** и подсказка для `docker run -P`. Порт на хост не открывается, пока не укажете `-p` или Compose `ports:`. -```html - - -Docker COPY demo -

Файл попал в образ через COPY

- +## `VOLUME` - каталог для данных вне слоя записи + +```dockerfile +VOLUME ["/data"] +VOLUME /var/log/app ``` -Сборка и запуск: +Объявляет точку, куда при запуске без явного `-v` Docker может подставить **анонимный том**. Часто для данных БД или логов. **Не путать** с явным монтированием в `docker run -v`. -``` -docker build -t my-web:1.0 . -docker run -d --name from-dockerfile -p 8090:80 my-web:1.0 +## `USER` - под каким UID/GID работать + +```dockerfile +USER nginx +USER 1000:1000 ``` -**Скриншот:** этапы сборки `Step ...` и успешное `Successfully tagged my-web:1.0`. +Все последующие `RUN` и процесс по умолчанию при старте — от этого пользователя (если не переопределить в `docker run -u`). - +## `LABEL` - метаданные образа -**Скриншот:** браузер на порту 8090 с вашим заголовком. +```dockerfile +LABEL maintainer="you@example.com" +LABEL version="1.0" description="My app" +``` - +Пары ключ–значение; удобно для OCI-аннотаций (`org.opencontainers.image.*`), реестров, политик. ---- +## `CMD` - что выполнять при запуске по умолчанию -## `.dockerignore` — что не отправлять в демон при сборке +Три формы: -В корне контекста создайте `.dockerignore`, чтобы не копировать мусор и секреты: +```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 -.env -*.log node_modules -__pycache__ +.env +*.md ``` -**Скриншот:** сравнение размера контекста в логе сборки до/после добавления `.dockerignore` (если делали большую папку). - - - ---- - -## COPY vs ADD - -- **`COPY`** — только копирование из контекста (предсказуемо, предпочтительно). -- **`ADD`** — то же плюс распаковка локальных tar и загрузка по URL (URL почти не используют; для tar — редко). - ---- - -## Многоэтапная сборка (multi-stage) - -Первый этап — сборка (тяжёлые компиляторы), финальный образ — только артефакт. Пример идеи: этап `builder` с Node, финальный — `nginx` со статикой. - -```dockerfile -# syntax=docker/dockerfile:1 -FROM node:22-alpine AS builder -WORKDIR /app -COPY package.json package-lock.json ./ -RUN npm ci -COPY src ./src -RUN npm run build - -FROM nginx:1.27-alpine -COPY --from=builder /app/dist /usr/share/nginx/html -EXPOSE 80 -``` - -**Скриншот:** `docker images` — финальный образ заметно меньше, чем образ с полным Node (сравните REPOSITORY/TAG и SIZE). - - - ---- - -## Передача секретов при сборке (обзорно) - -Не кладите пароли в `Dockerfile` в открытом виде. Варианты: - -- BuildKit **secret mount**: `RUN --mount=type=secret ...` и `docker build --secret id=mysecret,src=.env`. -- **ARG** для некритичных параметров; помните, что значения ARG могут остаться в истории слоёв, если не обнулить. - -Подробности — в [Dockerfile reference](https://docs.docker.com/reference/dockerfile/). - ---- - -## Прослойка образов: `docker history` +## Сборка и просмотр слоёв ``` +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**. - - ---- - -## Связь с Compose - -В `docker-compose.yml` можно указать `build: .` для сервиса — Compose вызовет `docker build` с нужным контекстом. Полный стек — в части **4** и в каталоге `docker/examples/multi-service/`. +## Документация +Полный список инструкций, edge cases и актуальные флаги [Dockerfile reference](https://docs.docker.com/reference/dockerfile/).