JavaRush /Курси /Docker for Spring /Disposable Redis та іменований том

Disposable Redis та іменований том

Docker for Spring
Рівень 19 , Лекція 3
Відкрита

1. Redis: volume чи без нього

До цього моменту в нас уже є базова зв’язка: застосунок бачить Redis, профіль cache вмикається, а контейнери підіймаються передбачувано. Питання про volume для першого запуску поки що не потрібне. Але в локальному житті воно спливає дуже швидко: чи має Redis переживати повторне створення контейнера, чи вигідніше тримати його disposable?

Коли ви вперше додаєте Redis у Compose-стек, рука й справді тягнеться зробити «як із PostgreSQL»: раз є сервіс, отже потрібен volume, щоб «нічого не загубилося». Інстинкт зрозумілий, але для Redis у ролі кешу він легко збиває з пантелику. Ми починаємо ставитися до прискорювача читання як до бази даних і тягнемо в локальне середовище зайвий стан там, де він не обов’язковий.

У локального середовища є дві протилежні потреби. З одного боку, хочеться, щоб після перезапуску все було «як учора»: швидко, прогріто, зручно. З іншого — хочеться легкого скидання: підняли середовище, попрацювали, видалили, підняли знову й отримали чистий, передбачуваний стан без учорашніх хвостів. Redis як кеш частіше допомагає саме другому сценарію.

Тому типовий сценарій тут простий: спочатку вважаємо Redis disposable. Це не заважає отримати перший робочий cache-path, а варіант із persistence розглядаємо як усвідомлену локальну політику, якщо він справді потрібен.

2. Redis як кеш: втрата даних не страшна

Причина проста: у Container-Ready Catalog Service Redis зберігає похідні дані, а не джерело правди. Джерело правди залишається в PostgreSQL. Коли Redis порожній, наступний запит просто робить промах кешу, читає дані з бази й знову кладе результат у кеш. Неприємно? Іноді так. Але це втрата кешу, а не втрата бізнес-даних.

Саме тому питання volume чи без нього починається не з «аби нічого не втратити», а з «чи потрібно нам узагалі зберігати цей стан між повторними створеннями контейнера».

/data і persistence у контейнері

Коли кажуть «Redis зберігає дані», у новачка в голові часто спливає образ «файл із базою даних». Насправді Redis передусім тримає дані в памʼяті процесу. Тобто поки контейнер живе й процес Redis запущений — дані є. Щойно процес перезапустився — памʼять обнулилася. Але в Redis є механізми persistence, які можуть зберігати стан на диск, а потім під час запуску завантажувати його назад. І саме тут зʼявляється папка /data.

В офіційному Docker-образі Redis каталог /data використовується як місце, куди Redis може записувати свої persistence-файли (наприклад, RDB snapshot або AOF, залежно від конфігурації). І далі починається найважливіше для Docker: якщо /data залишається всередині контейнера, то це лише writable layer конкретного контейнера. Щойно контейнер буде видалено й створено заново, цей стан зникне.

З named volume усе інакше. Ми даємо Redis окреме місце для зберігання даних, яке живе окремо від контейнера. Контейнер можна пересоздавати скільки завгодно, а volume залишиться. Якщо Redis налаштовано так, що справді записує persistence-файли в /data, то під час наступного запуску він зможе їх прочитати й відновити стан.

Корисно тримати в голові просту схему:

flowchart TD
    %% Ідея: дані живуть у памʼяті Redis, а /data — лише місце для опційного запису persistence-файлів
    A["Процес Redis (у памʼяті)"] -->|опційний запис persistence| B["/data всередині контейнера"]
    B -->|якщо немає volume| C["writable layer контейнера"]
    B -->|якщо є named volume| D["named volume (живе окремо)"]

Тут спеціально написано про опційний запис persistence-файлів, тому що persistence Redis — це окремий всесвіт налаштувань. Нам не потрібно занурюватися в усі деталі, але важливо розуміти: сам по собі volume ще не робить Redis «вічним», він лише дає місце, куди Redis може зберегти дані, якщо він це робить.

3. Варіант A: disposable Redis без volume

Якщо ми тримаємо Redis у межах ролі «кеш для повторних читань», то найчеснішим і найпростішим варіантом є Redis без volume. Це означає, що кеш живе рівно стільки, скільки живе конкретний контейнер, а під час повторного створення середовища ви отримуєте «чистий кеш». У локальній розробці це навіть приємно: ви часто хочете бачити поведінку промаху кешу після запуску, щоб розуміти, що кеш узагалі працює, а не «просто вчора випадково лишилося щось і тепер здається швидким».

