1. DevOps
1.1. Docker Image

Docker Image — це незмінний (immutable) шаблон, який містить все необхідне для запуску додатку в контейнері: вихідний код, залежності, бібліотеки, системні утиліти та конфігурацію середовища. Образ формується на основі Dockerfile — спеціального файлу інструкцій, який описує процес створення образу.
-
Layers — шари, які являють собою окремі зміни в образі. Кожен шар є результатом виконання команди в Dockerfile;
-
Filesystem — файловий простір, який містить всі файли та каталоги, необхідні для роботи додатку;
-
Metadata — метадані, які містять інформацію про образ, такі як автор, версія, команди запуску тощо.
Кожен Docker Image складається з одного або декількох шарів. Шари дозволяють ефективно використовувати дисковий простір, оскільки спільні шари між образами не дублюються. Коли ви змінюєте образ, створюється новий шар, який містить лише зміни, а попередні шари залишаються незмінними.
Layer (слой) — це один з шарів, з яких складається Docker-образ. Кожен слой являє собою результат виконання однієї інструкції (RUN, COPY тощо) в Dockerfile. Docker кешує ці шари, якщо в Dockerfile нічого не змінилось ні інструкція, ні файли які впливають на слой, Docker використовує кеш що прискорює збірку та дозволяє перевикористовувати вже побудовані частини. Але якщо один слой змінився, то всі наступні шари перезбираються
-
Base Images — базові образи, які містять лише операційну систему або мінімальний набір інструментів. Наприклад,
alpine
,ubuntu
,debian
. -
Application Images — образи, які містять готові до запуску додатки. Наприклад,
nginx
,mysql
,node
. -
Custom Images — користувацькі образи, створені на основі базових образів з додаванням власних файлів та налаштувань.
Секрети, паролі або ключі не варто зберігати всередені образу. Краще передавати їх через зовнішні змінні середовища, Docker secrets (Swarm), Kubernetes secrets або сторонні сховища (Vault), щоб мінімізувати ризик витоку.
Нжче приведені базові команда для роботи в Docker Image:
Образи створюються за допомогою команди docker build
, яка читає Dockerfile і створює образ на основі вказаних інструкцій. Наприклад:
docker build -t myapp:latest .
Ця команда створює образ з тегом myapp:latest
на основі Dockerfile в поточній директорії. Це простий варіант створення. Є більш екзотичний як Multi-stage build. Multi-stage build - це способ розділити сборку на кілька "етапів" (FROM … AS builder, FROM … AS runtime) та передавати артефакти, (наприклад, скомпільовані бінарники) з одного етапу в інший. Це зменшує кінцевий образ, оскільки в ньому не залишаються зайві інструменти збірки. Далі наведемо приклад Dockerfile:
FROM golang:1.16 AS builder
WORKDIR /app
COPY . .
RUN go build -o /app/app
FROM alpine:3.14
COPY --from=builder /app/app /app/app
CMD ["/app/app"]
Образи можна завантажувати з Docker Hub або інших реєстрів за допомогою команди docker pull
. Наприклад:
docker pull nginx:latest
Ця команда завантажує останню версію образу Nginx з Docker Hub.
Щоб опублікувати свій образ в Docker Hub або іншому реєстрі, використовуйте команду docker push
. Перед цим потрібно увійти в реєстр за допомогою docker login
. Наприклад:
docker login
docker push myusername/myapp:latest
Образи можна тегувати для зручності ідентифікації. Тегування дозволяє створювати різні версії одного образу. Наприклад:
docker tag myapp:latest myapp:v1.0
Ця команда створює тег v1.0
для образу myapp:latest
. Тепер ви можете використовувати обидва теги для запуску контейнерів.
docker inspect myapp:latest
Ця команда виведе детальну інформацію про образ, включаючи шари, метадані та налаштування.
docker rmi myapp:latest
Ця команда видаляє образ myapp:latest
. Якщо образ використовується в контейнерах, потрібно спочатку зупинити та видалити ці контейнери.
1.2. Dockerfile

