SSD Nodes Learn 🎉 VPS від $5.50/міс
Посібники Matt ConnorВід Matt Connor

Як створити бекап та оновити стек Docker Compose

Дізнайтеся, як правильно створити резервну копію Docker Compose. Ми розберемо, які томи копіювати, як зробити дамп бази даних та безпечно оновити стек без втрати критичних даних.

Що має містити резервна копія стека Docker Compose

Резервна копія стека Docker Compose повинна складатися з чотирьох окремих елементів, втрата будь-якого з яких призведе до неможливості відновлення застосунку: файл compose, файл .env поруч із ним, вміст усіх томів (volumes) та дамп бази даних, створений власним клієнтом цієї бази. Копіювання файлів бази даних під час роботи контейнера не є резервним копіюванням. Оновлення використовують той самий перелік плюс одне правило: створюйте резервну копію перед виконанням pull, оскільки міграції схеми розраховані на прямий хід, і більшість проєктів не передбачають шляху назад.

Усе, що наведено нижче, передбачає, що стек уже розгорнуто і команда docker compose ps показує його роботу. У прикладах використовується директорія проєкту /srv/myapp із сервісами, названими app та db. Підставте власні назви. Команди навмисно залишені загальними, оскільки критичні компоненти — томи та база даних — працюють однаково незалежно від самого застосунку.

З’ясуйте, що саме зберігає ваш стек

cd /srv/myapp
docker compose ps
docker compose config --volumes
docker volume ls --filter label=com.docker.compose.project=myapp

docker compose config --volumes виводить короткі назви іменованих томів, оголошених у вашому файлі. docker volume ls виводить назви, які ці томи фактично мають на диску. Ці два списки відрізняються, оскільки Compose додає назву проєкту на початку: том, записаний як db_data у файлі, існує як myapp_db_data. Назва проєкту за замовчуванням збігається з назвою каталогу, тому перейменування каталогу спрямовує стек на новий набір порожніх томів, залишаючи старі з вашими даними. Кожна команда нижче потребує використання реальної назви з docker volume ls.

Bind mounts не відображаються в жодному зі списків. У файлі compose це записи, де шлях до хоста вказано ліворуч від двокрапки, ./config:/app/config. Це звичайні каталоги на хості, тому звичайні інструменти мають до них доступ. Іменовані томи розташовані в /var/lib/docker/volumes/, а docker volume inspect --format '{{.Mountpoint}}' myapp_db_data виводить точний шлях до одного з них. Тип, який використовує ваш стек, впливає на спосіб копіювання, а в bind mounts проти іменованих томів детально описано всі переваги та недоліки.

Тепер розподіліть знайдене на дві групи. Деякі томи містять стан, який неможливо відтворити: завантажені файли, згенеровані ключі, саму базу даних і все, що користувач ввів у застосунок. Інші містять похідні дані, такі як мініатюри та пошукові індекси, які застосунок може відновити самостійно. Резервне копіювання другої групи витрачає місце на диску та час на відновлення, не даючи жодної користі. Том кешу Redis — найочевидніший приклад: його втрата призводить лише до одного повільного першого запиту.

Створення резервної копії compose-файлу та файлу .env

Обидва файли розміщені на хості поруч один з одним, і жоден із них не знаходиться всередині volume. Файл .env містить пароль до бази даних, секрет застосунку та будь-які API-токени, тому саме цей файл перетворює набір volume на робочий застосунок. Він також зазвичай вказаний у .gitignore, а це означає, що план «моя конфігурація в git» виключає єдиний файл, який має найбільше значення. Зберігання секретів у файлі env є правильним підходом, і це покладає відповідний обов'язок на вашу систему резервного копіювання.

sudo install -d -m 700 -o "$USER" -g "$(id -gn)" /srv/backups/myapp
cp -a compose.yaml .env /srv/backups/myapp/
chmod 600 /srv/backups/myapp/.env

Скопіюйте кожен compose-файл, який використовує стек, а не лише перший. Стек, запущений за допомогою -f compose.yaml -f compose.prod.yaml, потребує обох файлів для відновлення в тому самому вигляді, а принцип об'єднання кількох compose-файлів визначає, які саме значення потраплять у контейнер.

