Модуль 32

Файлові права та volumes у контейнерах

Це чудове завдання! Вмикаємо режим CS50, налаштовуємо мікрофон, беремо віртуальну крейду і... поїхали!

Ось ваш урок.


📦 Файлові права та Volumes у контейнерах: Як не втратити дані?

Привіт, друзі! Радий бачити вас знову.

1. 🔥 Вступ: Проблема та мотивація

Уявіть собі таку ситуацію. Ви запустили базу даних у Docker-контейнері. Все працює ідеально: ви реєструєте користувачів, зберігаєте замовлення, ваш стартап злітає! Але раптом ви помічаєте, що потрібно оновити версію бази даних або просто перезавантажити сервер.

Ви зупиняєте контейнер. Видаляєте його. Запускаєте новий (оновлений). І... Пусто.

База порожня. Користувачів немає. Замовлень немає. Ваш стартап збанкрутував за 2 хвилини. Чому?

Або інша ситуація: ви намагаєтеся зберегти файл логів із контейнера на свій комп'ютер, а Docker кричить вам у відповідь: "Permission Denied". Ви ж адміністратор свого комп'ютера! Чому якийсь контейнер вам вказує?

Без розуміння Volumes (томів) та прав доступу робота з контейнерами — це як життя в готелі:

🏨 Аналогія: Контейнер — це номер у готелі. Ви можете там жити, розкладати речі, клеїти стікери на дзеркало. Але як тільки ви виїжджаєте (видаляєте контейнер), покоївка прибирає все. Наступний гість заїжджає в ідеально чистий номер.

А якщо ви хочете зберегти свої речі (дані) після виїзду? Вам потрібен сейф або камера схову, яка не залежить від конкретного номеру. Оце і є Volume.

Сьогодні ми навчимося робити дані безсмертними та домовлятися з Linux про права доступу. Погнали!


2. 🧠 Теоретична база (без сухої академічності)

Давайте заглянемо "під капот", але не будемо там бруднити руки мастилом занадто сильно.

Ефемерність контейнерів

За замовчуванням файлова система контейнера — ефемерна (тимчасова). Вона складається з шарів (layers). Коли ви щось пишете в контейнері, ви пишете в тоненький верхній шар, який зникає разом із контейнером.

Як зберегти дані? (Persistence)

