BashTex | Linux
2.58K subscribers
48 photos
9 videos
293 links
Авторский канал для тех, кто хочет глубже погрузиться в мир Linux.

Подойдет для разработчиков, системных администраторов и DevOps

Реклама: @dad_admin
Download Telegram
Резервное копирование 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
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Сны при температуре 40

BashTex 📱 #юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
😁13
Сбор данных с нескольких серверов


<(ssh host1 cmd) vs <(ssh host2 cmd)


Конструкция позволяет сравнивать состояние двух (или нескольких) машин без временных файлов, параллельно и максимально быстро.

Process substitution создает виртуальные файлы, в которые пишется вывод команд. SSH-запросы выполняются параллельно, а diff думает, что сравнивает два обычных файла:


diff <(ssh h1 cmd) <(ssh h2 cmd)


▪️ Лучшие практические примеры

▪️ Сравнение пакетов


diff <(ssh h1 "dpkg -l | sort") \
<(ssh h2 "dpkg -l | sort")


▪️ Конфиги (sshd_config)


diff -u <(ssh h1 "grep -v '^#' /etc/ssh/sshd_config") \
<(ssh h2 "grep -v '^#' /etc/ssh/sshd_config")


▪️ Сетевые соединения


diff <(ssh h1 "ss -tuna | sort") \
<(ssh h2 "ss -tuna | sort")


▪️ Docker-контейнеры


diff <(ssh h1 "docker ps --format '{{.Names}} {{.Image}}' | sort") \
<(ssh h2 "docker ps --format '{{.Names}} {{.Image}}' | sort")


▪️ Мини-функция


compare_hosts() {
diff <(ssh "$1" "$3") <(ssh "$2" "$3")
}


Использование:


compare_hosts node1 node2 "df -h"


BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
Сравнение authorized_keys между серверами

Когда в кластере несколько серверов, важно, чтобы доступ имели одни и те же пользователи с одинаковыми ключами. Несогласованность в authorized_keys будет частой точка входа для проблем.

▪️ Базовый прием: сравнение двух серверов


diff <(ssh h1 "sort ~/.ssh/authorized_keys") \
<(ssh h2 "sort ~/.ssh/authorized_keys")


Сразу видно какие ключи есть только на h1 и какие есть только на h2. Строки отличаются полностью, поэтому легко понять лишние.

▪️ Сравнение директорий для всех пользователей


compare_keys() {
user="$1"
diff <(ssh "$2" "sort /home/$user/.ssh/authorized_keys 2>/dev/null") \
<(ssh "$3" "sort /home/$user/.ssh/authorized_keys 2>/dev/null")
}


Использование:


compare_keys deploy h1 h2
compare_keys admin h1 h2


▪️ Мультисерверная проверка списка хостов


hosts=(h1 h2 h3)
base="h1"

for h in "${hosts[@]:1}"; do
echo "=== $base vs $h ==="
diff <(ssh "$base" "sort ~/.ssh/authorized_keys") \
<(ssh "$h" "sort ~/.ssh/authorized_keys")
done


Покажет отличия между эталоном и всеми остальными.

▪️ Поиск лишних ключей


ssh h1 "sort ~/.ssh/authorized_keys" \
| grep -vFf <(ssh h2 "sort ~/.ssh/authorized_keys")


Покажет ключи, присутствующие только на h1.

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4