Що таке Dockerfile?
Це декларативний файл: ви описуєте, яким має бути образ, а Docker сам вирішує, як його зібрати. Це як рецепт: ви пишете кроки, а Docker збирає з них готовий образ, який можна за...
🟢 Junior Level
Просте пояснення
Dockerfile — це текстовий файл з інструкціями для створення Docker-образу.
Це декларативний файл: ви описуєте, яким має бути образ, а Docker сам вирішує, як його зібрати. Це як рецепт: ви пишете кроки, а Docker збирає з них готовий образ, який можна запустити як контейнер.
Аналогія
Dockerfile — це кулінарний рецепт. FROM — це основа (наприклад, тісто), COPY — додавання інгредієнтів, RUN — приготування, ENTRYPOINT — спосіб подачі страви. З одного рецепту можна приготувати скільки завгодно однакових страв (контейнерів).
Приклад
# 1. Базовий образ
FROM openjdk:17-jdk-slim
# 2. Робоча директорія
WORKDIR /app
# 3. Копіювання файлу
COPY myapp.jar app.jar
# 4. Порт додатку
EXPOSE 8080
# 5. Команда запуску
ENTRYPOINT ["java", "-jar", "app.jar"]
# Зібрати образ з Dockerfile
docker build -t myapp .
# Запустити контейнер
docker run -p 8080:8080 myapp
Основні інструкції
| Інструкція | Що робить |
|---|---|
FROM |
Вказує базовий образ (наприклад, openjdk:17) |
WORKDIR |
Задає робочу директорію |
COPY |
Копіює файли в образ |
RUN |
Виконує команду при збірці |
EXPOSE |
Вказує порт додатку |
ENTRYPOINT |
Команда запуску додатку |
Що запам’ятати
- Dockerfile — це рецепт для створення Docker-образу
- Кожна інструкція створює новий шар в образі
FROM— завжди перша інструкція- Використовуйте конкретні версії образів, а не
latest docker buildзбирає образ,docker runзапускає контейнер
Коли НЕ потрібен Dockerfile
Якщо використовуєте platform-as-a-service (Heroku, Railway, Render), Dockerfile може не знадобитися – платформа сама збирає образ з коду.
🟡 Middle Level
Як працює збірка образу
Коли ви запускаєте docker build .:
- Docker-клієнт передає вміст поточної папки (Build Context) Docker-демону.
- Демон покроково виконує інструкції з Dockerfile.
- Кожна інструкція створює новий шар (layer) в образі.
- Шари кешуються — якщо інструкція не змінилася, Docker використовує кеш.
Build Context і .dockerignore
Build Context — це весь вміст директорії, переданий Docker. Щоб не передавати зайві файли (.git, target/, логи), використовуйте .dockerignore:
.git
target/
*.log
.idea/
Поняття шарів (Layers) і кешування
Docker використовує шарувату файлову систему (UnionFS/Overlay2):
- Кожна команда (
RUN,COPY,ADD) створює новий шар - Шари кешуються — якщо інструкція і файли не змінилися, Docker бере готовий шар з кешу
Правило оптимізації: Розміщуйте рідко змінювані інструкції на початку, часто змінювані — в кінці.
# ПОГАНО: при кожній зміні коду кеш залежностей скидається
COPY src /app/src
COPY pom.xml /app
RUN mvn -f /app/pom.xml clean package
# ДОБРЕ: залежності кешуються окремо
COPY pom.xml /app
RUN mvn -f /app/pom.xml dependency:go-offline
// Docker кешує шар, якщо інструкція і УСІ попередні шари не змінилися.
// Змінився pom.xml -- інвалідація всіх наступних шарів.
COPY src /app/src
RUN mvn -f /app/pom.xml clean package
Типові помилки
| Помилка | Наслідок | Як уникнути |
|---|---|---|
FROM openjdk:latest |
Недетерміновані збірки | FROM openjdk:17-jdk-slim |
Немає .dockerignore |
Повільна збірка, великі образи | Створіть .dockerignore |
| Усі команди в одному RUN | Неможливо використовувати кеш частково | Розділяйте логічні кроки |
| Запуск додатку від root | Ризик безпеки | USER appuser |
| Один величезний шар | Немає кешування, повільний rebuild | Розділяйте залежності і код |
Основні принципи хорошого Dockerfile
- Єдина відповідальність — один контейнер, один процес.
- Мінімізація розміру — використовуйте легкі базові образи (
alpine,slim,distroless).
Alpine – мінімальний Linux-дистрибутив (~5 МБ), часто використовується як база для образів.
- Безпека — не запускайте додаток від
root. ВикористовуйтеUSER. - Конкретні версії — завжди вказуйте точні версії базових образів.
Multi-stage build
Дозволяє компілювати код в одному тимчасовому образі, а у фінальний копіювати лише артефакт:
# Stage 1: Build
FROM maven:3.8-openjdk-17 AS build
COPY src /app/src
COPY pom.xml /app
RUN mvn -f /app/pom.xml clean package -DskipTests
# Stage 2: Runtime
FROM openjdk:17-jdk-slim
COPY --from=build /app/target/app.jar /app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]
Що запам’ятати
- Кожна інструкція = новий шар
- Кешування — ключ до швидкої збірки
- Порядок інструкцій важливий для продуктивності
- Використовуйте
.dockerignoreдля виключення зайвих файлів - Multi-stage build — стандарт для продакшен-образів
🔴 Senior Level
Dockerfile як Infrastructure as Code
Dockerfile — це не просто скрипт збірки, це фундамент Infrastructure as Code (IaC) для рівня додатків. Він визначає відтворюваність, безпеку і ефективність доставки ПЗ.
Глибокий аналіз процесу збірки
Build Context і його вплив на CI/CD
docker build . → tar-архів усієї директорії → відправка Docker daemon
Проблеми: великий контекст = повільна відправка (особливо в remote daemon). .dockerignore працює як .gitignore, але для Docker. В CI/CD контекст може включати артефакти попередніх збірок.
Best Practice:
# Виключаємо все, крім потрібного
**
!src/
!pom.xml
!Dockerfile
Механізм кешування: глибоке розуміння
Docker обчислює хеш кожного шару на основі: самої інструкції, хешів попередніх шарів, вмісту файлів (для COPY і ADD).
Кеш інвалідація відбувається коли: змінилася інструкція, змінилися файли, що копіюються, змінився хеш батьківського шару.
Патерн “Dependency Layer” для Java:
FROM maven:3.8-openjdk-17 AS build
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline -B # рідко змінюється → кешується
COPY src ./src
RUN mvn package -DskipTests # часто змінюється
Це дає 90%+ hit rate кешу при збірках без зміни залежностей.
Trade-offs
| Рішення | Плюс | Мінус |
|---|---|---|
| Alpine-образи | Мінімальний розмір (~5MB base) | musl libc ≠ glibc, проблеми з native libraries |
| Slim-образи | glibc сумісність, маленький розмір | Більші за alpine |
| Distroless | Мінімальна поверхня атаки | Немає shell для налагодження, потрібні ephemeral debug containers |
| Багато шарів | Краще кешування | Більше мета-даних, повільніший pull |
| Мало шарів | Швидкий pull | Гірше кешування |
Edge Cases
- Alpine + native libraries: Alpine використовує musl libc. JNI-бібліотеки (Netty epoll, PostgreSQL native) можуть вимагати glibc. Рішення: використовуйте
debian-slimабо збирайте під musl. - Таймаути при збірці:
RUN apt-get updateможе зависнути через мережеві проблеми. Рішення: використовуйте дзеркала, retry-логіку. - Non-deterministic builds:
apt-get updateбез фіксації версій пакетів дає різні результати. Рішення:apt-get install -y package=1.2.3-1. - Cross-platform builds: Збірка amd64 образу на ARM (Apple Silicon). Рішення:
docker buildxз QEMU емуляцією або remote builders.
Безпека Dockerfile
# Production-ready Dockerfile для Spring Boot
FROM maven:3.9-eclipse-temurin-17 AS build
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn package -DskipTests -B
FROM eclipse-temurin:17-jre-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
WORKDIR /app
COPY --from=build /build/target/*.jar app.jar
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget -qO- http://localhost:8080/actuator/health || exit 1
ENTRYPOINT ["java", "-XX:+UseG1GC", "-jar", "app.jar"]
Критичні правила:
- Не використовуйте
latest - Не запускайте від root
- Read-only filesystem де можливо
- Мінімізуйте поверхню атаки
- Використовуйте
HEALTHCHECK
Вплив на CI/CD pipeline
developer → git push → CI запускає docker build →
cache hit? → швидко (секунди) : повільно (хвилини) →
docker push → CD деплоїть
Оптимізація CI: registry cache (pull попереднього образу), BuildKit cache, layer sharing між образами.
BuildKit (Docker 23+): паралельне виконання незалежних кроків, secret-менеджмент (--mount=type=secret), SSH forwarding (--mount=type=ssh), cache mounts (--mount=type=cache).
Продуктивність
| Базовий образ | Розмір | Час pull | Час start |
|---|---|---|---|
openjdk:17 |
~500 МБ | ~30s | ~5s |
openjdk:17-slim |
~300 МБ | ~15s | ~5s |
eclipse-temurin:17-jre-alpine |
~100 МБ | ~5s | ~4s |
distroless/java17 |
~80 МБ | ~4s | ~4s |
Моніторинг
docker history <image>— аналіз шарів і їхніх розмірівdocker build --progress=plain— детальний вивід збіркиdive <image>— інтерактивний аналізатор шарів- BuildKit
--progress=trace— tracing кожного кроку
Production Story
Команда з 50 розробників зіткнулася з тим, що CI-збірка займала 12 хвилин. Аналіз показав: щоразу завантажувались усі Maven-залежності заново. Впровадження multi-stage build з окремим кешуванням pom.xml скоротило час до 2 хвилин (83% improvement). Додатково: перехід на slim-образ зменшив розмір з 650MB до 280MB, що прискорило деплой у 2.3 рази і заощадило 40% storage в registry.
Резюме
- Dockerfile — рецепт створення іммутабельного артефакту. Розуміння кешування шарів — ключ до швидких CI/CD.
- Завжди прагніть до мінімізації шарів і Multi-stage збірки.
- Dockerfile має бути детермінованим (конкретні версії, не
latest). - Безпека: non-root користувач, мінімальний базовий образ, health checks.
- На масштабі оптимізація Dockerfile економить сотні годин CI/CD і гігабайти storage.
🎯 Шпаргалка для інтерв’ю
Обов’язково знати:
- Dockerfile — декларативний рецепт створення іммутабельного Docker-образу
- Кожна інструкція (RUN, COPY, ADD) створює новий read-only шар
- Кешування шарів — ключ до швидкої збірки: порядок інструкцій критичний
- Multi-stage build — стандарт для production: збірка в одному образі, runtime в іншому
- Exec form
["cmd", "arg"]обов’язкова для CMD/ENTRYPOINT (signal handling) - Безпека: non-root користувач, конкретні теги, мінімальний базовий образ
- BuildKit: секрети (
--mount=type=secret), SSH forwarding, cache mounts
Часті уточнюючі питання:
- «Чому важливий порядок інструкцій?» — Зміна інструкції інвалідує всі наступні шари кешу
- «Що таке .dockerignore?» — Виключає файли з build context (як .gitignore для Docker)
- «Чому Alpine може бути проблемою?» — musl libc ≠ glibc; JNI-бібліотеки можуть не працювати
- «Чим COPY відрізняється від ADD?» — ADD вміє розпаковувати архіви і скачувати по URL, але COPY переважніше
Червоні прапорці (НЕ говорити):
- «Використовую тег
latestдля зручності» (недетерміновані збірки) - «Секрети передаю через ARG» (видно в
docker history) - «Запускаю додаток від root у контейнері» (ризик безпеки)
- «ADD кращий ніж COPY» (COPY — best practice в 95% випадків)
Пов’язані теми:
- [[Які основні інструкції використовуються в Dockerfile]] — детальний розбір інструкцій
- [[Що таке multi-stage build]] — оптимізація розміру образу
- [[В чому різниця між CMD та ENTRYPOINT]] — запуск контейнера