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

163 lines
6.6 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 build -t my-app:1.0 -f Dockerfile /path/to/context
```
**Контекст сборки** — каталог, который вы передаёте последним аргументом (часто `.`). В образ попадают только файлы из контекста (по правилам `.dockerignore`).
---
## Минимальный Dockerfile и сборка
Готовый вариант каталога **web** лежит в репозитории: `docker/examples/multi-service/web/` — можно собирать оттуда (`docker build -t my-web:1.0 ./web` из корня `multi-service`). Ниже — пошагово «с нуля»:
```
mkdir -p ~/learn-docker/web && cd ~/learn-docker/web
```
Содержимое `Dockerfile` (ниже — максимально «говорящий» вариант с комментариями; в реальном файле комментарии допустимы):
```dockerfile
# Синтаксис Dockerfile (опционально, для BuildKit features)
# syntax=docker/dockerfile:1
# Базовый образ: лучше фиксировать мажорную версию и по возможности slim/alpine
FROM nginx:1.27-alpine
# Метаданные (удобно в docker inspect / реестрах)
LABEL org.opencontainers.image.title="Demo static site"
LABEL org.opencontainers.image.description="Nginx with baked-in HTML from COPY"
# Переменные на этапе сборки (не попадают в runtime автоматически как ENV)
ARG BUILD_DATE=unknown
LABEL build-date="${BUILD_DATE}"
# Переменные окружения внутри контейнера при запуске
ENV NGINX_ENTRYPOINT_QUIET_LOGS=1
# Рабочая директория для последующих инструкций
WORKDIR /usr/share/nginx/html
# Копирование файлов ИЗ контекста сборки В образ (ключевой способ «положить файлы в образ»)
COPY ./html/ /usr/share/nginx/html/
# Права (nginx в alpine часто от uid 101 — для продакшена уточняйте образ)
RUN chown -R nginx:nginx /usr/share/nginx/html
# Документируем порт (не открывает его само по себе на хосте — это метаданные)
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;"]
```
Папка `html/index.html`:
```html
<!DOCTYPE html>
<html lang="ru">
<head><meta charset="utf-8"><title>Docker COPY demo</title></head>
<body><h1>Файл попал в образ через COPY</h1></body>
</html>
```
Сборка и запуск:
```
docker build -t my-web:1.0 .
docker run -d --name from-dockerfile -p 8090:80 my-web:1.0
```
**Скриншот:** этапы сборки `Step ...` и успешное `Successfully tagged my-web:1.0`.
<img src="./assets/docker_build_steps_tagged.png" width="auto">
**Скриншот:** браузер на порту 8090 с вашим заголовком.
<img src="./assets/docker_browser_copy_demo.png" width="auto">
---
## `.dockerignore` — что не отправлять в демон при сборке
В корне контекста создайте `.dockerignore`, чтобы не копировать мусор и секреты:
```
.git
.env
*.log
node_modules
__pycache__
```
**Скриншот:** сравнение размера контекста в логе сборки до/после добавления `.dockerignore` (если делали большую папку).
<img src="./assets/docker_dockerignore_context_smaller.png" width="auto">
---
## 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).
<img src="./assets/docker_multistage_image_size.png" width="auto">
---
## Передача секретов при сборке (обзорно)
Не кладите пароли в `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 history my-web:1.0
```
**Скриншот:** список слоёв и размеров.
<img src="./assets/docker_history_layers.png" width="auto">
---
## Связь с Compose
В `docker-compose.yml` можно указать `build: .` для сервиса — Compose вызовет `docker build` с нужным контекстом. Полный стек — в части **4** и в каталоге `docker/examples/multi-service/`.