Одне застереження пов'язує .env з volume. Офіційний образ Postgres зчитує POSTGRES_PASSWORD лише під час ініціалізації порожнього каталогу даних. Зміна цього значення пізніше не змінює пароль всередині бази даних. Якщо відновити volume минулого місяця поруч із сьогоднішнім .env, застосунок не зможе підключитися з помилкою FATAL: password authentication failed for user "appuser", хоча при перевірці обидва файли виглядатимуть коректно. Зберігайте .env та volume, створені в один і той самий момент часу, разом в одній резервній копії.

Створення дампу бази даних за допомогою власного клієнта

Сервер бази даних постійно записує дані у свої файли. tar файлів /var/lib/postgresql/data, зроблений під час роботи сервера, копіює деякі сторінки до запису, а деякі — після, тому архів містить суміш станів, які неможливо відтворити. Інструмент для створення дампів зчитує дані в межах однієї транзакції, тому файл містить один узгоджений стан. Саме ця різниця відокремлює резервну копію від простої копії.

docker compose exec -T db sh -c \
  'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc' \
  > /srv/backups/myapp/db-$(date +%F).dump

Використовуйте -T. Цей прапор вимикає виділення TTY; якщо TTY підключено, Docker транслює потік виводу до вашої оболонки, що пошкоджує бінарний дамп. Ви не дізнаєтеся про це, доки не спробуєте відновити дані. Одинарні лапки також важливі: вони запобігають розгортанню $POSTGRES_USER вашою хостовою оболонкою, тому розгортання виконується всередині контейнера з використанням значень, які вже задані у файлі compose. -Fc записує дамп у спеціальному форматі, який стискається під час створення та дозволяє pg_restore вибирати окремі об'єкти пізніше.

Ролі та їхні паролі зберігаються поза межами окремих баз даних, тому їх також слід вивантажити:

docker compose exec -T db sh -c 'pg_dumpall -U "$POSTGRES_USER" --globals-only' \
  > /srv/backups/myapp/globals.sql

Після цього перевірте, чи є файл дампом, а не повідомленням про помилку:

ls -lh /srv/backups/myapp/
head -c 5 /srv/backups/myapp/db-$(date +%F).dump

Дамп у спеціальному форматі починається з п'яти байтів PGDMP. Файл нульового розміру або такий, що починається з pg_dump:, означає, що команда завершилася помилкою. Оболонка створює вихідний файл ще до запуску команди, тому невдалий дамп залишає файл із коректним іменем і часовою міткою. Це найпоширеніша причина прихованих збоїв резервного копіювання.

Для MariaDB або MySQL клієнт змінюється, але принцип залишається тим самим:

docker compose exec -T db sh -c \
  'mariadb-dump -u root -p"$MARIADB_ROOT_PASSWORD" --single-transaction --databases "$MARIADB_DATABASE"' \
  > /srv/backups/myapp/db-$(date +%F).sql

--single-transaction забезпечує узгоджений дамп таблиць InnoDB без блокування запису. В образі MySQL команда має вигляд mysqldump, а змінні — MYSQL_ROOT_PASSWORD та MYSQL_DATABASE. В актуальних образах MariaDB mysqldump досі працює як сумісна назва для mariadb-dump. Зауважте, що пароль, вказаний у командному рядку, відображається у списку процесів контейнера протягом усього часу виконання дампу.

SQLite потребує особливого підходу. База даних — це один файл, але останні транзакції можуть зберігатися в окремому файлі -wal поруч, тому копіювання лише .db призведе до втрати найновіших записів. Якщо в образі є клієнт, sqlite3 /data/app.db ".backup '/data/app-backup.db'" створить узгоджену копію під час роботи застосунку. Якщо клієнта немає, зупиніть контейнер і скопіюйте файл .db разом із його супутниками -wal та -shm.

Якщо ваша база даних працює на хості, а не всередині стека, застосовуються ті самі команди без префікса docker compose exec, а статтю запуск бази даних у Docker або на хості варто прочитати перед наступним переналаштуванням системи.

Архівація томів

Іменований том не має шляху на хості, який можна редагувати вручну, тому підмонтуйте його до тимчасового контейнера та створіть архів звідти.

docker run --rm \
  -v myapp_uploads:/data:ro \
  -v /srv/backups/myapp:/backup \
  alpine:3 tar czf /backup/uploads.tar.gz -C /data .

Допоміжний контейнер монтує том у режимі лише для читання за шляхом /data, а ваш каталог для резервних копій — за шляхом /backup, після чого записує архів на хост. Прапор --rm видаляє допоміжний контейнер одразу після завершення роботи tar. Параметр :ro є важливим, оскільки помилка в команді tar не призведе до пошкодження вихідних даних. Використання -C /data . забезпечує коректне відновлення: він зберігає всі шляхи відносно кореня тому. Якщо вказати tar czf /backup/uploads.tar.gz /data, кожен шлях отримає провідний data/, тому під час відновлення всередині тому створиться /data/data, і застосунок побачить порожній каталог. Архів належить користувачу root, оскільки tar виконувався від імені root всередині контейнера. Виконайте sudo chown "$USER" /srv/backups/myapp/uploads.tar.gz, якщо це заважає, і прочитайте як PUID та PGID визначають власника файлів, якщо після відновлення застосунок не може прочитати файли.

Виконуйте це для кожного іменованого тому окремо. Для bind mounts контейнер не потрібен: tar czf /srv/backups/myapp/config.tar.gz -C /srv/myapp/config . виконує ту саму роботу безпосередньо на хості.

Для кожного тому вирішуйте окремо, чи потрібно зупиняти застосунок. Створення архіву tar «на льоту» для тому, який застосунок постійно перезаписує, може призвести до того, що файл буде скопійовано під час запису. Для каталогів із завантаженнями, де файли записуються один раз, а потім лише зчитуються, цей ризик мінімальний. Для будь-яких інших випадків зупиніть сервіс на час копіювання за допомогою docker compose stop app, а потім виконайте docker compose start app. Команда stop залишає контейнери та томи на місці, що саме і потрібно в цьому сценарії, і варто чітко розуміти різницю між down та stop перед тим, як вводити будь-яку з цих команд.

Не вважайте архів tar тому бази даних повноцінною резервною копією бази. Резервною копією є дамп. Архів тому зупиненої бази даних — це лише зручний спосіб швидкого відновлення, і не більше.

Порядок виконання операцій

  1. Скопіюйте файли compose та .env у каталог резервного копіювання.
  2. Виконайте дамп бази даних, поки вона ще працює.
  3. Зупиніть контейнер застосунку, якщо його томи змінюються на місці.
  4. Архівуйте кожен іменований том та кожен каталог із прив'язкою (bind-mount).
  5. Запустіть усе, що було зупинено, а потім підтвердьте стан за допомогою docker compose ps.
  6. Запишіть теги образів та хеші (digests), які використовує стек.
  7. Скопіюйте весь каталог резервного копіювання з цього сервера.

Крок 7 — це те, що люди зазвичай відкладають на потім.

Перенесення копії з сервера

Резервна копія на тому самому диску, де розміщено стек, захищає лише від ваших власних помилок. Один пошкоджений том, видалений сервер або втрачений обліковий запис призведуть до втрати обох копій одночасно. Передавайте каталог у сховище, яке не є цим VPS, за розкладом і з політикою зберігання. У резервному копіюванні restic з VPS описано налаштування репозиторію, прапорці зберігання та команду перевірки, тому немає потреби повторювати це тут.

restic також може зчитувати дамп безпосередньо з каналу (pipe), що дозволяє взагалі не записувати базу даних у відкритому вигляді на диск:

docker compose exec -T db sh -c 'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc' \
  | restic backup --stdin --stdin-filename db.dump

Який би інструмент ви не використовували, додайте розклад у systemd timer або cron job і налаштуйте сповіщення про помилки виконання завдання там, де ви їх побачите. Скрипт резервного копіювання, вивід якого нікуди не спрямовується, — це скрипт, який може перестати працювати на пів року, і ніхто про це не дізнається.

Перевірка резервної копії через тренування з відновлення

Резервна копія, яку ніхто не відновлював, — це лише гіпотеза. Наведене нижче тренування передбачає відновлення в другий стек, що працює паралельно з основним, тому продуктивне середовище продовжує обслуговувати запити, а ваші дії не вплинуть на нього.

Механізм базується на назві проєкту. Compose бере її з назви каталогу та додає до кожного контейнера й тому, які створює. Скопіюйте резервну копію в новий каталог, і відновлений стек автоматично отримає власні томи.

sudo install -d -m 700 -o "$USER" -g "$(id -gn)" /srv/myapp-restore
cd /srv/myapp-restore
cp /srv/backups/myapp/compose.yaml /srv/backups/myapp/.env .