У Docker є два основних способи "пробити дірку" з контейнера назовні, щоб зберегти дані:

  1. Volumes (Томи):

    • Це спеціальні папки, якими керує сам Docker.
    • Вони лежать десь у надрах Docker (зазвичай /var/lib/docker/volumes/...).
    • Інтуїтивно: Це як банківська комірка. Ви просто знаєте її номер (ім'я), а банк (Docker) сам дбає про безпеку і розміщення.
    • Найкраще для: Баз даних, логів, постійного сховища.
  2. Bind Mounts (Примонтовані папки):

    • Це пряме посилання на папку на вашому комп'ютері (хості).
    • Ви кажете: "Візьми мою папку C:\Projects\Code і встав її в контейнер у папку /app".
    • Інтуїтивно: Це як відкрите вікно між вашою кімнатою і вулицею. Все, що ви кидаєте у вікно, опиняється на вулиці, і навпаки.
    • Найкраще для: Розробки (змінили код у редакторі — він змінився в контейнері), конфігураційних файлів.

Проблема прав доступу (Permissions) 👮‍♂️

Ось тут стає цікаво. * Всередині контейнера процес може працювати від імені root (суперкористувача). * Ззовні (на хості) ці файли теж мають власника. * Якщо контейнер створює файл як root, а ви на хості — звичайний користувач oleg, ви можете не мати прав редагувати або навіть видалити цей файл! * Linux дивиться на цифри UID (User ID). Якщо файл належить ID 0 (root), а ваш ID 1000 — вибачайте, доступ заборонено.

❗️ Запам'ятайте обов'язково: Дані бази даних ЗАВЖДИ повинні бути у Volume або Bind Mount. Ніколи не зберігайте важливі дані просто "всередині" контейнера.


3. 🧪 Приклади (від простого до реального)

Приклад 1: Зникнення даних (Магія Гудіні)

Давайте переконаємося, що дані дійсно зникають.

# 1. Запускаємо Ubuntu і створюємо файл
docker run -it --name test-container ubuntu bash
# (Всередині контейнера)
echo "Hello CS50!" > /secret.txt
exit

Тепер запитання до вас: Якщо я видалю цей контейнер і запущу такий самий новий, чи буде там файл /secret.txt?

Відповідь: Ні.

docker rm test-container
docker run -it ubuntu cat /secret.txt
# cat: /secret.txt: No such file or directory

Він зник назавжди.

Приклад 2: Використання Volume (Банківська комірка)

Тепер зробимо це правильно. Створимо іменований Volume.

# Створюємо сховище
docker volume create my-data

# Монтуємо його в папку /data всередині контейнера
docker run -d --name writer -v my-data:/data ubuntu \
  bash -c "echo 'Я тут надовго!' > /data/persistent.txt && sleep 1000"
  • my-data — це назва сховища на хості (у "банку" Docker).
  • /data — це папка всередині контейнера.

Тепер ми видаляємо контейнер writer без жалю!

docker rm -f writer

І запускаємо абсолютно новий контейнер, підключаючи до нього ту саму комірку:

docker run --rm -v my-data:/data ubuntu cat /data/persistent.txt

Результат: Я тут надовго! Вуаля! Контейнер помер, але дані живуть.

Приклад 3: Bind Mount для розробки (Вікно)

Уявіть, що ви пишете вебсайт. Ви хочете змінити index.html на своєму комп'ютері й одразу побачити зміни в браузері, не перезбираючи контейнер.

Створіть файл index.html у поточній папці:

<h1>Hello World</h1>

Запустіть Nginx (вебсервер), прокинувши поточну папку ($(pwd)) всередину:

docker run -d -p 8080:80 -v $(pwd):/usr/share/nginx/html:ro nginx

(Зверніть увагу на :ro в кінці — read-only. Ми дозволяємо контейнеру тільки читати наш файл, але не змінювати його. Безпека!)

Тепер відкрийте localhost:8080. Бачите "Hello World"? Змініть файл на хості (на своєму ПК). Оновіть сторінку. Текст змінився!


4. 🛠 Практична частина

Час закачати рукави. Виконайте ці завдання:

🔹 Завдання 1: Вічна База Даних

  1. Запустіть контейнер postgres, не вказуючи volume. Створіть там таблицю.
  2. Видаліть контейнер. Запустіть знову. Переконайтеся, що таблиця зникла.
  3. Тепер запустіть postgres з опцією -v pgdata:/var/lib/postgresql/data.
  4. Створіть таблицю. Видаліть контейнер. Запустіть знову (з тим самим volume).
  5. Мета: Переконатися, що дані збереглися.

🔹 Завдання 2: Обмін даними (Місток)

  1. Створіть volume shared-logs.
  2. Запустіть контейнер "Письменник" (наприклад, alpine), який кожну секунду пише поточний час у файл /logs/time.log. Підключіть volume до /logs.
  3. Запустіть окремий контейнер "Читач", який використовує той самий volume і робить tail -f /logs/time.log.
  4. Мета: Побачити, як два різні контейнери спілкуються через спільне сховище.

🔹 Завдання 3: "А що, якщо..." (Конфлікт)

Що буде, якщо ви змонтуєте пусту папку з вашого хоста (Bind Mount) у папку контейнера, де вже є файли (наприклад, /etc/nginx/ у контейнері nginx)? 1. Створіть пусту папку empty_config. 2. Запустіть: docker run -it -v $(pwd)/empty_config:/etc/nginx nginx ls /etc/nginx. 3. Що ви побачите? Чому Nginx може не запуститися? (Підказка: Монтування "перекриває" вміст папки контейнера).

🔹 Міні-кейс: Виправлення помилки (Permission Hell)

Ситуація: Ви змонтували папку з хоста в контейнер Node.js. Контейнер працює від користувача node, але папка на хості належить вам (root або ваш user). Програма падає з помилкою EACCES: permission denied, коли намагається створити кеш-файл. Завдання: Знайдіть у документації або Google, як передати поточний uid (user id) у контейнер або як змінити права на папку, щоб контейнер міг у неї писати.


5. 💡 Мислення як у розробника

Як на цю тему дивляться Senior-розробники?

  1. Дані — це святе, код — це сміття. Досвідчений розробник може видалити всі контейнери однією командою (docker rm -f $(docker ps -aq)) і не спітніти. Чому? Тому що всі важливі дані лежать у Volumes або зовнішніх сховищах (S3, хмарні БД). Якщо ви боїтеся видалити контейнер — ви щось зробили неправильно.

  2. Не використовуйте Bind Mounts у продакшені (зазвичай). Для локальної розробки Bind Mounts — це супер (зручно редагувати код). Але на сервері краще використовувати Docker Volumes. Вони швидші, безпечніші й не залежать від структури папок конкретного сервера.

  3. Принцип найменших привілеїв. Бачили прапорець :ro (read-only) у прикладі з Nginx? Якщо контейнеру не потрібно писати у папку — забороніть йому це. Це захистить ваш код від випадкового видалення або вірусу-шифрувальника всередині контейнера.

  4. Типова помилка новачка: Робити chmod 777 (дозволити все всім) на папку, щоб "просто запрацювало". Чому це погано: Це як залишити двері квартири відчиненими, бо вам ліньки шукати ключі. Працюйте з UID/GID коректно.


6. 🧩 Підсумок

Отже, що ми сьогодні поклали у свій "рюкзак знань"?

  1. Контейнери "забувають" усе після видалення. Це фіча, а не баг.
  2. Volumes — це надійні "сейфи" для баз даних та важливих файлів.
  3. Bind Mounts — це "вікна" для зручної розробки та передачі конфігів.
  4. Права доступу (Permissions) мають збігатися всередині та ззовні, інакше буде біль.

Тепер ви можете сміливо вбивати свої контейнери, знаючи, що дані в безпеці!

🔜 У наступній серії: Ми навчилися запускати один контейнер. Але що, якщо нам потрібен вебсервер + база даних + кеш + аналітика? Запускати 4 команди вручну? Ні! Наступного разу ми познайомимося з диригентом цього оркестру — Docker Compose.

Це був CS50... тобто, урок про Docker Volumes. Є питання?