dockerfile — це текстовий файл, який містить набір інструкцій для створення Docker-образу. Він визначає, як збирати образ, які команди виконувати, які файли копіювати, які порти відкривати тощо. Dockerfile використовується командою docker build
для створення нового образу на основі вказаних інструкцій.
FROM
FROM
— це перша й обов’язкова інструкція у більшості Dockerfile. Вона визначає базовий образ, на основі якого буде створено новий Docker-образ. Головні особливості:
-
Вказує базовий образ, з якого починається збірка нового образу;
-
Може використовуватися декілька разів для multi-stage builds;
-
Підтримує різні формати, такі як
FROM <image>[:<tag>]
абоFROM <image>@<digest>
для більшої стабільності збірки; -
Підтримує вказівку архітектури та тегу, наприклад
FROM --platform=linux/amd64 ubuntu:20.04
; -
Підтримує вказівку
AS <name>
для іменування етапу в multi-stage builds.
Головне призначення FROM
— це визначення базового образу, на якому буде побудований новий образ. В multi-stage builds FROM
може використовуватися декілька разів для створення різних етапів збірки:
FROM ubuntu AS builder
RUN apt-get update && apt-get install -y build-essential
COPY . /app
WORKDIR /app
RUN make
FROM alpine AS runtime
COPY --from=builder /app/myapp /usr/local/bin/myapp
CMD ["/usr/local/bin/myapp"]
У цьому прикладі перший FROM
створює етап збірки, де встановлюються залежності та компілюється додаток. Другий FROM
створює етап виконання, де копіюється скомпільований додаток з попереднього етапу.
Якщо FROM
не вказано, Docker не зможе створити образ, оскільки не буде знати, з якого базового образу починати збірку. Це призведе до помилки (Dockerfile parse error: No FROM instruction found) під час виконання команди docker build
.
Є особливий випадок, коли FROM
не вказується, це використання scratch
як базового образу. scratch
— це порожній образ, який використовується для створення мінімальних образів без операційної системи. Наприклад:
FROM scratch
COPY myapp /myapp
CMD ["/myapp"]
scratch
використовується:
-
Коли потрібно створити дуже легкий образ без операційної системи;
-
Коли додаток не потребує жодних бібліотек або залежностей, окрім самого виконуваного файлу;
-
Для створення образів на основі статично скомпільованих додатків, таких як Go або Rust.
Особливостями scratch
є:
-
Він не містить жодних файлів або директорій, тому всі команди, такі як
RUN
,COPY
,ADD
, будуть створювати нові файли в порожньому образі; -
Не підтримує жодних операцій з файловою системою, оскільки це порожній образ;
-
Не має shелл або інших утиліт, тому не можна виконувати команди, які потребують shell (наприклад,
RUN ls
не спрацює).
В FROM
можна вказати архітектуру, на якій буде створено образ. Це особливо корисно для multi-stage builds, де різні етапи можуть мати різні архітектури. Наприклад:
FROM --platform=linux/arm64 ubuntu:20.04 AS builder
RUN apt-get update && apt-get install -y build-essential
COPY . /app
WORKDIR /app
RUN make
CMD ["/app/myapp"]
Оптімальними базовими образами для FROM
є:
-
alpine
— легкий образ (~5МВ) з базовою операційною системою, який містить лише необхідні утиліти; -
ubuntu
— повноцінний образ з Ubuntu, який містить всі стандартні утиліти та бібліотеки, розмір ~30-60МВ; -
debian
/slim
— повноцінний образ з Debian, який також містить всі стандартні утиліти та бібліотеки, розмір ~20МВ; -
scratch
— порожній образ, який використовується для створення мінімальних образів без операційної системи, розмір ~0МВ.
-
Використовуй легкі базові образи, такі як
alpine
абоscratch
, якщо це можливо; -
Уникай використання важких базових образів, таких як
ubuntu
абоdebian
, якщо не потрібні всі їхні утиліти; -
Використовуй
FROM
з тегами, щоб уникнути проблем з несумісністю версій (наприклад,FROM ubuntu:20.04
замістьFROM ubuntu
); -
Уникай використання
latest
тегів, оскільки це може призвести до непередбачуваних змін у збірці; -
Використовуй
FROM
зAS <name>
для іменування етапів у multi-stage builds, щоб зробити Dockerfile більш читабельним; -
Уникай використання
FROM scratch
, якщо не впевнений, що додаток не потребує жодних бібліотек або утиліт; -
Використовуй
FROM
з--platform
для вказівки архітектури, якщо потрібно створити образ для різних платформ (наприклад,FROM --platform=linux/amd64 ubuntu:20.04
).
RUN
RUN
— виконує команду на етапі збірки образу. Результат її виконання зберігається як шар (layer) в Docker-образі. Для кожної інструкції RUN
створюється новий шар, який містить зміни, внесені цією командою. Це дозволяє Docker використовувати кеш для оптимізації збірки образів. Чим більше шарів тім більше образ, тому краще об’єднувати команди в один RUN
, використовуючи &&
для зменшення кількості шарів. Наприклад:
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*
Для кождної інструкції RUN
створюється новий шар, що може призвести до збільшення розміру образу. Краще об’єднати ці команди в один RUN
, щоб зменшити кількість шарів:
RUN apt-get update && \
apt-get install -y curl && \
rm -rf /var/lib/apt/lists/*
Зараз Docker створить лише один шар, який міститиме всі зміни, внесені цими командами. Це зменшує розмір образу та прискорює збірку. Docker кешує результати кожної інструкції RUN
, якщо команда не змінилася, Docker використовує кеш для цього шару. Якщо команда не змінилась але ми хочемо, щоб Docker знову виконав її, можна використовувати --no-cache
при збірці образу:
docker build --no-cache -t myimage .
Також для мінімізації розміру образу треба використовувати apt-get clean && rm -rf /var/lib/apt/lists/*
після встановлення пакетів, щоб видалити тимчасові файли, які не потрібні в кінцевому образі. Наприклад:
RUN apt-get update && \
apt-get install -y curl && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
Також гарною практикою є створення каталогу с певними правами доступу, щоб уникнути проблем з правами доступу до файлів в контейнері. Наприклад:
RUN mkdir -p /app && \
chown -R username:usergroup /app
Що створює каталог /app
з правами доступу для користувача username
та групи usergroup
. Це дозволяє уникнути проблем з правами доступу до файлів в контейнері, якщо додаток працює від імені цього користувача.
-
Використовуй
&&
для об’єднання команд в одинRUN
, щоб зменшити кількість шарів; -
Не додавай секрети або конфіденційну інформацію в
RUN
, оскільки вони залишаться в історії образу; -
Використовуй
--no-cache
при збірці, якщо потрібно примусово виконати командуRUN
, навіть якщо вона не змінилася; -
Використовуй
apt-get clean && rm -rf /var/lib/apt/lists/*
після встановлення пакетів, щоб зменшити розмір образу; -
Створюй каталоги з певними правами доступу, щоб уникнути проблем з правами доступу до файлів в контейнері.
CMD
CMD — це інструкція Dockerfile, яка визначає команду за замовчуванням, яку Docker виконає при запуску контейнера, якщо не вказано інше під час запуску.
CMD ["executable", "param1", "param2"]
Ця команда не буде виконана під час збірки образу, а лише при запуску контейнера (docker run
). Якщо вказано декілька аргументів, вони будуть передані як список. Може бути тільки одна інструкція CMD в Dockerfile, якщо їх декілька, то буде використана остання. Така інструкція не потребує ENTRYPOINT
. Не запускається через shell, тому не потрібно використовувати sh -c
або bash -c
. Якщо потрібно виконати команду через shell, використовуйте ENTRYPOINT
з CMD
для аргументів, або наступний формат (але це застарілий варіант):
CMD executable param1 param2
Наприклад:
CMD nginx -g "daemon off;"
Що єквівалентно до:
CMD ["/bin/sh", "-c", "nginx -g 'daemon off;'"]
Головне призначення CMD
— це визначення команди, яка буде виконана при запуску контейнера. Інструкція CMD у Dockerfile використовується Docker’ом під час запуску контейнера, а не під час збірки образу. Вона задає команду за замовчуванням, яка буде виконана, якщо користувач не вкаже свою. Наприклад є Dockerfile:
FROM alpine
CMD ["echo", "Hello, World!"]
І при запуску користувач вказує свою команду, наприклад "ls- la":
docker run myimage echo "ls -la"
У цьому випадку команда CMD
буде ігноруватися, і буде виконана команда користувача. Якщо ж користувач не вказує свою команду, то буде виконана команда з CMD
, тобто echo "Hello, World!"
. Якщо CMD
використовується разом з ENTRYPOINT
, то CMD
буде передаватися як аргументи до ENTRYPOINT
. Наприклад:
FROM alpine
ENTRYPOINT ["ping"]
CMD ["google.com"]
docker run myimage
# → ping google.com
docker run myimage yahoo.com
# → ping yahoo.com
Також для того, щоб перевизначити CMD
у docker-compose файлі, можна використовувати command
:
version: '3'
services:
myservice:
image: myimage
command: ["echo", "Hello from docker-compose!"]
Якщо не вказано command
, то буде виконана команда з CMD
в Dockerfile.
У Kubernetes, CMD
може бути перевизначено в Deployment
або Pod
через поле command
. Наприклад:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: mycontainer
image: myimage
command: ["ping", "localhost"] # Перезаписує ENTRYPOINT/CMD, що єквівалентно ENTRYPOINT ["echo", "Hello from Kubernetes!"]
args: ["google.com"] # Аргументи для команди, що єквівалентно CMD ["google.com"]
Головне про CMD:
-
Використовується для визначення команди за замовчуванням, яка буде виконана при запуску контейнера;
-
Якщо не вказано, то буде виконана команда з
CMD
; -
Якщо користувач вказує свою команду при запуску, то команда з
CMD
буде ігноруватися; -
Якщо використовується разом з
ENTRYPOINT
, тоCMD
буде передаватися як аргументи доENTRYPOINT
; -
Якщо в Dockerfile є декілька
CMD
, то буде використана остання команда; -
CMD
не виконується якщо вказана інша команда при запуску контейнера або якщо використовується--entrypoint
, тодіCMD
буде ігноруватися (якщо не використовується як аргумент).
ENTRYPOINT
ENTRYPOINT
— визначає основну команду, яку Docker завжди виконає, коли запускається контейнер. На відміну від CMD
, вона не перезаписується аргументами docker run, якщо явно не використати --entrypoint. Головною метою ENTRYPOINT
є запусити процес який має стартувати разом з контейнером. Приймати параметри від CMD
або аргументів командного рядка (docker run
).
Головною метою ENTRYPOINT
є запуск процесу, який має стартувати разом з контейнером в незалежності від того, чи вказані додаткові аргументи при запуску контейнера. Це дозволяє створити контейнер, який завжди виконує певну задачу, наприклад, запуск веб-сервера або бази даних. Далі наведемо приклади використання ENTRYPOINT
, першим прикладом є простий запуск Nginx сервера(наприклад):
FROM nginx
ENTRYPOINT ["nginx", "-g", "daemon off;"]
Також ENTRYPOINT
може використовуватись для запуску та передачі аргументів в shell-скрипт, наприклад:
FROM alpine
COPY start.sh /usr/local/bin/start.sh
ENTRYPOINT ["/usr/local/bin/start.sh"]
#!/bin/sh
echo "Запуск з аргументами: $@"
exec "$@"
При запуску контейнера з таким ENTRYPOINT
, ви можете передати додаткові аргументи, які будуть доступні в скрипті start.sh
через $@
. Наприклад:
docker run myimage echo "Hello, World!"
# → Запуск з аргументами: Hello, World!
$Hello, World!
Головне про ENTRYPOINT
:
-
Використовується для визначення основної команди, яка завжди виконується при запуску контейнера;
-
Не перезаписується аргументами
docker run
, якщо не використовується--entrypoint
; -
Дозволяє створити контейнер, який завжди виконує певну задачу;
-
Може використовуватись разом з
CMD
для передачі аргументів до основної команди; -
Використовується для запуску процесів, які мають стартувати разом з контейнером;
-
Може бути використано для запуску shell-скриптів, які приймають аргументи;
-
Якщо в Dockerfile є декілька
ENTRYPOINT
, то буде використана остання команда; -
ENTRYPOINT
може бути використано для запуску процесів, які мають стартувати разом з контейнером, наприклад, веб-серверів або баз даних; -
Якщо використовується разом з
CMD
, тоCMD
буде передаватися як аргументи доENTRYPOINT
; -
Якщо в Dockerfile є декілька
ENTRYPOINT
, то буде використана остання команда; -
ENTRYPOINT
не виконується якщо використовується--entrypoint
.
CMD
vs ENTRYPOINT
Особливість |
CMD |
ENTRYPOINT |
Призначення |
Команда за замовчуванням |
Основна команда (завжди виконується) |
Перевизначення |
Легко перевизначається через docker run |
Може вимагати --entrypoint |
Взаємодія |
Може передавати аргументи до ENTRYPOINT |
Команду не можна легко змінити |
COPY
COPY
використовується в Dockerfile для копіювання файлів і директорій з локальної файлової системи (контексту збірки) в файлову систему образу. Головні особливості:
-
Копіює файли/директорії з контексту збірки в контейнер;
-
--chown
дозволяє встановити власника та групу для скопійованих файлів; -
Не розпаковує архіви (.tar.gz, .zip тощо);
-
Не підтримує URL, тобто не завантажує файли з Інтернету.
ADD
ADD
— інструкція Dockerfile, яка копіює файли з локального контексту збірки або з віддалених URL у файлову систему контейнера, але з додатковими можливостями, яких не має COPY
. Головними особливостями ADD
є:
-
Копіює файли/директорії з контексту збірки в контейнер;
-
Підтримує розпакування архівів (наприклад, .tar.gz) при копіюванні;
-
Підтримує завантаження файлів з віддалених URL;
-
Має параметр
--chown
для встановлення власника та групи для скопійованих файлів. -
Не розпаковує архіви з URL, тобто якщо ви вказуєте URL, то архів не буде розпакований.
ADD myapp.tar.gz /usr/src/myapp/
То результатом виконання буде:
/usr/src/myapp/file1.txt
/usr/src/myapp/file2.txt
...
Але якщо ви вказуєте URL:
ADD https://example.com/myapp.tar.gz /usr/src/myapp/
то результатом буде:
/usr/src/myapp/myapp.tar.gz
Тобто якщо архів вказаний в команді ADD
розташований локально то він буде розпакований, але якщо він вказаний як URL, то він буде просто скопійований в контейнер без розпакування.
COPY
vs ADD
Відмінність між COPY та ADD:
-
COPY
копіює файли/директорії з контексту збірки в контейнер. -
ADD
робить те ж саме, але також може автоматично розпаковувати архіви та завантажувати файли по URL. Рекомендується частіше використовуватиCOPY
(більш передбачувано),ADD
— тільки коли потрібні додаткові можливості.
Як результат можна зробити висновок, що:
-
COPY
— це простий і передбачуваний спосіб копіювання файлів з контексту збірки в контейнер; -
ADD
— це більш потужний інструмент, який дозволяє розпаковувати архіви та завантажувати файли з URL, але може бути менш передбачуваним; -
Рекомендується використовувати
COPY
для простих копіювань, аADD
— тільки коли потрібні додаткові можливості, такі як розпакування архівів або завантаження файлів з URL.
WORKDIR
WORKDIR встановлює робочу директорію всередині контейнера для наступних інструкцій (RUN, CMD, ENTRYPOINT і т.д.). Якщо каталогу немає, він буде створений.
EXPOSE
EXPOSE вказує, що контейнер слухає порт вказаний в цій команді. Це не впливає на роботу контейнера всередині Docker, але це корисно для читабельності та може враховуватися інструментами оркестрації.
ENV
ENV встановлює змінні середовища для контейнера, які будуть доступні на етапі виконання контейнера (runtime).
Ці змінні:
-
можуть використовуватись як під час збірки Dockerfile, так і в запущеному контейнері, оскільки зберігаються в образі;
-
дозволяють задавати конфігураційні параметри, які можуть бути змінені при запуску контейнера;
-
завжди присутні в контейнері, що робить його більш передбачуваним і “персистентним”;
-
можуть бути використані в командах, додатках або скриптах, що працюють всередині контейнера.
Для перевизначення змінних середовища при запуску можна використати:
-
docker run -e KEY=VALUE
-
docker run --env KEY=VALUE
Також їх можна заздалегідь визначити в Dockerfile через:
ENV APP_HOME=/usr/src/app
WORKDIR $APP_HOME
RUN echo "App home is set to $APP_HOME"
Головне призначення ENV
— це встановлення змінних середовища, які будуть доступні на етапі виконання контейнера. Це дозволяє задавати конфігураційні параметри, які можуть бути змінені при запуску контейнера, і робить його більш передбачуваним і “персистентним”. Гнучкість для користувача: якщо ви хочете дозволити користувачам змінювати параметри роботи контейнера на етапі запуску, використовуйте ENV
. Ці значення можна легко перевизначити за допомогою флага -e
або через docker-compose.
ARG
Для того щоб передати аргументи сборки в Dockerfile, використовуйте інструкцію ARG. При зборці передавайте --build-arg. Наприклад Dockerfile:
ARG APP_VERSION=latest
RUN echo "Version: $VERSION"
Сборка:
docker build --build-arg APP_VERSION=1.2 .
Головне призначення ARG
дозволяє задавати змінні на єтапі зборки образу (build-time). Ці змінні використовуються тільки під час зборки і не доступні коли образ зібран. Тобто ці змінні використовуються тільки в Dockerfile і не зберігаються в контейнері та недоступні під час виконання контейнера. Використання ARG
є вірним вибором для зберігання сенсатів даних (токени, ключі API тощо) для того щоб вони не зберігалися в кінцевому образі. Але краще уникати використання таких даних в будь-якому вигляді, тому що навіть у випадку з ARG
, ці дані можуть залишитися в історії збірки Docker-образу (наприклад, в проміжних шарах).
ARG
vs ENV
Параметр |
|
|
Використання |
На етапі збірки образу |
На етапі виконання контейнера |
Доступность |
Доступны только на этапе сборки |
Доступны на этапе выполнения контейнера |
Перевизначення |
Можно переопределить с помощью |
Можно переопределить с помощью |
Сохранение в образе |
Не сохраняется в образе |
Сохраняется в образе |
Цель |
Используется для передачи временных значений при сборке |
Используется для задания окружения приложений внутри контейнера |
ARG
/ENV
best practices:
-
Використовуйте
ARG
для змінних, які потрібні тільки на етапі збірки. Це хороший спосіб уникнути витоку даних, які не потрібні на етапі виконання. -
Використовуйте
ENV
для змінних, які потрібні на етапі виконання контейнера. Це дозволяє гнучко налаштовувати контейнер, передаючи параметри додатку та середовища. -
Мінімізуйте кількість змінних середовища
ENV
, що містять чутливі дані. ХочаENV
може бути зручним для передачі конфігурацій, це не найкращий спосіб для зберігання секретів, оскільки вони зберігаються в образі і можуть бути витягнуті. Краще використовувати секрети Docker (наприклад, через Docker Swarm або Kubernetes), якщо потрібно працювати з чутливими даними. -
Чітко розмежовуйте етапи збірки та виконання: Розуміння того, на якому етапі (збірки чи виконання) потрібні змінні, допоможе правильно вибрати між
ARG
іENV
. -
Використовуйте спільне використання
ARG
іENV
, коли потрібно передати значення на етапі збірки, а потім зберегти його для використання в контейнері.
ARG
/ENV
Summary:
-
ARG
— це змінні, які використовуються тільки на етапі збірки Dockerfile. Вони не зберігаються в кінцевому образі і не доступні під час виконання контейнера. -
ENV
— це змінні середовища, які доступні на етапі виконання контейнера. Вони зберігаються в образі і можуть бути використані додатками всередині контейнера.
USER
USER
— визначає користувача, від імені якого будуть виконуватись усі наступні інструкції (RUN, CMD, ENTRYPOINT, тощо), а також процес у контейнері під час запуску. Це дуже важлива інструкція для безпеки, тому що за замовченням все запускається від root користувача. Це зручно для встановлення пакетів але небеспечно для запуску додатків. Простий приклад:
FROM alpine
# Під root встановлюємо залежності
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
# Створюємо користувача
RUN adduser -D myuser
# Переключаємось
USER myuser
# Далі всі команди — без root-доступу
CMD ["echo", "Hello from myuser!"]
Коли використовуєш USER
треба переконатись що користувач має права доступу до потрібних дерікторій:
FROM alpine
WORKDIR /app
RUN adduser -D myuser
USER myuser
RUN --chown=myuser:myuser /app
VOLUME
VOLUME
— створює точку монтування для зберігання даних, які не зберігаються в образі. Це дозволяє зберігати дані, які можуть змінюватись під час виконання контейнера, і робить їх доступними навіть після перезапуску контейнера. Наприклад:
VOLUME ["/data", "/logs"]
При цьому Docker створює нові томи для /data
та /logs
, монтує їх в вказану директорію в контейнері, дані в цих директоріях не зберігаються у шарах образу, а зберігаються в том. І при перезапуску контейнеру дані зберігаються. Але неможна задати ім’я тома, тому що Docker сам створює тома з випадковими іменами. Але за необхідністю можна створити іменований тома вручну і підключити його до контейнера.
LABEL
LABEL
— використовується для додавання метаданих (інформації) до Docker-образу у вигляді пар ключ=значення. Ці дані не впливають на виконання контейнера, але корисні для ідентифікації, автоматизації та документування. Docker рекомендує OCI Image Specification для ключів:
LABEL org.opencontainers.image.title="My App" \
org.opencontainers.image.description="Awesome app" \
org.opencontainers.image.version="1.0.0" \
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.source="https://github.com/user/repo"
Для того щоб переглянути метадані образу, можна використати команду:
docker inspect myimage --format='{{json .Config.Labels}}'
HEALTHCHECK
HEALTHCHECK
— це інструкція, яка дозволяє перевіряти “здоров’я” контейнера під час його роботи. Docker автоматично виконує команду перевірки з певним інтервалом і встановлює статус:
-
✅ healthy — контейнер працює коректно
-
⚠️ unhealthy — контейнер не відповідає
-
⏳ starting — контейнер ще запускається
Це дозволяє автоматично виявляти проблеми з контейнером і вживати заходів, наприклад, перезапускати його. Приклад використання:
FROM nginx:alpine
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -f http://localhost/ || exit 1
Для перевірки статусу здоров’я контейнера можна використати команду:
docker inspect --format='{{json .State.Health}}' mycontainer
або
docker ps
І як результат можна побачити статус здоров’я контейнера в колонці STATUS
.
Up 30 seconds (healthy)
Up 1 minute (unhealthy)
Up 10 seconds (starting)
Важливі нюанси:
-
HEALTHCHECK
не перезапускає контейнер автоматично (але можна налаштувати Docker Swarm/Kubernetes для рестарту при unhealthy); -
Впливає на CI/CD (деякі оркестратори чекають статусу healthy перед деплоєм);
-
Використовуй легкі команди (перевірка має бути максимально швидкою (кілька секунд)
-
Винось складну логіку в скрипт, наприклад:
COPY healthcheck.sh /usr/local/bin/
HEALTHCHECK CMD /usr/local/bin/healthcheck.sh
SHELL
SHELL
— визначає, яку командну оболонку (shell) Docker буде використовувати для виконання інструкцій на кшталт RUN, CMD та ENTRYPOINT (коли вони задаються у shell-форматі). Тобто потрібен для того щоб змінити інтерпретатор команд, який буде використовуватись для виконання команд в Dockerfile. За замовчуванням це /bin/sh -c
, але можна змінити на іншу оболонку, наприклад, /bin/bash -c
або /bin/zsh -c
. Приклад:
SHELL ["/bin/bash", "-c"]
RUN echo "Hello from bash" \
Для того, щоб забезпечити якість Dockerfile ніж пушити до репозіторію, можна використовувати наступні підходи:
-
Сборка образу. Запустіть
docker build .
для зборки образу. Перевірте, що образ збирається без помилок. -
Запуск контейнера. Запустіть контейнер зі збудованим образом через
docker run
. Перевірте, що контейнер запускається і працює коректно. -
Юніт-тести. Напишіть юніт-тести для Dockerfile. Наприклад, використовуючи Molecule або Testcontainers.
-
Базовый образ — бери минимальный (alpine, slim, scratch), фиксируй версию, не используй latest;
-
Меньше слоев — объединяй команды RUN, удаляй кеши и временные файлы;
-
.dockerignore — исключай ненужные файлы (.git, node_modules, логи);
-
Не root — создавай пользователя и запускай от него (USER app);
-
ENTRYPOINT + CMD — разделяй основную команду и аргументы по умолчанию;
-
Multi-stage build — собирай в одном образе, запускай в другом (минимальном);
-
Безопасность — только нужные пакеты, без секретов в Dockerfile, регулярные обновления;
-
Використовуйте
COPY
замістьADD
, якщо не потрібно автоматичне розпакування архівів або завантаження з URL; -
Використовуйте
ARG
для передачі змінних збірки, щоб зробити Dockerfile більш гнучким.
1.3. Docker Volume

Docker Volumes — це механізм для зберігання даних поза життєвим циклом контейнера тобто по за файловою системою контенера. Контейнер можна перестворити, а дані в томі залишаться. А також як варіант ділитися файламі між хостом та контейнером або між контейнерами. Але при одночасному підключенню одного тому до декількох контейнерів можуть виникнути конфлікти, тому потрібно переконатися, що додатки підтримують спільний доступ до томів.
Розрізняють три види томів:
-
Anonymous Volume — це том, який створюється без імені і використовується тільки в одному контейнері;
-
Bind Mount — це прив’язка до каталогу або файлу на хості, який буде доступний в контейнері;
-
Named Volume — це том, який створюється з іменем і може бути використаний в декількох контейнерах.
Anonymous Volumes — це томи, які створюються автоматично без імені при використанні VOLUME в Dockerfile або docker run -v /path
. Очевидним мінусом є те, що їх важко ідентифікувати та керувати ними та використовувати повторно.
Bind Mount — це механізм, який дозволяє прив’язати каталог або файл на хості до контейнера. Це дозволяє контейнеру отримувати доступ до даних на хості або зберігати дані на хості. Приклад:
docker run -v /host/path:/container/path ...
Мінус цього варіанту в, тому що є залежність від файлової системи.
# Створюємо том з іменем вручну
docker volume create my_named_volume
# Запускаємо контейнер з підключеним іменованим томом
docker run -d \
--name my-container \
-v my_named_volume:/app/data \
my-image
# або
docker run -d \
--name my-container \
--mount type=volume,source=my_named_volume,target=/app/data \
myimage
або в docker-compose
version: '3.8'
services:
my-service:
image: my-image
volumes:
- my_named_volume:/app/data
Може бути зручно для повторного використання даних між контейнерами або для резервного копіювання.
-
Bind Mount напряму зв’язує каталог/файл хоста з контейнером;
-
Anonymous Volume зберігається в управляємому Docker (наприклад, /var/lib/docker/volumes), не прив’язаний напряму до шляху на хості.
-
Named Volume — це окремий об’єкт в Docker, який можна використовувати в інших контейнерах;
-
Bind Mount — це просто шлях на хості, який можна використовувати тільки в одному контейнері.
Різниця у швидкості доступу до даних: Named Volume* швидше, але Bind Mount має більше можливостей.
Порівняльня таблиця:
Тип тома |
Доступ до даних |
Повторне використання |
Залежність від хоста |
Розшарювати між контейнерами |
Головне використання |
Anonymous Volume |
Через Docker |
Ні |
Ні |
Технічно так, але незручно |
Тимчасові дані |
Named Volume |
Через Docker |
Так |
Ні |
Так |
Постійне зберігання даних |
Bind Mount |
Через хост |
Ні |
Так |
Так, якщо вказати той самий шлях |
Розробка,тестування |
Зазвичай логи контейнера виводяться в stdout/stderr (для docker logs
) або підключаються до централізованої системи логування. Якщо потрібно зберігати логи на хості, можна підключити volume або bind mount для каталогу логів.
-
Зберігати дані поза контейнером, що дозволяє зберегти їх при перезапуску або видаленні контейнера;
-
Ділитися даними між контейнерами;
-
Зберігати конфігураційні файли, логи та інші дані, які можуть змінюватися під час роботи контейнера;
-
Використовувати дані з хоста в контейнері, наприклад, для розробки або тестування.
Драйвера доступні в volume:
Драйвер |
Тип зберігання |
Призначення |
local |
Локальна ФС (/var/lib/docker/volumes) |
За замовчуванням, швидке локальне зберігання |
nfs |
NFS-сервер |
Спільний доступ між кількома хостами |
tmpfs |
Оперативна пам’ять |
Дуже швидке, але тимчасове зберігання |
aws |
Amazon EBS |
Блочне сховище AWS |
azurefile |
Azure File Storage |
Хмарне сховище Microsoft Azure |
gcs |
Google Cloud Storage |
Хмарне сховище Google |
efs |
AWS Elastic File System |
Розподілене хмарне сховище AWS |
rexray |
Багатоплатформне блочне сховище |
AWS, GCP, Azure, OpenStack |
flocker |
Кластерне зберігання |
Для розподілених систем |
portworx |
Розподілене блокове сховище |
Для Kubernetes/Docker кластерів |
ceph |
CephFS або RBD |
Масштабоване кластерне сховище |
Для того щоб створити том з використанням специфічного драйвера, можна використовувати команду:
docker volume create --driver <ім'я_драйвера> [--opt ключ=значення] <ім'я_тому>
Далі наведемо приклади створення томів, першим спробуємо створити з використанням драйвера tmpfs
:
docker volume create \
--driver local \
--opt type=tmpfs \
--opt device=tmpfs \
--opt o=size=200m \
tmpfs_volume
Розберемо команду більш детально:
-
docker volume create
— команда для створення нового тому; -
--driver local
— вказує, що ми використовуємо локальний драйвер; -
--opt type=tmpfs
— вказує тип тома якtmpfs
, що означає, що дані будуть зберігатися в оперативній пам’яті; -
--opt device=tmpfs
— вказує, що ми використовуємоtmpfs
як пристрій для зберігання даних; -
--opt o=size=200m
— вказує, що розмір тома обмежений 200 мегабайтами; -
tmpfs_volume
— ім’я створюваного тому.
Ще одним прикладом буде створеня тому з використання NFS-драйвера:
docker volume create \
--driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,rw,nfsvers=4,tcp \
--opt device=:/nfs_data \
my_nfs_volume
Розберемо команду більш детально:
-
docker volume create
— команда для створення нового тому; -
--driver local
— вказує, що ми використовуємо локальний драйвер; -
--opt type=nfs
— вказує тип тома якnfs
, що означає, що дані будуть зберігатися на NFS-сервері; -
--opt o=addr=192.168.1.100,rw
— вказує адресу NFS-сервера та режим доступу (читання і запис); -
--opt device=:/nfs_data
— вказує шлях до каталогу на NFS-сервері, який буде використовуватися як том; -
my_nfs_volume
— ім’я створюваного тому.
Основні опції для docker volume create --driver local --opt
:
Опція |
Приклад Значення |
Опис |
type |
tmpfs, nfs, ceph, aws, azurefile |
Тип тома, який буде створено. |
device |
/path/to/device, :/nfs_data |
Шлях до пристрою або каталогу, який буде використовуватися як том. |
o |
rw, ro, size=200m, addr=192.168.1.100 |
Опції монтування, як у mount -o |
uid |
1000 |
Власник файлів (User ID) |
gid |
1000 |
Група файлів (Group ID) |
mode |
0700 |
Права доступу до каталогу |
nfsvers |
3 або 4 |
Версія NFS |
noatime |
— |
Не оновлювати час доступу до файлів (оптимізація швидкості) |
soft / hard |
— |
Поведінка при розриві зв’язку з NFS (soft — повертає помилку, hard — чекає відновлення) |
timeo |
600 |
Таймаут у десятих частках секунди для NFS |
tcp / udp |
— |
Протокол передачі для NFS |
vers |
4.1 |
Версія протоколу NFS |
nolock |
— |
Вимкнення блокування файлів в NFS |
-
docker volume inspect <volume_name>
- отримання детальної інформації про том<volume_name>
, включаючи його шлях на хості; -
docker volume rm <volume_name>
- видалення тому<volume_name>
; -
docker volume rm $(docker volume ls -q)
- видалення всіх томів (будьте обережні, це видалить всі томи без підтвердження); -
docker volume prune
- видалення всіх не використовуваних томів; -
docker volume prune --force
- примусове видалення всіх не використовуваних томів без підтвердження; -
docker run -v <volume_name>:/path/in/container <image>
- запуск контейнера з підключеним томом<volume_name>
до шляху/path/in/container
; -
docker run --mount type=volume,source=<volume_name>,target=/path/in/container <image>
- запуск контейнера з підключеним томом<volume_name>
до шляху/path/in/container
(альтернативний синтаксис); -
docker volume create <volume_name>
- створення нового тому з іменем<volume_name>
; -
docker volume create --name <volume_name>
- створення нового тому з іменем<volume_name>
; -
docker volume create --driver <driver_name> <volume_name>
- створення нового тому з використанням специфічного драйвера<driver_name>
; -
docker volume create --opt <key>=<value> <volume_name>
- створення нового тому з додатковими опціями<key>=<value>
.
1.4. Docker Container

Docker Container — це ізольований userspace-процесс або звичайний linux процесс запущений з використанням kernel features для ізоляції та обмеження ресурсів, яке дозволяє запускати додатки та сервіси в контейнеризованому вигляді. Працює поверх ядра Linux (або через WSL2 на Windows) та створюється на основі Docker-образа з використанням containerd як high-level контейнерного runtime і runc як low-level OCI-сумісного runtime для запуску процесів контейнера. Контейнери використовують спільне ядро операційної системи, але мають власні файлові системи, мережеві інтерфейси та процеси. Це дозволяє запускати додатки в ізоляції від інших процесів на хості, забезпечуючи легкість, швидкість та портативність. Контейнер реалізує ізоляцію процесів, файлової системи, мережі, користувачів та ресурсів через kernel-примітиви: namespaces, cgroups, seccomp, AppArmor/SELinux, capabilities.
Контейнери не зберігають стан (stateless by design), що робить їх ідеальними для мікросервісної архітектури, де кожен сервіс може бути запущений в окремому контейнері. Вони також легко масштабуються та інтегруються в CI/CD процеси. Presistence даних може бути досягнута через volumes, bind mounts або external services (наприклад, бази даних). Дуже добре маштабується в кластерних середовищах, таких як Kubernetes, Swarm або Nomad.
Виртуальная машина — це полноценная ОС, яка віртуалізує апаратне забезпечення та запускає окрему гостьову ОС. Контейнер — це ізольоване середовище, яке використовує ядро хостової ОС та запускає окремі процеси. Контейнери запускаються швидше, оскільки вони не потребують емуляції апаратного середовища та завантаження окремої ОС.
Характеристика |
Контейнер Docker |
Віртуальна машина (VM) |
Ядро ОС |
Спільне з хостом |
Власне, повноцінне ядро |
Швидкість запуску |
Секунди |
Хвилини |
Ресурси |
Мінімальні |
Значно більше |
Вага (типово) |
10–100 МБ |
Гігабайти |
Ізоляція |
Через kernel features (LXC, namespaces, cgroups) |
Через гіпервізор |
Портативність |
Висока |
Середня |
Мета |
Запуск окремих процесів |
Запуск повноцінної ОС |
Параметр |
Контейнер |
Віртуальна машина |
Startup time |
~50–500 мс |
~10–60 сек |
CPU overhead |
мінімальний |
помітний |
Memory overhead |
мінімальний |
високе споживання |
I/O performance |
залежить від storage driver |
близьке до native (з pass-through) |
Storage drivers: OverlayFS (default), aufs (deprecated), devicemapper, ZFS, Btrfs — кожен має нюанси по performance, stability та layered caching. |
Архітектура запуску контейнера:
Контейнери не віртуалізують апаратне забезпечення — замість цього вони опираються на ядро хоста і lightweight isolation primitives. |
Контейнер состоїть з:
Файлова система контейнера Docker побудована на основі шарів Docker-образа, які використовують каскадне об’єднане монтування (OverlayFS, UnionFS) з copy-on-write. Це дозволяє створювати ізольовані файлові системи для кожного контейнера, де зміни записуються лише у верхній rw-шар, не змінюючи базовий образ. Це дозволяє економити місце та швидко створювати нові контейнери.
Процеси в контейнері запускаються в ізольованому PID namespace, що дозволяє їм не бачити процеси на хості та інших контейнерах. Це забезпечує безпеку та ізоляцію, оскільки процеси в контейнері не можуть взаємодіяти з процесами на хості або в інших контейнерах.
Контейнери обмежуються в використанні ресурсів через control groups (cgroups). Це дозволяє контролювати використання CPU, пам’яті, I/O та інших ресурсів, що забезпечує стабільність та безпеку системи. Наприклад, можна обмежити кількість CPU, пам’яті або I/O, які може використовувати контейнер.
Контейнер має власний network namespace, що дозволяє йому мати окрему IP-адресу, DNS та порти. Це забезпечує ізоляцію мережі між контейнерами та хостом, дозволяючи кожному контейнеру мати свій власний мережевий стек. Контейнери можуть спілкуватися між собою через Docker network. Але можуть виникнути проблеми спілкування між контейнерами, якщо вони не налаштовані правильно або використовують різні мережеві драйвери. Для пошуку проблем з мережею між контейнерами можна використовувати:
-
docker exec -it <container> sh
для доступу до контейнера і виконання команд ping, curl або netcat до інших контейнерів. -
docker network inspect <network>
для перевірки налаштувань мережі.
Контейнери забезпечують безпеку через кілька механізмів:
-
PID namespace — ізолює процеси, що дозволяє контейнеру не бачити процеси на хості.
-
NET namespace — забезпечує окремий мережевий стек, що дозволяє контейнеру мати власні IP-адреси, порти та DNS.
-
MNT namespace — ізолює файлову систему, що дозволяє контейнеру мати власний простір монтування (/, /proc, /sys).
-
UTS namespace — ізолює hostname, що дозволяє контейнеру мати власний hostname.
-
IPC namespace — забезпечує власну пам’ять для inter-process communication, що дозволяє контейнеру мати власні IPC-ресурси.
-
User namespace — дозволяє UID 0 у контейнері не бути root на хості, що забезпечує додатковий рівень безпеки.
Для того, щоб запускати контейнери під non-root користувачем, використовуйте флаг --user
, наприклад:
docker run --user 1000 myimage
це є бест практикою для безпеки. Тому що при взломі якщо зловмисник отримає доступ до контейнера, він не отримає root-права на хості. Це мінімізує можливий збиток при взломі. --user 1000
означає, що контейнер буде запущений від користувача з UID 1000 (На більшості Linux систем це перший створений користувач). Як що в контейнере нема користувача с таким UID, то процеси все одно запустяться і можуть не мати доступу до файлів або дерікторій. Це може бути корисно для запуску додатків, які не потребують root-доступу, або для обмеження доступу до системних ресурсів.
Додаткові механізми безпеки:
-
Seccomp — фільтрація системних викликів, що дозволяє обмежити доступ до небезпечних системних викликів.
-
AppArmor/SELinux — мандатне управління доступом, що дозволяє контролювати доступ до ресурсів на основі політик безпеки.
Namespaces — это механизм ядра Linux, который позволяет изолировать системные ресурсы между группами процессов.
Namespace |
Изолирует |
Детали |
pid |
ID процессов |
Процессы не видят друг друга |
net |
Сетевые интерфейсы и IP-стек |
Своя сеть, DNS, маршруты |
mnt |
Файловую систему и монтирования |
Изоляция /, /proc, /sys |
ipc |
Shared memory |
Не пересекаются IPC-ресурсы |
uts |
Hostname, domainname |
У контейнера свой hostname |
user |
UID/GID |
Разделение root внутри контейнера и на хосте |
Контроль над ресурсами |
Контейнер — член своего cgroup |
-
Не запускайте контейнери під root-користувачем всередині контейнера.
-
Відключайте зайві Capabilities.
-
Використовуйте AppArmor/SELinux профілі.
-
Скануйте образи на уразливості.
-
Своєчасно оновлюйте.
Перевагами контейнерів є:
-
Однакове середовище в розробці, тестуванні й продакшені (проблема "It works on my machine" вирішена)
-
Швидкий запуск і масштабування
-
Економія ресурсів у порівнянні з віртуальними машинами
-
Портативність — запуск на будь-якій платформі з Docker Engine
-
Легко інтегруються у CI/CD процеси
Недоліками є:
-
Безпека — ізоляція не така сильна, як у віртуальних машинах
-
Складність управління — потребують додаткових інструментів для оркестрації (Kubernetes, Docker Swarm)
-
Залежність від хостової ОС — не можуть запускати різні ОС (наприклад, Windows-контейнер на Linux)
Далі перейдемо до практичного використання Docker-контейнерів.
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
-
--name
— вказує ім’я контейнера; -
--env-file
— передає змінні середовища з файлу; -
--cpus
— обмежує використання CPU (наприклад,--cpus="1.5"
); -
--cpu-period
— встановлює період для обмеження CPU (наприклад,--cpu-period=100000
); -
--cpu-quota
— встановлює квоту для обмеження CPU (наприклад,--cpu-quota=50000
); -
-m
або--memory
— обмежує використання пам’яті; -
--memory-swap
— обмежує використання пам’яті з урахуванням swap; -
--cpuset-cpus
— обмежує використання певних CPU; -
--pids-limit
— обмежує кількість процесів у контейнері (наприклад,--pids-limit=100
); -
--device-read-bps
— обмежує швидкість читання з пристрою (наприклад,--device-read-bps /dev/sda:1mb
); -
it
— запускає контейнер в інтерактивному режимі (tty) (поєднання-i
та-t
); -
-i
— інтерактивний режим (stdin залишається відкритим); -
-t
— виділяє псевдотермінал (tty); -
--rm
— автоматично видаляє контейнер після завершення; -
--restart
— вказує політику перезапуску контейнера (наприклад,always
,unless-stopped
,on-failure
); -
--network
— вказує мережу, до якої підключити контейнер; -
--entrypoint
— вказує точку входу для контейнера (перезаписує значення з образу); -
--mount
— більш гнучкий спосіб підключення томів (наприклад,--mount source=mydata,target=/app/data
). -
--privileged
— надає контейнеру всі можливості хостової системи (не рекомендується використовувати без потреби).
Для того, щоб опублікувати порт контейнера на зовні, використовуйте флаг -p
або --publish
. Наприклад:
docker run -p <HOST_PORT>:<CONTAINER_PORT> myimage
де:
-
<HOST_PORT>
— порт на хості, на якому буде доступний контейнер; -
<CONTAINER_PORT>
— порт всередині контейнера, на якому працює додаток.
docker run -e APP_ENV=prod -e DB_PASS=secret myimage
docker run --env-file <file> myimage
--cpus
— це ручна огортка над --cpu-period
та --cpu-quota
, яка дозволяє легко обмежити використання CPU контейнером. Але якщо треба точне управління, наприклад, змінити довжину періодів (для real-time додатків), задати квоту не в цілих ядрах або адаптувати поведінку в embedded-середовищах, то --cpu-period
+ --cpu-quota
дають повний контроль. Наведемо приклад:
docker run --rm -it \
--cpu-period=100000 \
--cpu-quota=50000 \
ubuntu
у цьому випадку контейнер буде обмежений до 50000 / 100000 = 0.5 → 50% одного ядра CPU. Це означає, що контейнер може використовувати максимум 50% CPU в кожному періоді в 100000 мікросекунд (або 0.1 секунди) тобто 0.05 секунди прицює 0.05 секунди не працює.
Для запуску контейнера в інтерактивному режимі з доступом до командного рядка, використовуйте флаг -it
(поєднання -i
та -t
). Це дозволяє вам взаємодіяти з контейнером через термінал. Наприклад:
docker exec -it <CONTAAINER_NAME> bash
Тобто ця команда дозволяє виконувати команди в середені контейнера. В цьому ми викликаєм оболочку bash. Також це може бути корисним якщо на просто треба перевірити наявність файлу в контейнері, наприклад:
docker exec -it <CONTAINER_NAME> ls -la
Але в цілому це дозволяє виконувати будь які команди в середені контейнеру.
Для того, щоб автоматично видалити контейнер після завершення його роботи, використовуйте флаг --rm
. Це дозволяє уникнути накопичення зупинених контейнерів. Наприклад:
docker run --rm myimage
А якщо взяти попередній приклад, наприклад ви створили Docker Image і просто хочете субу перевірити чи є там наприклад якійсь файл то команда
`docker run --rm <IMAGE_NAME> ls -l <PATH_TO_FILE>`
Тобто докер запускає контейнер виконує команда і по завершені команди видаляє контейнер.
docker run --network=none myimage
Флаг --privileged
дає контейнеру майже необмежений доступ до хостової системи. Це може бути корисно для деяких сценаріїв, але також значно знижує безпеку, тому його слід використовувати з обережністю. Використання цього флага:
-
Усі Linux Capabilities (capabilities) надаються контейнеру;
-
Доступ до всіх пристроїв в /dev;
-
Можливість монтувати файлові системи, змінювати мережеві інтерфейси та інші системні ресурси;
-
Робота з AppArmor/SELinux може бути ослаблена.
docker run --privileged myimage
Контейнер маже бути в наступних станах:
Контейнер має стан Running, коли він запущений і виконує процеси. У цьому стані всі процеси активні, і контейнер може обробляти запити.
Контейнер має стан Paused, коли він призупинений. У цьому стані всі процеси зупинені, але зберігають свій стан. Це може бути корисно для тимчасового призупинення роботи контейнера без його зупинки. Для того щоб призупинити контейнер, використовуйте команду:
docker pause <container_id>
Команда docker pause
надсилає сигнал SIGSTOP усім процесам контейнера. Всі процеси заморожуються (їх стан зберігається в пам’яті, але вони не виконуються). І контейнер переходить в стан Paused. Для відновлення контейнера до стану Running, використовуйте команду:
docker unpause <container_id>
Ця команда може бути корисною для тимчасового призупинення роботи контейнера, наприклад, для проведення технічного обслуговування або безпечного оновлення мережевого або дискового шару (у деяких сценаріях CI/CD або live-debug). Або для зупинки енергоємного процессу.
docker stop <container_id>
Комадна docker stop
посилає сигнал SIGTERM процесам в контейнері, даючи їм час для коректного завершення. Якщо процеси не завершуються протягом 10 секунд, Docker відправляє сигнал SIGKILL для примусового завершення. Але якщо необхідно одразу відправити сигнал SIGKILL то використовується команда docker kill
яка моментально зупиняє контейнер не даючи йому час на коректну зупинку процессів. Контейнер зупиняється, але його дані зберігаються, і ви можете знову запустити його пізніше. І переходить у стан Exited. Для відновлення контейнера до стану Running, використовуйте команду:
docker start <container_id>
Контейнер має стан Exited, коли він завершив свою роботу. Це може статися через успішне завершення процесу або через помилку. Контейнер все ще існує, і ви можете переглядати його логи або перезапустити його. Якщо контейнер одразу після запуску переходить в цей стан, це може бути через те, що процес в контейнері завершився з помилкою або не був запущений або був короткостроковим, наприклад docker run alpine ls -la
. Це може трапитись через декілька причин:
-
Невірна команда ENTRYPOINT або CMD в Dockerfile;
-
Відсутність необхідних залежностей або бібліотек в образі;
-
Помилки в коді додатку, які призводять до аварійного завершення;
-
Неправильні аргументи або змінні середовища, які передані при запуску контейнера.
Контейнер має стан Dead, коли він не відповідає на запити. Це може статися через серйозні помилки в процесах контейнера або проблеми з ресурсами. Контейнер все ще існує, але його неможливо перезапустити без видалення.
-
Використовуйте легкі образи (alpine, distroless).
-
Використовуйте шари з вже завантаженими залежностями.
-
Відкиньте непотрібні модулі (spring-devtools).
-
Механізми типу GraalVM native-image (якщо виправдано).
Розберемо корисні команди які необхідно знати для роботи з Docker Containers
docker logs <container_id>
С флагами -f
(follow) та --tail
можна "підглядати" в режимі реального часу.
-
Не публікуйте порти на зовні (не вказуйте -p).
-
Використовуйте firewall на хості.
-
Застосовуйте політики безпеки (docker network та інші).
Для того щоб передати файли з хоста в контейнер (або навпаки) без пересборки образа, використовуйте bind mount (-v /host/path:/container/path), приклад:
docker run -v /host/path:/container/path myimage
або копіюйте дані командою docker cp
приклад:
docker cp /host/path mycontainer:/container/path
Для того, щоб зберегти дані при перезапуску контейнера БД, використовуйте volume, наприклад:
docker run -v mydb-data:/var/lib/postgresql/data postgres
Перезапуск контейнера не затроне дані в томі.
docker run --cap-add=<cap_name> myimage
або для того щоб видаляти Capabilities з контейнера, використовуйте флаг --cap-drop
:
docker run --cap-drop=<cap_name> myimage
Для того, щоб перевірити які Capabilities має контейнер, використовуйте команду docker inspect
:
docker inspect <container_id>
та перегляньте секцію CapAdd/CapDrop. По замовчуванню є базовий набір (наприклад, NET_RAW та інші).
За замовчуванням JVM може "не бачити" обмеження cgroups. -XX:MaxRAMPercentage допомагає JVM коректно визначати доступну пам’ять. Інакше може бути OutOfMemoryError, якщо JVM буде думати, що доступна вся пам’ять хоста. -XX:MaxRAMFraction працює аналогічно, але відносно обсягу пам’яті. Приклад використання:
docker run -e JAVA_OPTS="-XX:MaxRAMPercentage=75.0" <IMAGE_NAME>
що означає, що JVM використовує 75% доступної пам’яті.
docker run -e JAVA_OPTS="-XX:MaxRAMFraction=0.5" <IMAGE_NAME>
що означає, що JVM використовує половину доступної пам’яті.
-
Мінімізуй образи (multi-stage builds, Alpine, distroless).
-
Run as non-root + drop capabilities.
-
Використовуй ReadOnly rootfs (--read-only), tmpfs для /tmp.
-
Monitor: docker stats, cAdvisor, Prometheus exporters.
-
Scan images на CVE (Trivy, Grype, Snyk).
-
Використовуй image signing (Cosign, Notary v2).
-
Автоматичне оновлення — через GitOps або image watchers.
2. QUESTIONS
-
Що таке Docker Image? Answer
-
Яку структуру має Docker Image? Answer
-
З чого складається Docker Image? Answer
-
Що таке Layer в Docker Image? Answer
-
Що таке Layer Cache в Docker Image? Answer
-
Які типи Docker Image існують? Answer
-
Як зберігати секрети в Docker Image? Answer
-
Як створити Docker Image? Answer
-
Як створити Docker Image з Multi-stage build? Answer
-
Як завантажити Docker Image з реєстру? Answer
-
Як опублікувати Docker Image в реєстр? Answer
-
Як додати теги до Docker Image? Answer
-
Як перевірити інформацію про Docker Image? Answer
-
Як видалити Docker Image? Answer
-
Що таке Dockerfile? Answer
-
Головні інструкції які використовуються в Dockerfile? Answer
-
Що означає
FROM
в Dockerfile? Answer -
Використання
FROM
. Answer -
Best Practices для
FROM
. Answer -
Що означає
RUN
в Dockerfile? Answer -
Використання
RUN
. Answer -
Best Practices для
RUN
. Answer -
Що означає
CMD
в Dockerfile? Answer -
Використання
CMD
. Answer -
Кратко про
CMD
. Answer -
Що означає
ENTRYPOINT
в Dockerfile? Answer -
Використання
ENTRYPOINT
. Answer -
Кратко про
ENTRYPOINT
. Answer -
В чому різниця між
CMD
таENTRYPOINT
. Answer -
Що означає
COPY
в Dockerfile? Answer -
Що означає
ADD
в Dockerfile? Answer -
Використання
ADD
. Answer -
В чому різниця між
COPY
таADD
. Answer -
Що означає
WORKDIR
в Dockerfile? Answer -
Що означає
EXPOSE
в Dockerfile? Answer -
Що означає
ENV
в Dockerfile? Answer -
Використання
ENV
. Answer -
Що означає
ARG
в Dockerfile? Answer -
Використання
ARG
. Answer -
В чому різниця між
ENV
таARG
. Answer -
Best Practices для
ENV
таARG
. Answer -
Коротко для
ENV
таARG
. Answer -
Що означає
USER
в Dockerfile? Answer -
Що означає
VOLUME
в Dockerfile? Answer -
Що означає
LABEL
в Dockerfile? Answer -
Що означає
HEALTHCHECK
в Dockerfile? Answer -
Що означає
SHELL
в Dockerfile? Answer -
Як тестувати Dockerfile? Answer
-
Best Practices при роботі з Dockerfile? Answer
-
Що таке VOLUME в Docker? Answer
-
Чи можна підключати один том до декількох контейнерів? Answer
-
Які типи томів існують в Docker? Answer
-
Що таке Anonymous Volume? Answer
-
Що таке Bind Mount? Answer
-
Що таке Named Volume? Answer
-
Різниця між Bind Mount та Volume? Answer
-
Різниця між Named Volume та Bind Mount Answer
-
Різниця між Named Volume та Bind Mount та Anonymous Volume? Answer
-
Необхідно лі монтувати volume для запису логів додатку? Answer
-
Цілі використання томів в Docker? Answer
-
Які драйвери доступні для томів в Docker? Answer
-
Опції для під час створення Volume? Answer
-
Як видалити невикорсовуємі тома? Answer
-
Як подивитись все доступні Volumes? Answer
-
Що таке Docker Container? Answer
-
Відмінності Docker Container від VM? Answer
-
Чому Docker Container запускається швидше, ніж VM? Answer
-
Как запустить контейнер в фоновом режиме? Answer
-
Як обмежити ресурси контейнера по CPU та пам’яті?Answer
-
Які стани може мати контейнер? Answer
-
Через що контейнер може бути завершеним одразу після запуску? Answer
-
Чим відрізняються
docker stop
відdocker kill
? Answer -
Флаги
docker run
? Answer -
Як зменьшити час запуску Spring Boot в контейнере? Answer
-
Як шукати проблеми мережі між контейнерами? Answer
-
Як і які обмеження можно задати і якими фалгами? Answer
-
Як виконати команду в середені запущеного контейнеру? Answer
-
Як подивитись логі працюючого контейнера? Answer
-
Як зробити порт видиммин наружу контейнера? Answer
-
Як встановити змінні середовища при запуске контейнера? Answer
-
Чи можна використовувати файл зі змінними для запуску контейнера? Answer
-
Як обмежити доступ до контейнеру зовні? Answer
-
Як передати файли до контейнеру (або навпаки) без пересборки образу? Answer
-
Як зберегти данні при перезапуску контейнера? Answer
-
Як додати Capabilities є у контейнера? Answer
-
Як перевірити, які Capabilities є у контейнера? Answer
-
Що робить флаг
--privileged
при запуску контейнера? Answer -
Навіщо використовувати non-root user всередині Docker-контейнера? Answer
-
Як запустити контейнер без сетевого стека? Answer
-
Як забеспечується безпека Docker-контейнерів? Answer
-
Головні аспекти безпеки Docker-контейнерів? Answer
-
Яким чином Docker Container забезпечує ізоляцію процесів? Answer
-
Які Best Practices Docker-контейнерів? Answer
Introduced in different languages: