Пошук уроків, статей та іншого контенту
Навчитеся використовувати FROM, WORKDIR, COPY, ADD, RUN, EXPOSE і USER для опису середовища та застосунку.
Dockerfile — це текстовий файл з інструкціями для створення Docker-образу. Кожна інструкція описує частину середовища:
базовий образ;
робочу директорію;
файли застосунку;
встановлення залежностей;
порт застосунку;
користувача, від імені якого працює процес.
Docker читає інструкції зверху вниз і створює образ пошарово. Кожен шар може використовуватися повторно під час наступних збірок.
FROMFROM задає базовий образ, з якого починається створення нового образу.
FROM python:3.12-slimУ цьому прикладі базовим образом є мінімальна версія Python 3.12.
Інші приклади:
FROM node:22
FROM nginx:alpine
FROM ubuntu:24.04FROM зазвичай є першою інструкцією у Dockerfile. Базовий образ повинен містити середовище, необхідне для роботи застосунку.
WORKDIRWORKDIR задає поточну робочу директорію всередині контейнера:
WORKDIR /appПісля цього:
наступні RUN виконуються в /app;
файли через COPY або ADD можна копіювати відносно /app;
команда запуску контейнера за замовчуванням також працює з /app.
Якщо директорії /app ще немає, Docker створить її автоматично.
Замість зміни директорії через команди на кшталт RUN cd /app потрібно використовувати WORKDIR. Зміна директорії в одному RUN не зберігається для наступних інструкцій:
RUN cd /app
RUN pwdУ другому RUN робочою директорією не обов’язково буде /app. Правильний варіант:
WORKDIR /app
RUN pwdCOPYCOPY копіює файли або директорії з контексту збірки до образу.
COPY server.py .Крапка означає поточну робочу директорію, тобто /app, якщо перед цим використано:
WORKDIR /appТоді файл server.py буде скопійовано до /app/server.py.
Можна також вказати повний шлях призначення:
COPY package.json /app/
COPY src/ /app/src/Файли для COPY повинні знаходитися в контексті збірки. Якщо образ збирається командою:
docker build -t my-app .то контекстом є поточна директорія ., і Docker може копіювати файли лише з неї або її піддиректорій.
COPY package.json package-lock.json ./Це скопіює обидва файли до поточної робочої директорії.
COPYCOPY має просту і зрозумілу поведінку: він лише копіює файли. Для більшості випадків цього достатньо, тому COPY є кращим вибором для звичайних файлів застосунку.
ADDADD також копіює файли до образу, але має додаткові можливості.
ADD message.txt /app/message.txtДля звичайного копіювання ADD і COPY працюють подібно. Проте ADD додатково може автоматично розпаковувати локальні архіви деяких форматів, наприклад tar-архіви:
ADD assets.tar.gz /app/assets/Якщо assets.tar.gz є локальним архівом, його вміст буде розпаковано в /app/assets/.
Для звичайного копіювання файлів переважно використовувати COPY, а ADD залишати для випадків, коли потрібне автоматичне розпакування архіву. Так поведінка Dockerfile залишається очевиднішою.
RUNRUN виконує команду під час створення образу.
Наприклад, встановлення системного пакета:
RUN apt-get update && apt-get install -y curlАбо встановлення залежностей Python:
RUN pip install --no-cache-dir -r requirements.txtРезультат RUN зберігається в образі. Команда виконується під час docker build, а не під час кожного запуску контейнера.
Якщо кілька команд є частиною одного кроку, їх можна об’єднати:
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*Оператор && запускає наступну команду лише тоді, коли попередня завершилася успішно.
Очищення списків пакетів зменшує розмір фінального шару образу.
RUN від запуску контейнераRUN python --versionЦя команда виконується під час створення образу.
Запуск застосунку під час роботи контейнера зазвичай описують окремою інструкцією, наприклад:
CMD ["python", "server.py"]У цьому уроці CMD потрібна лише для повного прикладу запуску застосунку.
EXPOSEEXPOSE документує порт, який використовує застосунок у контейнері:
EXPOSE 8000Ця інструкція:
не відкриває порт автоматично;
не публікує порт на комп’ютері;
повідомляє Docker та іншим розробникам, який порт очікує застосунок.
Щоб зробити порт доступним з операційної системи, під час запуску потрібно використати -p:
docker run --rm -p 8000:8000 my-python-appУ цьому записі:
перше 8000 — порт на комп’ютері;
друге 8000 — порт усередині контейнера.
Застосунок у контейнері повинен слухати адресу 0.0.0.0, а не лише localhost. Інакше він може бути недоступним через опублікований порт.
USERUSER задає користувача або групу, від імені яких виконуються наступні інструкції та запускається контейнер.
USER appuserЯкщо USER не вказано, процес зазвичай працює від імені root. Для застосунків краще створити окремого користувача з обмеженими правами.
Користувача можна створити через RUN:
RUN useradd --create-home --shell /usr/sbin/nologin appuser
USER appuserІнструкцію USER часто розміщують ближче до кінця Dockerfile. Команди, яким потрібні права адміністратора, наприклад встановлення пакетів або створення користувача, потрібно виконати до USER.
Якщо застосунок повинен записувати файли, користувач має мати відповідні права:
RUN chown -R appuser:appuser /app
USER appuserСтворимо простий Python-сервер, який повертає файл message.txt.
Структура проєкту:
my-python-app/
├── Dockerfile
├── message.txt
└── server.pyФайл server.py:
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
server = ThreadingHTTPServer(("0.0.0.0", 8000), SimpleHTTPRequestHandler)
server.serve_forever()Файл message.txt:
Привіт із Docker-контейнера!Файл Dockerfile:
FROM python:3.12-slim
WORKDIR /app
COPY server.py .
ADD message.txt .
RUN useradd --create-home --shell /usr/sbin/nologin appuser \
&& chown -R appuser:appuser /app
EXPOSE 8000
USER appuser
CMD ["python", "server.py"]У цьому прикладі:
FROM додає Python-середовище.
WORKDIR встановлює /app як робочу директорію.
COPY копіює файл сервера.
ADD копіює текстовий файл.
RUN створює користувача та змінює власника файлів.
EXPOSE описує порт 8000.
USER перемикає контейнер на непривілейованого користувача.
CMD запускає сервер.
Виконайте команду з директорії, де розташований Dockerfile:
docker build -t my-python-app .Крапка в кінці означає, що поточна директорія буде контекстом збірки.
docker run --rm -p 8000:8000 my-python-appПісля запуску файл буде доступний за адресою:
http://localhost:8000/message.txtЗупинити контейнер можна комбінацією Ctrl+C.
Docker кешує результати окремих інструкцій. Якщо змінюється інструкція або файл, від якого вона залежить, відповідний шар і наступні шари можуть бути створені повторно.
Наприклад:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "server.py"]Залежності копіюються та встановлюються окремо від коду. Якщо зміниться лише код, Docker зможе використати кеш для кроку встановлення залежностей.
Для маленького прикладу з одним файлом можна використовувати простішу структуру:
FROM python:3.12-slim
WORKDIR /app
COPY . .
CMD ["python", "server.py"]EXPOSE автоматично відкриє портEXPOSE 8000Цього недостатньо для доступу з комп’ютера. Порт потрібно опублікувати під час запуску:
docker run -p 8000:8000 my-python-applocalhost у сервері контейнераСервер, який слухає лише 127.0.0.1 або localhost, може бути недоступним ззовні контейнера.
Для мережевого сервера використовуйте:
("0.0.0.0", 8000)Команда:
COPY . .копіює весь контекст збірки. До нього можуть потрапити:
.git;
локальні залежності;
тимчасові файли;
секрети;
великі каталоги.
Файл .dockerignore допомагає виключити непотрібні файли з контексту:
.git
__pycache__
*.log
.envRUN cdТакий запис не встановлює робочу директорію для всього Dockerfile:
RUN cd /appЗамість нього використовуйте:
WORKDIR /approotЯкщо застосунку не потрібні адміністративні права, не залишайте його запущеним від імені root. Створіть окремого користувача через RUN і виберіть його через USER.
ADD для звичайних файлівADD працює для простого копіювання, але його додаткові можливості можуть бути неочевидними. Для звичайних файлів краще використовувати:
COPY config.json /app/ADD варто використовувати тоді, коли потрібна його спеціальна поведінка, наприклад автоматичне розпакування локального tar-архіву.
FROM вибирає базовий образ.
WORKDIR задає робочу директорію контейнера.
COPY копіює файли з контексту збірки.
ADD також копіює файли та може автоматично розпаковувати локальні tar-архіви.
RUN виконує команди під час створення образу.
EXPOSE документує порт контейнера, але не публікує його.
USER задає користувача для наступних інструкцій і запуску контейнера.
Для звичайного копіювання переважно використовуйте COPY.
Для доступу до застосунку з комп’ютера публікуйте порт через docker run -p.
Для безпечнішого запуску застосунку використовуйте непривілейованого користувача.