Готовый образ содержит чужую программу. Чтобы передать собственный скрипт вместе с окружением, нужно собрать образ проекта. Dockerfile хранит рецепт этой сборки: основу, файлы, зависимости и команду запуска.
Минимальный проект
Начнём с программы, которая печатает подготовленный отчёт. В отдельной папке создайте два файла. В учебном терминале они уже есть:
version=1FROM alpine:3.21
WORKDIR /app
COPY report.txt /app/report.txt
CMD ["cat", "/app/report.txt"]FROM выбирает основу. WORKDIR задаёт рабочую папку для следующих инструкций и запуска. COPY помещает файл проекта в образ. CMD задаёт команду по умолчанию, которая выполнится при создании контейнера. Форма JSON-массива запускает cat напрямую; оболочка для неё не требуется.
docker build -t demo-report:1 .
docker run --name demo-first demo-report:1Точка в конце build задаёт контекст сборки, каталог файлов, доступных сборщику. Из него COPY забирает report.txt. -t присваивает образу имя с тегом. Контейнер напечатает version=1 и завершится.
Что происходит при изменении файла
printf version=2 > report.txt
docker build -t demo-report:2 .
docker run --name demo-second demo-report:2
docker start demo-first
docker logs demo-firstНовый контейнер напечатает version=2. Старый demo-first снова выполнит свою команду, а его журнал пополнится строкой version=1: он создан из прежнего образа. COPY сделал снимок файла при сборке. Чтобы контейнер читал текущие файлы компьютера, вместо копирования используют bind mount при запуске.
Так разделяются изменения кода и изменения входных данных. Новую версию программы собирают в новый образ. Ежедневный CSV можно подключать к той же программе отдельно, не пересобирая её для каждой поставки.
Как этот рецепт выглядит для Python
У обработчика данных вместо cat будет интерпретатор. Например, если рядом с Dockerfile лежат pipeline.py и requirements.txt:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY pipeline.py .
CMD ["python", "pipeline.py"]RUN выполняется во время сборки и устанавливает библиотеки в образ. CMD сохраняется как настройка будущего запуска. При docker run повторно устанавливать зависимости не потребуется.
Сначала копируется список зависимостей, затем код. Если изменился только pipeline.py, сборщик может повторно использовать уже готовый слой с библиотеками. Если изменился requirements.txt, слой установки будет собран заново. Это кеш сборки: порядок инструкций влияет на объём повторной работы.
Контекст и команда запуска
Файл .dockerignore исключает из контекста ненужное: например, .git, локальное окружение .venv и большие выгрузки. Это уменьшает передачу файлов сборщику. Пароли и токены в образ не копируют: удаление секрета следующим шагом может оставить его в предыдущем слое.
Команда после имени образа переопределяет CMD:
docker run --rm demo-report:2 cat /etc/hostnameДля образов с ENTRYPOINT правила другие: эта инструкция задаёт исполняемую программу, а аргументы после имени образа обычно заменяют аргументы CMD. Поэтому перед переопределением запуска полезно посмотреть Dockerfile или настройки образа.
Попробуйте в учебном терминале
В папке report подготовлены Dockerfile и report.txt. Соберите первую версию, запустите её и выпустите вторую. Проверка сравнит файлы в двух экземплярах: изменение исходника должно попасть только в новую сборку. Эмулятор выполняет этот пример с cat; Python-рецепт выше предназначен для настоящего Docker.
Здесь команды Docker имитируются: терминал хранит учебное состояние образов, контейнеров и файлов. Реальные службы и внешнюю сеть он не запускает.
- 1. Соберите образ report:1 из текущего каталога.
- 2. Запустите report:1 с именем report-first и проверьте скопированный /app/report.txt.
- 3. Измените report.txt на version=2, соберите report:2 и запустите report-second. Старый образ и файл report-first должны остаться прежними.