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.
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:
# /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
# /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:
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:
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):
#!/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:
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:
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:
# 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:
# 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:
ls -t /var/backups/mysite/
SQLite bo'lsa:
# 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:
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.