Свой образ: Dockerfile
Dockerfile — это текстовый файл с рецептом образа. Каждая строка — один шаг. Командой docker build Docker читает рецепт и собирает образ.
Так вы упаковываете свой скрипт или пайплайн, чтобы он работал одинаково на любом компьютере.
Инструкции
Заголовок раздела «Инструкции»| Инструкция | Что делает |
|---|---|
FROM | Берёт готовый образ за основу. Всегда первая строка |
WORKDIR | Задаёт рабочую папку в образе. Если её нет, создаёт |
COPY | Копирует файлы с вашего компьютера в образ |
RUN | Выполняет команду при сборке (например, pip install) |
ENV | Задаёт переменную окружения |
CMD | Команда, которая запускается при старте контейнера |
ENTRYPOINT | Программа, которая запускается при старте. CMD становится её аргументами |
RUN работает один раз, при сборке. CMD работает каждый раз, когда вы запускаете контейнер.
Первый образ
Заголовок раздела «Первый образ»Учебный скрипт app/report.py читает orders.csv и печатает выручку по каналам. Ему нужен только Python. Упакуем его.
Перейдите в папку курса и создайте файл Dockerfile:
cd ~/docker-practiceFROM python:3.12-slimWORKDIR /appCOPY app/ .CMD ["python", "report.py"]Что здесь происходит:
- Берём
python:3.12-slim. В нём уже есть Python. - Рабочая папка в образе —
/app. - Копируем всё из папки
app/с вашего компьютера в/app. - При старте запускаем
python report.py.
Соберите образ:
docker build -t orders-report:1.0 .-t orders-report:1.0— имя и тег образа.- Точка
.в конце — контекст сборки. Это папка, из которойCOPYберёт файлы. Точка — текущая папка.
В конце вы увидите:
=> naming to docker.io/library/orders-report:1.0Проверьте:
docker images orders-reportREPOSITORY TAG IMAGE ID CREATED SIZEorders-report 1.0 57062938303c ... 145MBЗапуск и данные
Заголовок раздела «Запуск и данные»Запустите образ и подключите данные через bind mount (урок про тома):
docker run --rm -v "$PWD/data:/data" orders-report:1.0Файл: /data/orders.csvЗаказов: 500Выручка по каналам (только completed): organic 23715.82 ads 23082.74 email 15459.67Мы не положили orders.csv в образ. Данные меняются, а образ — это программа. Данные подключают снаружи.
Что будет без данных
Заголовок раздела «Что будет без данных»Запустите без -v:
docker run --rm orders-report:1.0Traceback (most recent call last): File "/app/report.py", line 11, in <module> with open(path, newline="") as f: ^^^^^^^^^^^^^^^^^^^^^^FileNotFoundError: [Errno 2] No such file or directory: '/data/orders.csv'Скрипт ищет /data/orders.csv, а в контейнере такой папки нет. Это ошибка в запуске, а не в образе.
Путь к файлу скрипт берёт из переменной ORDERS_PATH. Её можно поменять без пересборки:
docker run --rm -v "$PWD/data:/mnt" -e ORDERS_PATH=/mnt/orders.csv orders-report:1.0Первая строка ответа теперь Файл: /mnt/orders.csv.
Хотите задать путь по умолчанию в образе? Добавьте в Dockerfile строку ENV ORDERS_PATH=/data/orders.csv. Флаг -e при запуске всё равно её перекроет.
CMD и ENTRYPOINT
Заголовок раздела «CMD и ENTRYPOINT»CMD — команда по умолчанию. Её легко заменить при запуске:
docker run --rm orders-report:1.0 python --versionPython 3.12.16Всё, что вы пишете после имени образа, заменяет CMD. Версия Python у вас может быть другой.
docker run --rm orders-report:1.0 lsload_orders.pyreport.pyrequirements.txtТак видно, что WORKDIR /app работает: ls показывает файлы в /app. Здесь же лежит load_orders.py. Мы запустим его позже, в Compose.
ENTRYPOINT — программа, которая запускается всегда. То, что вы пишете после имени образа, превращается в её аргументы.
ENTRYPOINT ["python"]CMD ["report.py"]| Команда | Что запустится |
|---|---|
docker run образ | python report.py |
docker run образ --version | python --version |
docker run образ other.py | python other.py |
Так устроены образы-инструменты: dbt, aws, terraform. Образ — это сама программа, вы передаёте ей аргументы. Для обычного приложения хватает CMD.
Форма exec и форма shell
Заголовок раздела «Форма exec и форма shell»Команду пишут двумя способами:
| Форма | Пример | Когда |
|---|---|---|
| exec | CMD ["python", "report.py"] | Всегда по умолчанию. Программа получает сигналы (docker stop) напрямую |
| shell | CMD python report.py | Docker запускает /bin/sh -c. Сигнал получает shell, а не ваша программа |
С формой shell docker stop может ждать 10 секунд и убить программу принудительно. Пишите форму exec: квадратные скобки и двойные кавычки.
Слои и history
Заголовок раздела «Слои и history»Каждая инструкция делает слой образа. Посмотрите их:
docker history orders-report:1.0CREATED BY SIZECMD ["python" "report.py"] 0BCOPY app/ . # buildkit 1.9kBWORKDIR /app 0BCMD ["python3"] 0B...Ваши три слоя — сверху. Ниже идут слои базового образа Python. Наш код весит 1.9 КБ. Остальные 145 МБ — это Python.
Слои кэшируются. Как этим пользоваться — в следующем уроке.
Практика
Заголовок раздела «Практика»Работайте в папке ~/docker-practice.
Задание 1
Заголовок раздела «Задание 1»Создайте Dockerfile для report.py, как выше. Соберите образ orders-report:1.0. Запустите его с данными.
Проверка:
Файл: /data/orders.csvЗаказов: 500Выручка по каналам (только completed): organic 23715.82 ads 23082.74 email 15459.67Решение
FROM python:3.12-slimWORKDIR /appCOPY app/ .CMD ["python", "report.py"]docker build -t orders-report:1.0 .docker run --rm -v "$PWD/data:/data" orders-report:1.0Задание 2
Заголовок раздела «Задание 2»Запустите образ без -v. Прочитайте ошибку. Исправьте запуск, не меняя образ.
Проверка: сначала FileNotFoundError ... '/data/orders.csv'. После исправления — отчёт.
Решение
Добавьте -v "$PWD/data:/data". Образ менять не нужно: он не содержит данных.
Задание 3
Заголовок раздела «Задание 3»Запустите образ, но вместо отчёта выведите версию Python.
Проверка: Python 3.12.x.
Решение
docker run --rm orders-report:1.0 python --versionЗадание 4
Заголовок раздела «Задание 4»Соберите образ с тегом orders-report:2.0, у которого ORDERS_PATH по умолчанию равен /data/orders.csv, добавив ENV. Проверьте, какие переменные заданы в образе.
Проверка: в списке Env есть ORDERS_PATH=/data/orders.csv.
Решение
Добавьте строку ENV ORDERS_PATH=/data/orders.csv после FROM. Затем:
docker build -t orders-report:2.0 .docker image inspect orders-report:2.0 --format '{{.Config.Env}}'В выводе будет и PATH, и другие переменные базового образа. Найдите нужную.
Задание 5
Заголовок раздела «Задание 5»Сколько строк в docker history создали вы сами, а сколько пришло из python:3.12-slim? Какие ваши слои весят 0B?
Проверка: ваших слоёв три: WORKDIR, COPY, CMD. WORKDIR и CMD весят 0B.
Решение
docker history orders-report:1.0Строка CMD ["python3"] и всё ниже пришло из базового образа.
Дальше: Хороший образ.