Asosiy kontentga o‘tish

Maqolalar 9 daqiqa 136 ko‘rish

systemd timer va avtomatik backup: tiklanmagan zaxira — zaxira emas

Cron o'rniga systemd timer: loglari jurnal ichida, o'tkazib yuborilgan ishga tushishlarni quvib yetadi va sinash oson. Shu tool bilan bazani har kuni avtomatik zaxiralaymiz, eski nusxalarni tozalaymiz va eng muhimi — tiklashni ham sinaymiz.

database linux devops

Mundarija

Serverda muntazam bajariladigan ishlar bo'ladi: bazani zaxiralash, eski loglarni tozalash, hisobot yig'ish. An'anaviy javob — cron. Lekin systemd bilan ishlayotgan serverda (seriyaning 2-qismidan beri hamma xizmatimiz shunda) timer'lar ancha qulay: ishga tushish loglari journalctlda xizmatniki bilan yonma-yon turadi, vazifani qo'lda bir buyruq bilan sinash mumkin, server o'chiq paytga to'g'ri kelgan ishga tushishni esa keyin quvib yetish imkoni bor. Cron'da bularning har biri alohida bosh og'rig'i edi.

Timer'ni eng kerakli ishda ko'rsataman — kunlik baza zaxirasi. Yo'l-yo'lakay zaxiraning eng katta sirini ham aytaman: hech qachon tiklab ko'rilmagan backup — backup emas, umid xolos.

Juftlik: service + timer#

systemd'da rejali vazifa ikki fayldan iborat: ishning o'zi (.service) va jadval (.timer). Ular bir xil nomlanadi:

INI
# /etc/systemd/system/db-backup.service
[Unit]
Description=Kunlik baza zaxirasi

[Service]
# oneshot: ishga tushdi, bajarib bo'ldi, chiqdi — doimiy xizmat emas
Type=oneshot
User=deploy
ExecStart=/opt/mysite/scripts/backup.sh
INI
# /etc/systemd/system/db-backup.timer
[Unit]
Description=Har kuni 03:30 da zaxira

[Timer]
OnCalendar=*-*-* 03:30:00
# server o'sha payt o'chiq bo'lsa, yoqilgach darhol bajaradi —
# "kecha backup bo'lmabdi" degan bo'shliq qolmaydi
Persistent=true

[Install]
WantedBy=timers.target

E'tibor bering, yoqilganda service emas, timer enable qilinadi:

Terminal
sudo systemctl daemon-reload
sudo systemctl enable --now db-backup.timer

systemctl list-timers db-backup.timer   # NEXT ustunida navbatdagi 03:30 ko'rinadi

Sinash uchun kutish shart emas

Timer'ning eng yoqimli tomoni shu: vazifani hoziroq qo'lda ishga tushirib ko'rasiz — sudo systemctl start db-backup.service — va natijani sudo journalctl -u db-backup bilan o'qiysiz. Cron'da "yarim tunni kutamiz yoki jadvalni vaqtincha o'zgartiramiz" o'yini bor edi, bu yerda yo'q.

Zaxira skriptining o'zi#

Skript deploy nomidan ishlaydi, /var/backups esa root'ga tegishli — deploy u yerda papka yarata olmaydi va birinchi sinovning o'zi Permission denied bilan yiqiladi. Shuning uchun papkani oldindan tayyorlab, deployga beramiz:

Terminal
sudo mkdir -p /var/backups/mysite
sudo chown deploy:deploy /var/backups/mysite
# zaxirada parol xeshlari ham bor — serverdagi boshqa foydalanuvchilar o'qimasin
sudo chmod 700 /var/backups/mysite

mkdir -p /opt/mysite/scripts
nano /opt/mysite/scripts/backup.sh

Endi backup.shni yozamiz. Ikki keng tarqalgan holatni ko'rsataman — qaysi baza bo'lsa, o'shanisini oling (seriyadagi saytimiz PostgreSQL'da):

Terminal
#!/usr/bin/env bash
# /opt/mysite/scripts/backup.sh
set -euo pipefail   # xato bo'lsa jim davom etmasin — xizmat failed holatga tushsin
umask 077           # yaratilgan fayllarni faqat egasi o'qiy olsin

BACKUP_DIR=/var/backups/mysite
STAMP=$(date +%Y-%m-%d_%H%M)
mkdir -p "$BACKUP_DIR"