Відредагуйте скопійований файл compose, щоб опублікований порт хоста не конфліктував із запущеним стеком: вкажіть 18080:8080 замість 8080:8080 або змініть змінну, яка задає його у скопійованому .env. Після цього створіть контейнери та їхні порожні томи, не запускаючи сервіси:

docker compose create
docker volume ls --filter label=com.docker.compose.project=myapp-restore

Друга команда має вивести ті самі назви томів, що й у продуктивному середовищі, але з префіксом myapp-restore_. Заповніть їх, запустіть базу даних окремо та завантажте дамп:

docker run --rm -v myapp-restore_uploads:/data -v /srv/backups/myapp:/backup \
  alpine:3 tar xzf /backup/uploads.tar.gz -C /data
docker compose up -d db
docker compose exec -T db sh -c \
  'pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" --clean --if-exists' \
  < /srv/backups/myapp/db-2026-08-16.dump

--clean --if-exists видаляє кожен об'єкт перед його повторним створенням, що робить процес відновлення повторюваним. Без цього параметра другий запуск у базу даних, яка вже містить ці таблиці, зупиниться з помилкою pg_restore: error: could not execute query: ERROR: relation "users" already exists.

Потім запустіть решту сервісів і перевірте їх так, як це робив би користувач:

docker compose up -d --wait
docker compose exec -T db sh -c 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\dt"'
docker compose logs --tail=50

docker compose up -d --wait блокує виконання, доки кожен сервіс не повідомить про стан "running" або "healthy", і завершується з ненульовим кодом, якщо це не вдається, що дозволяє автоматизувати цей крок. Якщо сервіс не переходить у стан "healthy", docker compose ps покаже його статус, а Compose healthchecks пояснить, що означає цей стовпець. Після цього відкрийте застосунок на альтернативному порті та увійдіть під дійсним обліковим записом. Створіть один запис і відкрийте один файл, що зберігається в томі. Ця пара — доказ того, що дамп відновлено, том відновлено, і вони узгоджуються між собою. Тренування, яке лише підтверджує завантаження сторінки входу, нічого не доводить щодо цілісності ваших даних.

Видаліть тестовий стек після успішного завершення перевірки:

docker compose down -v

Це єдиний випадок, коли -v є коректним прапорцем. У робочому каталозі та сама команда видалить томи, які ви намагаєтеся захистити.

Як оновити стек Compose

Ознайомтеся з примітками до випуску для кожної версії між тією, що ви використовуєте, і цільовою. Шукайте в них слова breaking та migration. Проєкти, що не підтримують перехід через кілька мажорних версій, зазначають це. Міграція, яка завершується помилкою, зазвичай повідомляє про це лише після того, як частково змінила схему даних.

Зафіксуйте поточний стан перед будь-якими змінами:

docker compose images
docker image inspect --format '{{index .RepoDigests 0}}' postgres:16.4

docker compose images виводить образ і тег, які використовує кожен сервіс зараз. Digest — це єдине значення, що ідентифікує образ однозначно, оскільки тег може бути будь-коли перепризначений на інший образ.

Зробіть резервну копію згідно з попередніми розділами та скопіюйте її за межі сервера. Робіть це навіть для патч-релізів. Найбільш ризиковані оновлення — це ті, до яких припиняють готуватися.

Зафіксуйте версію у файлі compose, оскільки latest не є версією:

services:
  db:
    image: postgres:16.4

При використанні image: postgres:latest команда docker compose pull завантажує те, на що вказує тег сьогодні, і ви не зможете ідентифікувати версію, яка працювала вчора. Фіксований тег перетворює оновлення на редагування одного рядка, яке можна переглянути через git diff і скасувати ще одним редагуванням. Зафіксуйте образ застосунку таким самим чином, взявши точну версію зі сторінки релізів проєкту.

Завантажте та перестворіть контейнери:

docker compose pull
docker compose up -d --wait

docker compose up -d порівнює файл із запущеними контейнерами та перестворює лише ті сервіси, чий образ або конфігурація змінилися. Команда не чіпає іменовані томи, тому новий контейнер запускається з наявними даними. У цьому полягає мета процедури, але також і ризик, оскільки під час першого запуску нової версії зазвичай виконується міграція схеми.

Стежте за процесом:

docker compose ps
docker compose logs -f --tail=100 app