У compose.yaml цей варіант виглядає мінімально. Зазвичай ви вже додали healthcheck із попередньої лекції, тому покажу фрагмент саме в такій «дорослій» формі:

services:
  redis:
    image: redis:8.6.0

    # У цьому варіанті ми НЕ монтуємо /data: контейнер створено заново — кеш «чистий»
    # volumes: відсутні свідомо

    healthcheck:
      # Перевіряємо, що Redis справді відповідає, а не просто «контейнер запущений»
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5

Зверніть увагу, що тут немає volumes. Це не помилка й не «забули». Це свідоме рішення: Redis як кеш допускає втрату стану, бо стан похідний. Якщо ви зробите docker compose down, контейнер Redis зникне. Коли ви зробите docker compose up, Redis створиться заново. Кеш буде порожній і далі заповнюватиметься в міру запитів до вашого API.

Цей підхід добре поєднується з дисципліною скидання середовища, яку ми відпрацьовували на Flyway і PostgreSQL. База може жити в volume, бо вона — джерело правди, і вам часто важливо зберігати дані між перезапусками. Redis же можна безболісно викинути, бо це лише прискорювач, який сам «прогріється» природним чином.

Якщо вам потрібно швидко перевірити, що Redis справді живий, а не «нібито додали в YAML і забули», найпростіший людський спосіб — пінгнути його через redis-cli просто всередині контейнера:

# Виконуємо команду всередині контейнера redis і очікуємо відповідь PONG
docker compose exec redis redis-cli ping
# PONG

Це не перетворює курс на «курс із Redis CLI», але дає вам один простий і чіткий індикатор readiness: Redis не лише запустився, а й відповідає на базову команду.

4. Варіант B: Redis з named volume

Іноді вам усе ж хочеться, щоб Redis переживав повторне створення контейнера. Наприклад, ви довго прогріваєте кеш або хочете, щоб після docker compose down і up локальне середовище стартувало одразу «теплим». У такому разі Redis можна підʼєднати до named volume. Це рівно той самий механізм, який ми використовуємо для PostgreSQL, лише мотивація інша: для Postgres це майже необхідність (інакше ви постійно втрачаєте дані), для Redis це усвідомлений вибір.

У Compose це виглядає так: Redis пише в /data, а ми монтуємо туди іменований том. Фрагмент:

services:
  redis:
    image: redis:8.6.0
    volumes:
      # Монтуємо іменований том у /data — сюди Redis МОЖЕ записувати persistence-файли, якщо це ввімкнено
      - redis-data:/data
    healthcheck:
      # Мінімальна перевірка доступності Redis
      test: ["CMD", "redis-cli", "ping"]

volumes:
  # Іменований том живе окремо від контейнерів і переживає docker compose down (без -v)
  redis-data:

Сенс redis-data у тому, що Docker зберігає цей volume окремо від контейнерів. Контейнер Redis можна видалити, а volume залишиться. Потім новий контейнер Redis знову змонтує цей volume в /data.

Тепер — найпрактичніша частина: як це пов’язано з down і down -v.

Коли ви робите docker compose down, Compose видаляє контейнери (і мережу), але named volumes за замовчуванням не видаляє. Це означає, що redis-data залишиться. Під час наступного up він знову підключиться.

Коли ви робите docker compose down -v, Compose видаляє і контейнери, і пов’язані named volumes. Тобто redis-data зникне. Під час наступного up volume створиться заново, і Redis буде чистим, ніби ви щойно його додали.

Корисно один раз побачити це як коротку «таблицю поведінки», щоб не тримати все в голові, ніби це магія YAML:

Команда Контейнер Redis Іменований том Redis Що це означає для кешу
docker compose down
видалено залишився потенційно можна відновити стан (якщо Redis писав у /data)
docker compose down -v
видалено видалено кеш точно стане порожнім після наступного up

І ось тут важливо не потрапити в пастку очікувань. Якщо ви підʼєднали volume, це ще не гарантія, що ви прямо «зберігаєте кеш». Redis може не встигнути записати persistence-файл до зупинки, або persistence може бути налаштований так, що він не зберігає те, що ви очікуєте. Тому в межах курсу краще ставитися до volume так: це інструмент, щоб дати Redis місце для збереження, але не обіцянка «кеш завжди переживатиме рестарти». Нам важливіша інженерна дисципліна навколо середовища і зрозуміла модель життя даних, ніж абсолютна гарантія, що кеш після перезапуску буде прогрітим.

Якщо вам хочеться переконатися, що volume взагалі існує й живе власним життям, ви можете просто подивитися список volumes:

# Дивимося всі Docker volumes: тут буде видно, чи пережив redis-data команду down
docker volume ls
# ... побачите щось на кшталт:
# local   docker-java-catalog-service_redis-data