# --- SQLite bo'lsa ---
# oddiy cp EMAS: yozuv paytida ko'chirilgan fayl buzuq chiqishi mumkin.
# .backup buyrug'i esa bazani izchil holatda nusxalaydi
sqlite3 /opt/mysite/db.sqlite3 ".backup '$BACKUP_DIR/db_$STAMP.sqlite3'"
# -f: shu daqiqada qayta ishga tushirsangiz, eski .gz ustiga yozadi
gzip -f "$BACKUP_DIR/db_$STAMP.sqlite3"

# --- PostgreSQL bo'lsa (yuqoridagi ikki qator o'rniga) ---
# pg_dump -Fc mysite > "$BACKUP_DIR/db_$STAMP.dump"

# 14 kundan eski nusxalarni tozalaymiz — disk cheksiz emas
find "$BACKUP_DIR" -name "db_*" -mtime +14 -delete

echo "backup tayyor: db_$STAMP"

Skript ishlashidan oldin bazaga qarab bitta tayyorgarlik kerak.

SQLite: sqlite3 buyrug'i Ubuntu'da standart o'rnatilmagan — sudo apt install -y sqlite3.

PostgreSQL: pg_dump bazaga Linux foydalanuvchisi nomi bilan ulanadi, PostgreSQL'da esa deploy degan rol yo'q. Tayyorgarliksiz skript FATAL: role "deploy" does not exist bilan yiqiladi va ortidan bo'sh .dump fayl qoldiradi. Rolni yaratib, unga faqat o'qish huquqini beramiz:

Terminal
sudo -u postgres createuser deploy
# PostgreSQL 14+: barcha jadvallarni o'qiy oladi, lekin hech narsani o'zgartira olmaydi
sudo -u postgres psql -c "GRANT pg_read_all_data TO deploy;"

Zaxira skriptiga bundan ortiq huquq kerak emas: skript buzilsa yoki kimdir unga qo'l ursa ham, bazadagi ma'lumotni o'chira olmaydi.

Endi sinaymiz:

Terminal
chmod +x /opt/mysite/scripts/backup.sh
sudo systemctl start db-backup.service    # birinchi sinov
ls -lh /var/backups/mysite/               # fayl paydo bo'ldi

set -euo pipefail qatori mayda ko'ringani bilan muhim: usiz skript o'rtada xato bersa ham "muvaffaqiyatli" tugagan hisoblanadi va siz oylab bo'sh zaxira yig'ib yurishingiz mumkin. U bilan esa xato xizmatni failed holatga tushiradi — systemctl --failed va systemctl status db-backup.service buni darhol ko'rsatadi. systemctl list-timers dan buni kutmang: u faqat oxirgi va navbatdagi ishga tushish vaqtini chiqaradi, timer'ning o'zi esa active bo'lib qolaveradi.

Zaxira serverning o'zida qolsa — bu ham yarim ish#

Server diski kuysa, undagi zaxiralar ham birga ketadi. Shuning uchun kamida bitta nusxa boshqa joyda turishi kerak. Eng arzon yo'l — skriptga (echo qatoridan oldin) bitta qator qo'shib, faylni boshqa serverga yoki bulutga jo'natish:

Terminal
# boshqa serverga:
rsync -a "$BACKUP_DIR/" zaxira@boshqa-server:zaxiralar/mysite/

# yoki S3-ga o'xshash saqlashga (rclone oldindan sozlangan bo'lsa):
# rclone copy "$BACKUP_DIR" remote:mysite-backups

rsync qatori o'z-o'zidan ishlamaydi. 1-qismda sozlagan kalitimiz sizning kompyuteringizdan serverga kirish uchun edi, bu yerda esa serverning o'zi boshqa serverga kiradi. Buning uchun deployga alohida kalit kerak. Boshqa serverda avval sudo adduser zaxira bilan foydalanuvchi oching. backup nomini ishlatmang: Ubuntu va Debian'da bu nomli tizim foydalanuvchisi allaqachon bor va u orqali SSH'ga kirib bo'lmaydi. Keyin asosiy serverda, deploy sifatida:

Terminal
# parolsiz kalit: timer ishga tushganda parolni kiritadigan odam yo'q
ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519
ssh-copy-id zaxira@boshqa-server

# parol so'ramasdan kirsa — kalit joyida; shu bilan papkani ham yaratamiz
ssh zaxira@boshqa-server "mkdir -p zaxiralar/mysite"

Boshqa serverda parol bilan kirish yopiq bo'lsa, ssh-copy-id ishlamaydi. U holda cat ~/.ssh/id_ed25519.pub natijasini o'sha serverdagi /home/zaxira/.ssh/authorized_keys fayliga qo'lda qo'shing.

