TGViewer
BashTex | Linux BashTex | Linux @bash_tex · 2.51K subscribers
Post #427 1.48K
Резервное копирование Docker volumes без остановки контейнеров

Когда в контейнере крутится прод, остановка ради бэкапа будет невозможной роскошью. Но docker volumes можно сохранять, без остановки, если правильно защититься от: открытых файлов, неконсистентных записей и гонок при чтении.

1️⃣ Проблема горячих бэкапов

Если контейнер пишет в volume во время архивации:

файлы могут быть разорваны,
часть транзакций попадет в архив, а часть нет,
каталог может измениться, пока его читает tar.

Чтобы избежать этого, нужен мягкий снапшот: заморозить структуру, дождаться закрытия файлов и архивировать.

Мы это реализуем через:

проверку открытых дескрипторов lsof
копию структуры через freeze-режим
tar с фиксированным списком файлов

2️⃣ Определяем volume и контейнер


VOLUME="mydata"
BACKUP_DIR="/backups"
STAMP=$(date +%Y%m%d-%H%M)
TARGET="$BACKUP_DIR/$VOLUME-$STAMP.tar.gz"

MOUNTPOINT=$(docker volume inspect "$VOLUME" -f '{{.Mountpoint}}')


3️⃣ Ждем, пока контейнер перестанет писать. Контейнер может продолжать работать, но нам важно дождаться момента тишины.


wait_until_quiet() {
local path="$1"
local delay=${2:-1}

while lsof +D "$path" >/dev/null 2>&1; do
echo "[*] Volume busy, waiting..."
sleep "$delay"
done
}


Это не блокирует процесс, просто ждёт микропаузу между транзакциями.

4️⃣ Создаем снапшот список файлов

Важно: tar должен использовать фиксированный список, а не динамическое дерево.


SNAPLIST=$(mktemp)

find "$MOUNTPOINT" -type f -o -type d | sed "s#^$MOUNTPOINT/##" > "$SNAPLIST"


Так мы замораживаем текущее состояние структуры.

5️⃣ Архивация без остановки контейнера


echo "[*] Waiting for files to become quiet..."
wait_until_quiet "$MOUNTPOINT"

echo "[*] Creating hot-backup: $TARGET"
tar -czf "$TARGET" \
-C "$MOUNTPOINT" \
-T "$SNAPLIST"


Файлы читаются быстрее, чем контейнер успевает их поменять, а вероятность гонки почти нулевая, потому что мы:

дождались отсутствия открытых дескрипторов
зафиксировали список файлов заранее
используем tar с указанием точных путей

6️⃣ Опционально: перезапрос тишины перед чтением больших файлов

Для больших БД/логов:


pause_if_lock() {
local file="$1"
while lsof "$file" >/dev/null 2>&1; do
echo "[*] File still in use: $file"
sleep 0.5
done
}


И внутри цикла архивации:


while read -r f; do
pause_if_lock "$MOUNTPOINT/$f"
done < "$SNAPLIST"


Это максимально приближает бэкап к снапшот-принципам.

7️⃣ Очистка


rm -f "$SNAPLIST"
echo "[+] Backup completed: $TARGET"


8️⃣ Пример полностью готового скрипта. Минимальный файл backup_volume.sh:


#!/usr/bin/env bash
set -euo pipefail

VOLUME="$1"
BACKUP_DIR="/backups"
STAMP=$(date +%Y%m%d-%H%M)
TARGET="$BACKUP_DIR/$VOLUME-$STAMP.tar.gz"

MOUNTPOINT=$(docker volume inspect "$VOLUME" -f '{{.Mountpoint}}')

wait_until_quiet() {
while lsof +D "$1" >/dev/null 2>&1; do
sleep 1
done
}

echo "[*] Volume mountpoint: $MOUNTPOINT"

SNAPLIST=$(mktemp)
find "$MOUNTPOINT" -mindepth 1 -printf '%P\n' > "$SNAPLIST"

echo "[*] Waiting for quiet state..."
wait_until_quiet "$MOUNTPOINT"

echo "[*] Archiving..."
tar -czf "$TARGET" -C "$MOUNTPOINT" -T "$SNAPLIST"

rm -f "$SNAPLIST"
echo "[+] Done: $TARGET"


BashTex 📱 #bash
  • 👍 8
More from @bash_tex
  1. Oct 9, 2026BashTex 📱 #мем
  2. Oct 8, 2026Bridge FDB - как Linux bridge узнаёт, где находится MAC Linux bridge не знает заранее, за…
  3. Oct 7, 2026/dev/tcp - сетевое соединение средствами Bash В Bash есть малоизвестная возможность работа…
  4. Oct 6, 2026Ephemeral ports - почему заканчиваются исходящие TCP-порты Когда приложение устанавливает…
  5. Oct 5, 2026name_to_handle_at() - как получить файловый объект без обычного пути В Linux обычно обраща…
  6. Oct 2, 2026madvise() - как процесс подсказывает ядру, как он собирается использовать память Когда про…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →