Бэкап, з якога можна аднавіцца, запускаецца па раскладзе без вашага ўдзелу, захоўвае адну копію па-за пляцоўкай, дзе ўзламаны сервер не зможа яе выдаліць, здымае базы даных ва ўзгодненым стане і нядаўна прайшоў праверку аднаўленнем з замерам часу. У restic гэта азначае зашыфраваны рэпазітарый у S3-сумяшчальным сховішчы пад аховай object lock або append-only сервера, дампы баз перад кожным запускам, таймер systemd з абвесткамі пра збоі і рэгулярныя вучэнні з аднаўлення. У гэтым дапаможніку такая схема сабрана для Linux-сервера, а тыя ж элементы падыходзяць і для машыны распрацоўшчыка.
Вызначце RPO і RTO да выбару інструментаў
Recovery point objective (RPO) паказвае, колькі даных вы гатовыя страціць, у адзінках часу. Recovery time objective (RTO) паказвае, колькі сэрвіс можа прастойваць падчас аднаўлення. Уладальнік сэрвісу адказвае на абодва пытанні простымі словамі: «мы можам страціць не больш за адзін дзень заказаў» і «крама павінна запрацаваць на працягу чатырох гадзін».
Найгоршая страта даных пры бэкапе па раскладзе прыкладна роўная інтэрвалу паміж запускамі плюс часу, за які запуск даходзіць да знешняга сховішча. Начное заданне, якое стартуе ў 02:00 і завяршае выгрузку ў 02:40, дае найгоршы RPO каля 24 гадзін 40 хвілін. Калі для базы даных гэта занадта шмат, рабіце яе бэкап часцей або дадайце архіваванне WAL.
RTO пераважна вызначаецца часам перадачы і перабудовы. Час перадачы ў секундах роўны аб’ёму даных у мегабітах, падзеленаму на хуткасць канала ў Мбіт/с. Аднаўленне 200 ГБ складае 1 600 000 мегабіт, таму на 100 Мбіт/с яно зойме 16 000 секунд, каля 4,4 гадзіны, яшчэ да аднаўлення базы. Калі гэта ўжо больш за RTO, адзін аддалены бакет мэты не забяспечыць, і патрэбная лакальная копія або рэзервовая сістэма.
Правіла 3-2-1 і яго пашырэнне 3-2-1-1-0
Правіла 3-2-1 азначае тры копіі даных на двух розных тыпах сховішчаў, з якіх адна копія знаходзіцца па-за пляцоўкай. На VPS першай копіяй з’яўляецца працоўны дыск, другой служыць лакальны дамп або рэпазітарый на асобным сховішчы, а трэцяя ляжыць у бакеце ў іншага правайдара ці ў іншым акаўнце. Другі раздзел на тым жа дыску памірае разам з першым, таму трымайце лакальную копію на іншай прыладзе (выбраць яе дапаможа дапаможнік па выбары NVMe SSD) або на іншым хосце.
Вытворцы сістэм рэзервовага капіравання папулярызавалі пашырэнне 3-2-1-1-0. Дадатковая адзінка азначае копію, якая знаходзіцца афлайн або з’яўляецца нязменнай, каб зламыснік з root на серверы і яго воблачнымі ўліковымі данымі ўсё роўна не змог яе выдаліць. Нуль азначае адсутнасць памылак у праверках цэласнасці і тэстах аднаўлення. Большасць схем прапускае менавіта апошнюю лічбу, хоць толькі яна паказвае, ці сапраўдныя астатнія чатыры.
Што ўключаць у бэкап і што выключаць
Захоўвайце тое, што нельга хутка ўзнавіць з публічнай крыніцы: /etc, код праграмы і загружаныя карыстальнікамі файлы ў /srv або /var/www, хатнія каталогі з ключамі SSH і GPG, crontab, TLS-матэрыялы, дампы баз даных і спіс усталяваных пакетаў з apt-mark showmanual. На машыне распрацоўшчыка каштоўныя неадпраўленая ў аддалены рэпазітарый праца, stash, dotfiles, ключы і дакументы.
Выключайце вялікія або ўзнаўляльныя даныя: кэшы, node_modules, віртуальныя асяроддзі, вынікі зборкі, вобразы кантэйнераў, вагі мадэлей і swap. Выключайце жывыя каталогі баз даных, напрыклад /var/lib/postgresql, бо копія, знятая з працуючага сервера, не з’яўляецца прыдатным бэкапам. У файлах выключэнняў restic шаблон, які пачынаецца з /, супадае з абсалютным шляхам, а простае імя накшталт node_modules супадае на любой глыбіні:
/var/lib/postgresql
/var/lib/docker
/var/cache
/var/tmp
/swapfile
/home/*/.cache
node_modules
.venv
__pycache__
*.tmp
--exclude-caches дадаткова прапускае каталогі са стандартным файлам CACHEDIR.TAG, а --one-file-system не дае restic пераходзіць у іншыя змантаваныя файлавыя сістэмы.
Асновы restic: рэпазітарый, шыфраванне і пароль
restic захоўвае дэдубліраваныя здымкі ў рэпазітарыі на лакальным дыску, праз SFTP, на ўласным REST-серверы або ў аб’ектным сховішчы і выгружае толькі новыя фрагменты. Шыфраванне нельга адключыць: паводле дакументацыі дызайну restic усе даныя шыфруюцца AES-256 у рэжыме лічыльніка і аўтэнтыфікуюцца Poly1305-AES, а ключ абаронены паролем, узмоцненым праз scrypt.
Трымайце налады ў файле асяроддзя, даступным толькі root, каб інтэрактыўныя каманды і заданні па раскладзе выкарыстоўвалі аднолькавыя значэнні. У дакументацыі па рэпазітарыях пералічаны фарматы URL, напрыклад s3:https://server:port/bucket для S3-сумяшчальных сэрвісаў.
# /etc/restic/restic.env, mode 600
RESTIC_REPOSITORY=s3:https://s3.example.com/web1-backups
RESTIC_PASSWORD_FILE=/etc/restic/password
RESTIC_CACHE_DIR=/var/cache/restic
AWS_ACCESS_KEY_ID=replace-me
AWS_SECRET_ACCESS_KEY=replace-me
HEARTBEAT_URL=https://monitor.example.net/ping/web1-backup
ALERT_WEBHOOK_URL=https://chat.example.net/hooks/backups
install -d -m 700 /etc/restic
(umask 077; openssl rand -base64 32 > /etc/restic/password)
set -a; . /etc/restic/restic.env; set +a
restic init
restic key add # другі пароль для афлайн-копіі на выпадак аднаўлення
restic backup --one-file-system --exclude-caches \
--exclude-file=/etc/restic/excludes.txt /etc /root /home /srv /var/www
restic snapshots
Дакументацыя кажа наўпрост: страта пароля азначае незваротную страту даных. Захоўвайце пароль, URL рэпазітарыя і ўліковыя даныя бакета ў менеджары пароляў і ў запячатанай афлайн-копіі, але ніколі толькі на серверы, які абараняеце. Калі вы карыстаецеся менеджарам сакрэтаў, RESTIC_PASSWORD_COMMAND можа выводзіць пароль замест чытання файла.
Захоўванне праз forget і prune, цэласнасць праз check
restic forget ужывае палітыку захоўвання да кожнай групы здымкаў (па змаўчанні групоўка ідзе па хосце і шляхах), а prune выдаляе даныя, на якія больш не спасылаецца ніводзін здымак. Сцяг --prune выконвае абодва крокі:
restic forget --prune --keep-daily 14 --keep-weekly 8 --keep-monthly 12 --keep-yearly 3
restic check --read-data-subset=10%
Такая палітыка захоўвае найноўшы здымак за кожны з апошніх 14 дзён, у якія ён быў, потым па адным на тыдзень за 8 тыдняў, на месяц за 12 месяцаў і на год за 3 гады. Змены палітыкі правярайце, дадаўшы --dry-run. У дакументацыі па forget сказана, што падчас prune рэпазітарый заблакаваны, таму разнясіце яго і бэкапы ў часе і дайце камандзе бэкапу --retry-lock.
restic check правярае структуру і метаданыя. --read-data спампоўвае кожны pack, што каштуе часу і выходнага трафіку, а --read-data-subset чытае частку: 10% выбірае выпадковае падмноства пры кожным запуску, а 3/12 чытае фіксаваную дванаццатую частку, як апісана ў дапаможніку па абслугоўванні рэпазітарыя. Паспяховая праверка даказвае ўзгодненасць, але не тое, што вы зможаце аднавіць сэрвіс.
Знешні рэпазітарый, які не сатрэ шыфравальнік
Зламыснік з root можа прачытаць /etc/restic/restic.env. Калі гэтыя ўліковыя даныя дазваляюць выдаляць аб’екты, знешнюю копію таксама можна выдаліць. Абмяжуйце ўліковыя даныя адным бакетам, трымайце адміністрацыйныя ключы па-за серверам і ўжывайце прынцып мінімальных прывілеяў з дапаможніка па абароне Linux VPS. Потым выберыце адзін з двух спосабаў абароны.
REST-сервер у рэжыме append-only
rest-server ад restic мае рэжым --append-only, які прымае новыя бэкапы, але забараняе выдаляць або змяняць наяўныя. Дакументацыя restic раіць запускаць forget і prune для такіх рэпазітарыяў з асобнай, добра абароненай машыны і выкарыстоўваць --keep-within замест правілаў накшталт --keep-weekly, бо ўзламаны кліент можа дадаць фальшывыя здымкі з падабранымі меткамі часу, якія зоймуць месцы сапраўдных.
Object lock у S3-сумяшчальным сховішчы
S3 Object Lock захоўвае версіі аб’ектаў па мадэлі write-once-read-many. Ён патрабуе версіянавання, а ў рэжыме compliance ніхто, у тым ліку root-карыстальнік акаўнта, не можа выдаліць заблакаваную версію да даты заканчэння захоўвання. Пачынаючы з версіі 0.13 restic адпраўляе кантрольныя сумы пры загрузцы, якіх патрабуюць такія бакеты, таму ён працуе з палітыкай захоўвання бакета па змаўчанні (для іншых правайдараў дадайце --endpoint-url):
aws s3api create-bucket --bucket web1-backups --object-lock-enabled-for-bucket
aws s3api put-object-lock-configuration --bucket web1-backups \
--object-lock-configuration '{"ObjectLockEnabled":"Enabled","Rule":{"DefaultRetention":{"Mode":"COMPLIANCE","Days":30}}}'
Калі restic выдаляе файл у такім бакеце, S3 дадае маркер выдалення, а заблакаваная версія застаецца. Пасля атакі скапіруйце бакет у тым стане, у якім ён быў, напрыклад камандай rclone copy --s3-version-at "2026-09-20" offsite:web1-backups /srv/recovered-repo, і аднаўляйцеся з гэтай копіі. Даныя пасля prune працягваюць займаць месца да канца тэрміну захоўвання, таму выдаляйце неактуальныя версіі правілам жыццёвага цыкла не раней за гэты тэрмін. Праверце ўвесь цыкл у свайго правайдара, бо рэалізацыі S3-сумяшчальных сэрвісаў адрозніваюцца.
Узгодненыя бэкапы PostgreSQL
Дакументацыя PostgreSQL пра бэкапы на ўзроўні файлавай сістэмы кажа наўпрост: для прыдатнай копіі каталога даных сервер павінен быць спынены, і забароны падключэнняў недастаткова, бо ўтыліты накшталт tar не робяць атамарнага здымка, а сервер буферызуе даныя ў памяці. Атамарны здымак тома з усімі файламі даных і WAL працуе, паколькі PostgreSQL прайгравае WAL, як пасля збою.
Для большасці сервераў лагічныя дампы застаюцца самым простым карэктным варыянтам. pg_dump робіць узгодненую выгрузку, пакуль база выкарыстоўваецца, і не блакуе іншых карыстальнікаў. Фармат directory дазваляе паралельна ствараць дампы і аднаўляць іх. Ролі ў дамп не ўваходзяць, таму глабальныя аб’екты выгружаюцца асобна. Гэты скрыпт запускаецца перад кожным бэкапам і захоўвае апошнія дампы на лакальным дыску:
#!/usr/bin/env bash
# /usr/local/sbin/pg-dump-for-backup
set -euo pipefail
out=/var/backups/postgresql
install -d -m 700 -o postgres -g postgres "$out"
runuser -u postgres -- pg_dumpall --globals-only --file="$out/globals.sql"
runuser -u postgres -- psql -Atc \
"SELECT datname FROM pg_database WHERE datallowconn AND NOT datistemplate" |
while read -r db; do
rm -rf "$out/$db.new"
runuser -u postgres -- pg_dump --format=directory --jobs=2 --file="$out/$db.new" "$db"
rm -rf "$out/$db"
mv "$out/$db.new" "$out/$db"
done
Выкарыстоўвайце pg_basebackup, калі лагічнае аднаўленне вялікага кластара не ўкладваецца ў RTO або патрэбна point-in-time recovery. Ён капіруе ўвесь кластар у пусты каталог па пратаколе рэплікацыі, патрабуе ролі з атрыбутам REPLICATION і запісу ў pg_hba.conf, а таксама перадае WAL, патрэбны для запуску копіі. pg_verifybackup правярае вынік па маніфесце:
sudo -u postgres pg_basebackup --pgdata=/var/backups/pg-base --wal-method=stream --checkpoint=fast
sudo -u postgres pg_verifybackup /var/backups/pg-base
pg_restore перабудоўвае індэксы паводле іх азначэнняў. Калі ў базе ёсць вялікія вектарныя індэксы, напрыклад HNSW з дапаможніка па гібрыдным пошуку на pgvector, гэтая перабудова можа заняць большую частку часу аднаўлення.
Расклад праз сэрвіс і таймер systemd
Сэрвіс тыпу oneshot запускае спачатку дамп, потым бэкап. Калі дамп не ўдаўся, бэкап не стартуе, і юніт пераходзіць у стан failed. Захавайце юніты ў /etc/systemd/system/:
# restic-backup.service
[Unit]
Description=restic backup to the off-site repository
Wants=network-online.target
After=network-online.target postgresql.service
OnFailure=backup-alert@%n.service
[Service]
Type=oneshot
EnvironmentFile=/etc/restic/restic.env
CacheDirectory=restic
Nice=10
IOSchedulingClass=idle
ExecStartPre=/usr/local/sbin/pg-dump-for-backup
ExecStart=/usr/local/bin/restic backup --retry-lock 30m \
--one-file-system --exclude-caches \
--exclude-file=/etc/restic/excludes.txt --tag scheduled \
/etc /root /home /srv /var/www /var/backups/postgresql
ExecStartPost=-/usr/bin/curl -fsS --max-time 10 --retry 3 ${HEARTBEAT_URL}
# restic-backup.timer
[Unit]
Description=Nightly restic backup
[Timer]
OnCalendar=*-*-* 02:15:00
RandomizedDelaySec=30m
Persistent=true
[Install]
WantedBy=timers.target
Уключыце таймер камандай systemctl enable --now restic-backup.timer і праверце яго праз systemctl list-timers. Паводле systemd.timer, Persistent=true даганяе запуск, прапушчаны, пакуль машына была выключаная, а RandomizedDelaySec= разносіць у часе хосты, якія пішуць у адзін бакет. У сэрвісаў oneshot па змаўчанні няма таймаўту запуску. На Linux-ноўтбуку тая ж пара працуе як карыстальніцкія юніты для хатняга каталога.
Штотыднёвы restic-maintenance.service з тым жа загалоўкам выконвае ачыстку і праверкі:
ExecStart=/usr/local/bin/restic forget --prune --retry-lock 2h \
--keep-daily 14 --keep-weekly 8 --keep-monthly 12 --keep-yearly 3
ExecStart=/usr/local/bin/restic check --read-data-subset=10%%
Пішыце %% для літаральнага знака працэнта, бо ў юнітах % пачынае спецыфікатар.
Маніторынг і абвесткі пра збоі
Выкарыстоўвайце два незалежныя сігналы, інакш ціхі збой выявіцца падчас інцыдэнту. Першы сігнал дае OnFailure=. Коды выхаду restic канкрэтныя: 1 азначае памылку каманды, 3 азначае, што частку зыходных файлаў не ўдалося прачытаць, 10 паведамляе пра адсутнасць рэпазітарыя, 11 пра няўдалае блакаванне, а 12 пра няправільны пароль. systemd лічыць збоем любы ненулявы код, і для 3 гэта правільна: здымак ёсць, але ў ім прабелы.
# [email protected]
[Unit]
Description=Alert for failed %i
[Service]
Type=oneshot
EnvironmentFile=/etc/restic/restic.env
ExecStart=/usr/bin/curl -fsS --max-time 10 --retry 3 \
--data-urlencode "text=%H: %i failed, see journalctl -u %i" \
${ALERT_WEBHOOK_URL}
Адзін шаблон абслугоўвае ўсе заданні, а systemd перадае яму зменныя накшталт MONITOR_EXIT_STATUS. Праверце ланцужок камандай systemctl start [email protected].
Другі сігнал працуе як dead man's switch: ExecStartPost= адпраўляе запыт на heartbeat URL толькі пасля поспеху, а сістэма маніторынгу падымае трывогу, калі запыт не прыйшоў, скажам, за 26 гадзін. Так выяўляюцца адключаны таймер або выключаны хост. Для погляду звонку штодня запускайце restic snapshots --latest 1 --json --no-lock з іншай машыны і паведамляйце, калі найноўшы здымак старэйшы за RPO.
Правядзіце вучэнні з аднаўлення з замерам часу
Вучэнні ператвараюць здагадкі ў лічбы. Праводзьце іх пасля першаснай наладкі, пасля буйных змен і не радзей за раз на квартал на чыстай віртуальнай машыне, а не на працоўным хосце, выкарыстоўваючы толькі тое, што будзе ў інжынера падчас рэальнага інцыдэнту: запіс у менеджары пароляў і runbook.
- Запусціце секундамер у момант пачатку ўмоўнага інцыдэнту.
- Атрымайце ўліковыя даныя, усталюйце restic і выведзіце спіс здымкаў. Узрост найноўшага здымка і ёсць ваш фактычны RPO.
- Аднавіце файлы і дампы, потым базу даных, замяраючы кожны крок.
- Запусціце staging-копію праграмы і прайдзіце адзін рэальны сцэнар.
- Запішыце працягласць этапаў і праблемы, потым абнавіце runbook.
set -a; . ./restic.env; set +a
restic snapshots --latest 3
time restic restore latest --target /restore --verify
sudo -u postgres psql -f /restore/var/backups/postgresql/globals.sql
sudo -u postgres createdb app
time sudo -u postgres pg_restore --jobs=4 --dbname=app /restore/var/backups/postgresql/app
sudo -u postgres psql -d app -c "SELECT max(created_at) FROM orders;"
--verify паўторна чытае адноўленыя файлы і параўноўвае іх са здымкам. Апошні запыт паказвае, колькі даных аднаўленне фактычна страціла. Памылкі пра тое, што ролі ўжо існуюць, чаканыя. Адпрацуйце таксама аднаўленне аднаго файла з --include /etc/nginx/nginx.conf, самы частый рэальны запыт.
Параўнайце агульны час з RTO. Тыповыя нечаканасці: адсутныя ўліковыя даныя, пароль, які жыў толькі на загінулым серверы, павольная перабудова індэксаў і забытыя файлы, напрыклад TLS-ключы або .env па-за шляхамі, якія захоўваюцца.
restic, BorgBackup ці здымкі файлавай сістэмы
Многія схемы спалучаюць гэтыя падыходы: здымак ZFS, Btrfs або LVM для хуткага лакальнага адкату плюс файлавыя бэкапы па-за пляцоўкай. BorgBackup 1.4 з’яўляецца бягучай стабільнай галіной.
| Уласцівасць | restic | BorgBackup 1.4 | Здымкі файлавай сістэмы |
|---|---|---|---|
| Дзе захоўваць | Лакальна, SFTP, REST-сервер, S3-сумяшчальныя і іншыя воблачныя сховішчы | Лакальна або праз SSH, лепш з Borg на серверы | Той жа пул; для знешняй копіі патрэбна рэплікацыя, напрыклад zfs send |
| Шыфраванне | Заўсёды ўключана | Выбіраецца пры стварэнні рэпазітарыя, неабавязковае | Залежыць ад сховішча |
| Узламаны кліент | rest-server --append-only, object lock бакета |
borg serve --append-only |
Абароненыя толькі пры рэплікацыі ў асобна адміністраваную сістэму |
| Узгодненасць БД | Патрэбныя дампы | Патрэбныя дампы | Crash-consistent, калі даныя і WAL у адным атамарным здымку |
| Аднаўленне | Ад аднаго файла да ўсяго дрэва, мантаванне праз FUSE | Ад аднаго файла да ўсяго дрэва, мантаванне праз FUSE | Адкат усяго тома або капіраванне са змантаванага здымка |
| Кліенты | Linux, macOS, Windows, BSD | Linux, macOS, BSD; Windows толькі праз эксперыментальныя WSL або Cygwin | Залежыць ад файлавай сістэмы |
Здымак у тым жа пуле абараняе ад няўдалага дэплою, але не ад адмовы пула ці ўзлому хоста, таму сам па сабе ён не з’яўляецца копіяй у сэнсе 3-2-1.
Чэк-ліст
- RPO і RTO запісаныя і ўзгодненыя з уладальнікам сэрвісу.
- Ёсць тры копіі, адна па-за пляцоўкай і адна нязменная або append-only.
- Пароль, URL рэпазітарыя і ўліковыя даныя ляжаць у менеджары пароляў і афлайн.
- Жывыя каталогі баз выключаныя, а дампы ўключаныя.
- PostgreSQL пакрыты
pg_dumpз глабальнымі аб’ектамі або праверанымpg_basebackup. - Таймер выкарыстоўвае
Persistent=true, а апрацоўшчыкOnFailure=хоць раз спрацаваў на тэсце. - Heartbeat падымае трывогу пры адсутнасці паспяховага запуску, а знешняя праверка пры састарэлых здымках.
forget --pruneіcheck --read-data-subsetвыконваюцца штотыдзень.- Уліковыя даныя сервера не могуць выдаліць заблакаваныя версіі.
- Вучэнні з аднаўлення з замерам часу прайшлі ў гэтым квартале, і runbook адлюстроўвае іх высновы.