Oxirgi buyruqni o'tkazib yubormang. Birinchidan, u timer yuradigan yo'lni qo'lda bir marta bosib o'tadi: boshqa serverga birinchi ulanishda SSH host kalitini "yes" bilan qabul qilasiz (ssh-copy-id paytida qabul qilgan bo'lsangiz, qayta so'ramaydi). Timer ichida "yes" deydigan odam yo'q — kalit saqlanmagan bo'lsa, xizmat Host key verification failed bilan yiqiladi. Ikkinchidan, papkani yaratadi: rsync manzildagi faqat oxirgi papkani o'zi yarata oladi, zaxiralar yo'q bo'lsa No such file or directory beradi. Yo'l / bilan boshlanmagani uchun papka zaxiraning uy papkasida (/home/zaxira/zaxiralar/mysite) paydo bo'ladi — u yerga yozish uchun sudo kerak emas.

Eng muhim qadam: tiklashni sinash#

Endi va'da qilingan gap. Zaxira tizimini sozlagan odamlarning ko'pi bitta savolga javob berolmaydi: "shu fayldan bazani tiklab ko'rganmisiz?" Fayl har kuni yaratilayotgani hali hech narsani anglatmaydi — u buzuq bo'lishi, yarim bo'lishi, kerakli jadvallarsiz bo'lishi mumkin. Buni bilishning yagona yo'li — tiklab ko'rish. Avval eng yangi zaxira nomini bilib olamiz (u ro'yxat tepasida turadi) va quyidagi buyruqlarda misoldagi nom o'rniga o'shani qo'yamiz:

Terminal
ls -t /var/backups/mysite/

SQLite bo'lsa:

Terminal
# alohida papkada, jonli bazaga TEGMASDAN:
cd /tmp
gunzip -c /var/backups/mysite/db_2026-08-16_0330.sqlite3.gz > sinov.sqlite3

# ichi joyidami? jadvallar va yozuvlar sonini tekshiramiz:
sqlite3 sinov.sqlite3 ".tables"
sqlite3 sinov.sqlite3 "SELECT count(*) FROM auth_user;"
rm sinov.sqlite3

PostgreSQL bo'lsa, zaxirani vaqtinchalik alohida bazaga tiklaymiz:

Terminal
sudo -u postgres createdb mysite_sinov
sudo -u postgres pg_restore -d mysite_sinov < /var/backups/mysite/db_2026-08-16_0330.dump

# ichi joyidami? jadvallar va yozuvlar sonini tekshiramiz:
sudo -u postgres psql -d mysite_sinov -c "\dt"
sudo -u postgres psql -d mysite_sinov -c "SELECT count(*) FROM auth_user;"
sudo -u postgres dropdb mysite_sinov

Faylni pg_restore ga yo'l bilan emas, < orqali berayotganimizga e'tibor bering. Zaxira papkasini faqat deploy o'qiy oladi, postgres foydalanuvchisi esa uni ocholmaydi va Permission denied beradi. < bilan faylni sizning shell'ingiz ochadi va tarkibini pg_restore ga uzatadi.

Tiklash mashqini kalendarga yozing

Bu bir martalik ish emas. Choraklik odat qiling: zaxiradan bazani sinov muhitiga tiklash, ilovani unga ulab bir aylanib chiqish. O'n besh daqiqa oladi, lekin "backup bor edi-ku!" degan eng achchiq jumladan saqlaydi — u odatda ma'lumot yo'qolgandan keyin, tiklash urinishi muvaffaqiyatsiz chiqqanda aytiladi.

Yakun#

Endi serverda o'zini o'zi qutqaradigan mexanizm bor: timer har kuni 03:30 da uyg'onadi, skript bazani izchil nusxalab siqadi, eskilarini tozalaydi va nusxani serverdan tashqariga jo'natadi. Xato bo'lsa failed holat ko'rinadi, o'chiq qolgan kun esa Persistent=true tufayli o'tkazib yuborilmaydi. Va siz vaqti-vaqti bilan tiklab ko'rasiz — chunki sinalmagan zaxira shunchaki fayl.

Keyingi qismda shu qurilgan tizimning yaxlitligini tekshiramiz: reboot'ga chidamlilik — server o'chib yonganda hamma narsa o'z-o'zidan qaytadigan holatga kelganini qanday kafolatlaymiz.

9 daqiqa 136 marta o‘qildi