Курс СРС SRS03
до ЛР2 рівень 2 → «4»↔ Лабораторна 2↔ Лекція 2⌨️ команди 8 · 1 нова
Самостійна робота · ~2.5 год

OverlayFS і шари образу: як влаштовано об'єднану файлову систему

🌌 Пласти міста-привида — С.І.Д. із гордістю розкладає на екрані власний образ на пласти — ті самі райони, покладені один на одного, які показує docker history: розберися, як OverlayFS склеює їх в одну вулицю, куди лягає все, що контейнер записує за сеанс, і чому нижні пласти ніхто не чіпає — тож із того самого образу можна підняти привида знову й знову, на будь-якій машині, куди він дотягнеться мережею.

📚 ТЕОРЕТИЧНІ ВІДОМОСТІ

Образ як стос лише-для-читання шарів

Docker-образ (image) — це не один файл, а впорядкований стос незмінних (read-only) шарів (layers), кожен із яких відповідає одній інструкції Dockerfile (RUN, COPY, ADD), що змінює файлову систему. Шари ідентифікуються за вмістом (хешем), тому шар, ідентичний уже завантаженому в іншому образі, не завантажується вдруге — саме тому спільна базова інструкція FROM ubuntu:24.04 у десятках образів займає місце на диску лише один раз. Переглянути список шарів конкретного образу можна командою docker history <image> (людяний вивід, з розміром і командою кожного шару) або docker inspect <image> у полі RootFS.Layers (точні digest-и).