Назва буде з префіксом проєкту Compose (зазвичай це імʼя каталогу), і це нормально: Docker намагається не створювати конфліктів між проєктами.

5. Стратегія для застосунку + PostgreSQL + Redis

Вибір «volume чи без volume» — це не справа смаку, а продовження архітектурної ролі Redis у проєкті. Сьогодні Redis — саме кеш. Це означає, що коли ви вагаєтеся, починайте з disposable-варіанта. Він простіший, чесніший і краще вчить правильного ставлення до кешу: кеш має покращувати життя, але не має ставати другою базою даних, яку ви змушені рятувати й створювати резервні копії «тому що інакше все зламається».

У disposable-варіанті Redis у вас виходить чіткий розподіл відповідальності. PostgreSQL зберігає реальний стан каталогу та export jobs, і саме тому в PostgreSQL є named volume. Redis зберігає лише прискорювачі читання, і тому Redis можна безболісно повторно створювати, особливо в локальному середовищі, де скидання середовища — нормальна щоденна операція. Ви швидше знаходите помилки конфігурації, бо вас не збивають «рештки вчорашнього кешу», які сьогодні маскують проблему.

Том для Redis стає виправданим, коли у вас зʼявляється конкретна причина. Наприклад, ви хочете порівняти поведінку після повторного створення середовища з «прогрітим кешем», або у вас такий локальний робочий процес, де ви піднімаєте середовище раз на день і хочете, щоб воно було швидким одразу. Але навіть у цьому разі варто тримати в голові межі: Redis усе одно не джерело правди, і ви не повинні писати код так, ніби Redis зобов’язаний пам’ятати все «назавжди». Якщо втрата Redis ламає сенс роботи сервісу, значить ви непомітно зробили його основним сховищем. Тоді змінюється не лише Compose-політика, а й уся модель застосунку.

Ще один практичний момент — документування. Якщо ви все-таки вмикаєте volume для Redis, це рішення має бути читабельним у compose.yaml. Не треба ховати його в десяти override-файлах або в «магічних» скриптах. Нехай студент (або ваш майбутній колега) відкриє YAML і одразу зрозуміє: Postgres зберігає дані в volume, Redis теж зберігає щось у volume, але з іншої причини. У цьому й цінність інфраструктурної дисципліни: вона не лише працює, а й пояснюється.

6. Типові помилки під час роботи з Redis

Помилка № 1: автоматично робити Redis «як PostgreSQL», не усвідомлюючи різниці в ролях.
Часто студент просто копіює патерн «сервіс → volume», і за кілька днів починає ставитися до Redis як до місця, де «лежить щось важливе». Проблема не в volume як такому, а в тому, що мислення зміщується: якщо Redis раптом став критичним, значить кеш перестав бути кешем. У нашому проєкті джерело правди залишається в PostgreSQL, а Redis зберігає лише похідний результат читання.

Помилка № 2: очікувати, що підʼєднання volume гарантує «після перезапуску кеш теплий».
Redis — in-memory сховище, і факт існування volume ще не означає, що дані туди постійно й негайно записуються. Persistence у Redis налаштовується окремо. Тому, якщо після down/up ви бачите порожній кеш, це не обов’язково «Docker зламався». Часто це просто означає, що ви очікували від кешу поведінки бази даних, а він вам нічого такого не обіцяв.

Помилка № 3: плутати restart і повторне створення контейнера, а потім дивуватися, чому дані «то є, то немає».
Перезапуск одного й того самого контейнера та видалення контейнера зі створенням нового — різні історії. У першому випадку може лишитися writable layer (і навіть якісь файли), у другому ви фактично починаєте з нуля. У Docker-оточенні важливо бути точним у термінах: «зупинив/запустив» і «видалив/створив заново» — це різні сценарії.

Помилка № 4: випадково видаляти потрібні volumes командою down -v, а потім намагатися «відновити» кеш, ніби це база.
down -v — потужна команда, і вона спеціально існує, щоб ви могли гарантовано скинути локальне середовище. Але якщо ви вмикали persisted Redis заради зручності, а потім автоматично виконуєте down -v «бо так звикли», ви самі собі стираєте стан. Важливо свідомо обирати: ви зараз робите скидання контейнерів чи скидання даних.

Помилка № 5: переносити persisted Redis у проєкт «за замовчуванням», не залишаючи простого disposable-шляху.
Для навчального проєкту й для рівня junior корисніше, коли базовий шлях простий: Redis можна повторно створити, і нічого страшного не станеться. Persisted-варіант краще залишати як свідоме розширення, а не як єдиний режим. Тоді середовище залишається легким і передбачуваним, а кеш — справді кешем, а не другою прихованою базою даних.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