Контейнер, що завершився помилкою, відображає Exited (1) у стовпці STATUS команди docker compose ps, а причину можна знайти в останніх рядках його журналу. Помилки міграції там дуже помітні, хоча в інших місцях вони невидимі. Коли журнали стабілізуються, увійдіть у систему та попрацюйте з застосунком протягом хвилини.

Якщо docker compose pull зупиняється з помилкою no space left on device, зазвичай причиною є старі шари образів. Очищення невикористовуваних образів Docker допоможе звільнити місце. Виконуйте очищення лише після того, як переконалися, що оновлення пройшло успішно, а не до того, оскільки старі шари потрібні для швидкого відкату.

Як виконати відкат, якщо оновлення пройшло невдало

Існує два сценарії, і вони мають різну вартість. Якщо нова версія не змінювала схему даних, відкат виконується одним рядком: поверніть старий тег у файл compose і запустіть docker compose up -d. Контейнер замінюється, томи залишаються на місці, а старий код зчитує дані, які він сам і записав.

Якщо нова версія мігрувала схему, старий код більше не може її зчитати. Міграції пишуться для виконання вперед, і більшість проєктів не постачають скриптів для відкату. Тому стара версія запускається, а потім видає помилку під час першого запиту до стовпця, який було перейменовано або видалено, з помилками типу ERROR: column "avatar_url" does not exist. Шлях назад — це дамп, який ви зробили перед оновленням: поверніть старий тег, видаліть том бази даних, створіть його порожнім, відновіть у нього дамп і запустіть сервіс. Без цього дампа шляху назад немає, саме тому резервне копіювання виконується перед оновленням.

Мажорні версії Postgres є найбільш критичними в цьому плані, і вони часто стають несподіванкою, оскільки помилка виникає під час оновлення, а не під час відкату. Формат даних на диску змінюється з кожним мажорним релізом. Змініть postgres:16.4 на postgres:17.2, запустіть docker compose up -d, і новий сервер відмовиться запускатися:

FATAL:  database files are incompatible with server
DETAIL:  The data directory was initialized by PostgreSQL version 16, which is not compatible with this version 17.2.

Образ не виконує pg_upgrade автоматично. Підтримуваний шлях у межах стека Compose: дамп, заміна, відновлення. Зробіть дамп, поки стара версія ще працює, виконайте docker compose down, видаліть том бази даних, встановіть новий тег, виконайте docker compose create для створення свіжого порожнього каталогу даних, запустіть базу даних, відновіть дамп, запустіть решту сервісів. Зберігайте старий дамп, доки нова мажорна версія не опрацює реальний трафік протягом доби. Мінорні оновлення в межах однієї мажорної версії, наприклад з 16.4 до 16.9, не потребують жодних додаткових дій, оскільки формат даних залишається стабільним, і контейнер просто запускається.

Чи є VPS-снапшоти резервною копією?

Вони є доповненням до неї, оскільки ці два методи мають різні сценарії відмови. Снапшот копіює весь диск на рівні гіпервізора, тому він дозволяє відновити всю машину за лічені хвилини, включно з тими даними, про резервне копіювання яких ви забули. Це робить його правильним інструментом для одного конкретного завдання: оновлення пошкодило сервер, і ви хочете повернути його до стану, у якому він був двадцять хвилин тому.

Для всього іншого це неефективний інструмент. Гранулярність обмежена цілою машиною, тому відновлення однієї видаленої таблиці означає розгортання цілого сервера деінде та вилучення з нього цієї таблиці. Термін зберігання зазвичай короткий. Копії, як правило, зберігаються в тому самому обліковому записі провайдера, що й сервер, тому втрата доступу до акаунта призводить до одночасної втрати сервера та його снапшотів. Крім того, снапшот працюючої машини фіксує базу даних у момент запису, тому при першому запуску база даних виконує відновлення після аварії (crash recovery), а всі транзакції, що були в процесі виконання, втрачаються.

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

Що може піти не так і що ви побачите

Прапор volumes під час down. docker compose down -v видаляє іменовані томи, оголошені у файлі, а Compose підтверджує це рядком Volume myapp_db_data Removed. Скасувати цю дію неможливо. Звичайна команда docker compose down залишає їх без змін. Використовуйте повну форму, docker compose down --volumes, щоб деструктивний прапор був словом, яке ви ввели свідомо.

