Пошук уроків, статей та іншого контенту
Розберете формат Dockerfile, порядок інструкцій і принцип побудови образу з базового образу та шарів.
Dockerfile — це текстовий файл з інструкціями, за якими Docker створює образ.
Образ будується послідовно:
Docker бере базовий образ.
Виконує інструкції з Dockerfile зверху вниз.
Додає файли, встановлює залежності та налаштовує середовище.
Зберігає результат як новий образ.
Контейнер запускається вже з готового образу.
Мінімальний Dockerfile може виглядати так:
FROM python:3.12-slim
WORKDIR /app
COPY app.py .
CMD ["python", "app.py"]Кожен рядок зазвичай містить інструкцію та її аргументи:
ІНСТРУКЦІЯ аргументиНазви інструкцій не залежать від регістру, але зазвичай їх пишуть великими літерами:
FROM python:3.12-slim
WORKDIR /appПорожні рядки ігноруються. Коментарі починаються із символу #:
# Використовуємо офіційний образ Python
FROM python:3.12-slimІнструкції виконуються в тому порядку, у якому вони записані. Тому порядок рядків у Dockerfile має значення.
Інструкція FROM визначає базовий образ:
FROM python:3.12-slimУ цьому прикладі:
python — назва образу;
3.12-slim — його тег;
базовий образ містить Linux-середовище та Python.
FROM зазвичай є першою інструкцією в Dockerfile. Вона визначає початковий стан майбутнього образу.
Інші приклади базових образів:
FROM node:22
FROM nginx:alpine
FROM ubuntu:24.04Для навчальних прикладів краще явно вказувати тег, а не покладатися на неявне значення latest.
WORKDIR задає поточну директорію всередині образу та контейнера:
WORKDIR /appПісля цього наступні інструкції працюють у /app.
Наприклад:
WORKDIR /app
COPY app.py .Файл app.py буде скопійовано до /app/app.py.
Якщо директорії /app ще не існує, Docker створить її. Тому зазвичай не потрібно окремо використовувати RUN mkdir /app.
WORKDIR також визначає директорію, з якої за замовчуванням запускатиметься команда контейнера.
COPY переносить файли з контексту складання до образу:
COPY app.py .Формат інструкції:
COPY джерело призначенняКрапка . у цьому прикладі означає поточну робочу директорію, тобто /app.
Можна скопіювати всю програму:
COPY . .Тут:
перша крапка — поточна директорія на комп’ютері;
друга крапка — поточна директорія всередині образу.
Однак копіювати всі файли одразу не завжди варто. До образу можуть потрапити непотрібні файли: локальні залежності, журнали, тимчасові файли або налаштування середовища.
RUN виконує команду під час створення образу:
RUN python --versionРезультат виконання команди зберігається в образі. Найчастіше RUN використовують для встановлення пакетів і підготовки середовища:
RUN apt-get update && apt-get install -y curlКожна окрема інструкція RUN створює додатковий шар. Тому пов’язані команди часто об’єднують:
RUN apt-get update && \
apt-get install -y curlСимвол \ переносить одну команду на кілька рядків.
Важливо відрізняти RUN від CMD:
RUN виконується під час складання образу;
CMD виконується під час запуску контейнера.
EXPOSE описує порт, який використовує програма в контейнері:
EXPOSE 8000Ця інструкція є документацією для образу. Вона не публікує порт автоматично.
Щоб зробити порт доступним із хост-комп’ютера, під час запуску контейнера потрібно вказати параметр -p:
docker run --rm -p 8000:8000 my-python-appУ цьому прикладі:
перший 8000 — порт на хост-комп’ютері;
другий 8000 — порт усередині контейнера.
CMD визначає стандартну команду, яка виконується під час запуску контейнера:
CMD ["python", "app.py"]Для команд запуску рекомендують JSON-форму:
CMD ["команда", "аргумент1", "аргумент2"]Така форма передає команду безпосередньо процесу і коректно обробляє аргументи.
У Dockerfile може бути кілька інструкцій RUN, але стандартною є лише остання інструкція CMD. Якщо вказати кілька CMD, попередні будуть замінені останньою.
Команду з CMD можна замінити під час запуску:
docker run --rm my-python-app python --versionУ цьому випадку замість python app.py виконається python --version.
Створімо простий HTTP-сервер на Python.
Структура проєкту:
my-python-app/
├── Dockerfile
└── app.pyФайл app.py:
from http.server import BaseHTTPRequestHandler, HTTPServer
class RequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
message = b"Hello from Docker!\n"
self.send_response(200)
self.send_header("Content-Type", "text/plain; charset=utf-8")
self.send_header("Content-Length", str(len(message)))
self.end_headers()
self.wfile.write(message)
def log_message(self, format, *args):
# Виводимо стандартні журнали запитів
print(format % args)
server = HTTPServer(("0.0.0.0", 8000), RequestHandler)
print("Server is running on port 8000")
server.serve_forever()Файл Dockerfile:
# Беремо базовий образ із Python
FROM python:3.12-slim
# Усі наступні операції виконуються в цій директорії
WORKDIR /app
# Копіюємо файл програми в образ
COPY app.py .
# Документуємо порт, який використовує програма
EXPOSE 8000
# Запускаємо програму під час старту контейнера
CMD ["python", "app.py"]Команду docker build потрібно виконувати з директорії, де розташовані Dockerfile і app.py:
docker build -t my-python-app .Розберімо команду:
docker build — створює образ;
-t my-python-app — задає ім’я образу;
. — передає поточну директорію як контекст складання.
Контекст складання — це файли, доступні інструкціям COPY і ADD. У цьому прикладі Docker може використати app.py з поточної директорії.
Після створення образу запустіть контейнер:
docker run --rm -p 8000:8000 my-python-appПараметр --rm автоматично видалить контейнер після його зупинки.
Параметр -p 8000:8000 з’єднує порт хост-комп’ютера з портом контейнера.
Після запуску програма буде доступна за адресою:
http://localhost:8000Зупинити контейнер можна комбінацією Ctrl+C.
Образ складається з базового образу та змін, які додають інструкції Dockerfile.
Для такого файлу:
FROM python:3.12-slim
WORKDIR /app
COPY app.py .
CMD ["python", "app.py"]можна уявити побудову так:
базовий шар python:3.12-slim;
робоча директорія /app;
шар із файлом app.py;
налаштування стандартної команди запуску.
Шари дають змогу Docker повторно використовувати незмінені частини образу. Це пришвидшує наступні складання та заощаджує дисковий простір.
Docker кешує результати інструкцій. Якщо певний крок і всі попередні дані не змінилися, Docker може використати готовий результат замість повторного виконання.
Це особливо важливо для залежностей. Наприклад, недоцільно копіювати весь проєкт перед встановленням залежностей:
FROM python:3.12-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txtЗміна будь-якого файлу проєкту змусить Docker повторно виконати RUN pip install.
Краще спочатку копіювати файл залежностей, встановити їх, а потім додати решту коду:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]Тепер зміна файлів програми не змінює шар із requirements.txt, тому Docker може використати кеш для встановлення залежностей.
Для цього прикладу файл requirements.txt має існувати, навіть якщо залежностей немає:
У простому Dockerfile часто використовують такий порядок:
FROM — вибір базового образу;
WORKDIR — робоча директорія;
COPY — копіювання файлів, необхідних для встановлення залежностей;
RUN — встановлення залежностей або виконання підготовчих команд;
COPY — копіювання коду програми;
EXPOSE — опис порту;
CMD — стандартна команда запуску.
Це не єдина можлива послідовність, але вона добре підходить для більшості простих застосунків.
Команда:
docker build -t my-python-app .шукає Dockerfile у поточній директорії. Якщо файл розташований в іншому місці, потрібно перейти до відповідної директорії або явно вказати шлях до нього.
Якщо написано:
COPY app.py .файл app.py має бути доступним у контексті складання. Docker не може скопіювати файл, який розташований за межами контексту.
Інструкція:
EXPOSE 8000не публікує порт на хост-комп’ютері. Під час запуску потрібно додати:
-p 8000:8000localhost для сервера в контейнеріСервер усередині контейнера має слухати адресу 0.0.0.0, щоб приймати з’єднання через мережу контейнера:
server = HTTPServer(("0.0.0.0", 8000), RequestHandler)Якщо сервер слухає лише 127.0.0.1, він може бути недоступним ззовні контейнера.
Неправильно використовувати CMD для встановлення залежностей:
CMD ["pip", "install", "-r", "requirements.txt"]Залежності потрібно встановлювати під час створення образу за допомогою RUN. CMD призначений для запуску програми в готовому контейнері.
Інструкція:
COPY . .копіює все з контексту. Перед її використанням варто перевірити, що в директорії немає непотрібних або конфіденційних файлів.
Dockerfile містить послідовність інструкцій для створення образу.
FROM визначає базовий образ.
WORKDIR задає робочу директорію.
COPY додає файли до образу.
RUN виконує команди під час створення образу.
EXPOSE описує порт контейнера, але не публікує його.
CMD визначає стандартну команду запуску контейнера.
Інструкції виконуються зверху вниз.
Образ складається з базового образу та шарів.
Правильний порядок інструкцій допомагає ефективно використовувати кеш Docker.