Об'єднання цих незмінних шарів у єдине дерево файлів виконує OverlayFS — драйвер файлової системи ядра Linux, що працює за принципом «union mount». У термінах overlayfs є чотири ключові каталоги: lowerdir — один або декілька шарів лише для читання (у Docker це шари образу, з'єднані в порядку від найновішого до найстарішого); upperdir — єдиний шар, доступний на запис, що створюється окремо для кожного запущеного контейнера; workdir — службовий каталог, який overlayfs використовує внутрішньо для атомарних операцій (обов'язковий, але «прозорий» для користувача); і merged — фінальна точка монтування, яку контейнер бачить як свій корінь / — логічно об'єднаний вигляд усіх lowerdir і upperdir разом.

Ключовий механізм — copy-on-write (CoW). Коли процес усередині контейнера читає файл, що існує лише в lowerdir, overlayfs віддає його напряму з lowerdir без копіювання. Але щойно процес намагається змінити цей файл, спрацьовує стратегія «copy-up»: файл повністю копіюється в upperdir, і вже там застосовується зміна — оригінал у lowerdir лишається недоторканим. Видалення файлу, який існує в lowerdir, реалізується не фізичним видаленням (це неможливо — lowerdir лише для читання), а створенням спеціального «whiteout»-запису в upperdir, який каже overlayfs «приховати цей файл із merged-подання».

Саме тому docker rm <container> видаляє контейнер практично миттєво і без ризику для образу: видаляється лише upperdir (і workdir) цього конкретного контейнера — тонкий шар усіх змін, зроблених під час сеансу. Базові lowerdir-шари образу лишаються незайманими й готовими для наступного docker run того самого образу — звідси запуск нового контейнера з уже завантаженого образу настільки швидкий: нічого не копіюється заздалегідь, лише монтується новий порожній upperdir поверх спільних lowerdir.

Побачити реальні шляхи цих каталогів для конкретного контейнера можна командою docker inspect <container> --format '{{json .GraphDriver.Data}}' — вона поверне поля LowerDir, UpperDir, MergedDir, WorkDir як абсолютні шляхи на хості (типово під /var/lib/docker/overlay2/), що робить абстракцію цілком відчутною — можна зазирнути в upperdir напряму й побачити файли, які контейнер створив або змінив за час роботи.

📖 ОПРАЦЮВАТИ

Прочитати ядрову документацію Documentation/filesystems/overlayfs.rst (lowerdir/upperdir/merged/workdir) і виконати docker inspect та docker history для перегляду списку шарів у RootFS.Layers.

🖥️ ТЕРМІНАЛ — СПРОБУЙ САМ
🎯 ЗАВДАННЯ
  1. Виконати docker history для власного образу з попередньої ЛР і зіставити кожен рядок виводу з відповідною інструкцією Dockerfile.
  2. Запустити контейнер, усередині створити новий файл і змінити один існуючий (наприклад, з базового шару), потім через docker inspect --format '{{json .GraphDriver.Data}}' знайти шляхи LowerDir/UpperDir/MergedDir на хості й переглянути вміст UpperDir на самому хості.
  3. У тому самому UpperDir знайти whiteout-запис для файлу, який був видалений усередині контейнера (пошук файлів із символом-префіксом .wh.), і пояснити його призначення.
  4. Порівняти час запуску (time docker run --rm image ...) для образу з 3 шарами і для семантично ідентичного образу з 15 дрібних шарів; пояснити, чому кількість шарів майже не впливає на швидкість запуску, але впливає на розмір і швидкість docker pull.
  5. Видалити контейнер (docker rm) і переконатися, що образ (docker images) і його lowerdir-шари лишилися незмінними — запустити з того самого образу новий контейнер і підтвердити, що зміни з попереднього сеансу зникли.
❓ КОНТРОЛЬНІ ПИТАННЯ
  1. У якому з чотирьох каталогів OverlayFS (lowerdir, upperdir, merged, workdir) з'являються файли, змінені контейнером під час роботи?
  2. Що таке copy-on-write у контексті overlayfs і коли саме він спрацьовує?
  3. Як overlayfs реалізує видалення файлу, що фізично існує в lowerdir лише для читання?
  4. Чому docker rm видаляє контейнер практично миттєво незалежно від розміру базового образу?
  5. Чим пояснюється те, що дві сторонні команди FROM ubuntu:24.04 в різних Dockerfile не займають подвійне місце на диску?
  6. Яку роль виконує каталог workdir у overlayfs, якщо він не бере участі в merged-поданні напряму?
  7. Яка команда покаже реальний шлях upperdir конкретного запущеного контейнера на хості?
✅ САМОПЕРЕВІРКА

У якому з каталогів OverlayFS (lowerdir, upperdir, merged) з'являються файли, які контейнер створив під час роботи, і чому вони зникають після docker rm?

🥚 ПАСХАЛКА
У найнижчому пласті свого старого образу — ще зі списаної машини — С.І.Д. знайшов файл .pixel, якого ніхто не додавав. Стерти його з контейнера можна лише «білою дірою» (whiteout) у верхньому шарі, а в lowerdir він лежить далі — і проступає знову з кожного нового контейнера. «Деякі речі, ранере, лежать глибше за upperdir. Кіт із них перший».
⌨️ КОМАНДИ НА ЦІЙ СТОРІНЦІ 8 · 1 нова

Кожна команда терміналу з цієї сторінки — одним реченням. Позначка нове — команда зустрічається в курсі вперше; далі вважаємо її знайомою.

docker inspect
Друкує повний JSON-опис контейнера чи образу; -f '{{.State.Pid}}' — витягнути одне поле.
docker
Клієнт Docker: усі дії з образами й контейнерами — через його підкоманди (docker <підкоманда> --help — довідка).
python3
Інтерпретатор Python; тут — python3 -m http.server 80, найкоротший спосіб підняти тестовий HTTP-сервер.
ls
Показує список файлів у каталозі; ls -la — з правами, власником, розміром і прихованими файлами.
findнове
Шукає файли за ім'ям чи ознаками рекурсивно по каталогах (find . -name '*.rs').
docker history
Показує шари образу: яка інструкція Dockerfile створила кожен і скільки він займає.
docker rm
Видаляє контейнер (docker rm -f name — навіть якщо він ще працює).
docker run
Створює й запускає контейнер з образу (docker run -it ubuntu:24.04 bash — інтерактивно з терміналом; -d — у фоні; --rm — видалити після виходу; -p 8080:80 — прокинути порт).

💡 Прочитати README прямо в терміналі: cat README.md (виведе весь файл) або less README.md (посторінково; вихід — клавіша q).
Довідка з будь-якої команди: man curl (повний посібник, вихід — q) або коротко curl --help; для підкоманд — docker run --help, cargo build --help.

← SRS02усі темиSRS04 →