Дамп без магічного рядка. pg_restore: error: did not find magic string in file header означає, що файл не є архівом. Найчастіша причина — відсутність -T у docker compose exec, оскільки при підключеному TTY потік даних перетворюється під час передачі в оболонку, і бінарний дамп пошкоджується. Зробіть дамп повторно з -T, а потім перевірте перші п'ять байтів за допомогою head -c 5.

Пароль, який не змінюється. FATAL: password authentication failed for user "appuser" після відновлення означає, що .env і каталог даних були створені в різний час. Образ встановлює цей пароль лише під час створення порожнього каталогу даних, тому подальше редагування .env нічого не змінює всередині бази даних. Відновіть відповідний .env або змініть пароль безпосередньо в базі даних за допомогою ALTER USER.

Другий, порожній том. Docker створює том за запитом, тому docker run -v myapp_upload:/data за відсутності s записує дані в абсолютно новий порожній том і повідомляє про успішне виконання. docker volume ls після цього покаже обидві назви, одна з яких буде порожньою. Копіюйте назви томів із docker volume ls, замість того щоб вводити їх по пам'яті.

Відновлення, спрямоване на production. Виконання команд відновлення в /srv/myapp замість /srv/myapp-restore призводить до перезапису робочих даних резервною копією, причому команди в обох місцях виглядають однаково. Перевіряйте pwd перед кожною командою відновлення та тримайте тестове середовище в окремому каталозі.

FAQ

Чи видаляє docker compose down мої дані?

Ні. docker compose down видаляє контейнери та мережу за замовчуванням, але залишає іменовані томи (named volumes) і bind mounts без змін. docker compose down -v видаляє іменовані томи, оголошені у вашому файлі, і це незворотна дія. Bind mounts — це каталоги на хост-машині, тому Compose ніколи їх не видаляє. Якщо ви хочете зупинити сервіси для створення резервної копії, не зачіпаючи нічого іншого, використовуйте docker compose stop.

Чи можна скопіювати каталог даних Postgres замість запуску pg_dump?

Тільки якщо контейнер зупинено. Поки сервер працює, його файли постійно змінюються, тому копія може містити неузгоджені дані, які неможливо відновити. Покопійне копіювання файлів також прив'язане до конкретної мажорної версії Postgres, тому воно не запуститься на іншій версії. Зупиніть контейнер, заархівуйте том, запустіть його знову і розглядайте цей результат як швидкий спосіб відновлення, а не як єдину резервну копію. Дамп — це портативна копія, з якої слід виконувати відновлення.

Як оновити Postgres до нової мажорної версії в Compose?

Зміни тегу недостатньо. Новий сервер відмовиться запускатися на старому каталозі даних і запише в журнал The data directory was initialized by PostgreSQL version 16, which is not compatible with this version 17.2. Виконайте pg_dump, поки стара версія ще працює, потім docker compose down, видаліть том бази даних, встановіть новий тег, виконайте docker compose create для створення нового порожнього тому, запустіть базу даних і відновіть у неї дамп. Зберігайте старий дамп, доки нова версія не опрацює реальний трафік.

Як часто слід робити резервні копії та як довго їх зберігати?

Підберіть інтервал відповідно до того, скільки роботи ви готові виконати повторно в разі втрати. Щоденне копіювання підходить для персонального стека або стека невеликої команди, плюс одна додаткова резервна копія вручну безпосередньо перед будь-яким оновленням. Щодо терміну зберігання: тримайте достатньо історії, щоб охопити пошкодження, які ви не помітили одразу, оскільки пошкоджену таблицю, знайдену в п'ятницю, неможливо відновити з копії за четвер. restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune — це прийнятна початкова політика. Незалежно від графіка, виконуйте відновлення з копії раз на квартал. Поки ви цього не зробили, у вас немає резервних копій, у вас є просто файли.

Чи потрібно зупиняти весь стек для створення резервної копії?

Зазвичай ні. Дамп бази даних є консистентним під час роботи сервера, тому база даних не потребує простою. Справжнє питання стосується томів. Якщо застосунок лише додає файли (наприклад, каталог завантажень), архівування «на льоту» є достатньо безпечним. Якщо застосунок перезаписує файли на місці, зупиніть цей конкретний сервіс на час копіювання за допомогою docker compose stop app, а після завершення запустіть його знову. Зупинка застосунку при працюючій базі даних — це зазвичай найкоротше безпечне вікно, яке можна організувати.