26 β Logging, alerting, backup va ishonchlilik¶
β¬ οΈ Oldingi: 25 β Monitoring: Prometheus va Grafana Β· π README Β· Keyingi: 27 β Infrastructure as Code: Ansible va Terraform β‘οΈ
Bu bobda: 25-bobda metrikani ko'rdik β endi metrika "nimadir buzilganini" ko'rsatadi, lekin nega buzilganini loglar aytadi, buzilganda sizni xabardor qilish esa alerting ishi. Avval markazlashtirilgan log nima uchun kerakligini (ko'p server/konteyner -> bitta joydan qidirish) ko'ramiz:
docker logs,journald(19-bobni eslaymiz), log drayverlar,logrotatebilan log fayllar disk to'ldirib yubormasligi, strukturali (JSON) log, va Prometheus oilasidagi Loki + Alloy/Promtail stek (ELK/EFK bilan qisqa taqqos). So'ng alerting: Prometheus alert qoidalari (alert/expr/for/labels/annotations), Alertmanager (routing, grouping, Telegram/email receiver'lar,amtool), healthcheck/uptime monitoring (blackbox exporter, UptimeRobot). Keyin ishonchlilik (SRE) asoslari β SLI, SLO, SLA, error budget sodda tilda. Oxirida backup va recovery: nega kerak,pg_dump/mysqldump, volumetarbackup, 3-2-1 qoidasi, retention, off-site, va eng muhimi β restore'ni sinash (sinalmagan backup = backup emas); to'liq avtomatik backup + restore skriptini cron bilan yozamiz.
Muammo: metrika "yong'in" deydi, lekin sababini ko'rsatmaydi¶
25-bobda Grafana dashboard qurdik. Bir kuni grafik qizarib ketdi: 5xx xatolar 0% dan 30% ga sakradi. Ajoyib β bilasiz. Lekin endi nima qilasiz?
- Sababni qayerdan ko'rasiz? Metrika "30% so'rov yiqilyapti" deydi, lekin qaysi endpoint, qanday xato β buni faqat log aytadi. SSH qilib
docker logsko'rasizmi? 5 ta konteynerda? 3 ta serverda? Qaysi birida? - Xabarni qanday olasiz? Grafik tunda qizarsa, siz uxlab yotgan bo'lsangiz β ertalab bilasiz. Sizga alert kerak: muammo boshlanganda Telegram'ga xabar kelsin.
- Eng yomoni β ma'lumot yo'qolsa? Disk o'ladi, kimdir
DROP TABLEqiladi, ransomware shifrlaydi. Metrika ham, log ham bu yerda yordam bermaydi β sizga backup kerak. Va backup bo'lsa-yu, qaytara olmasangiz β backup ham yo'q.
Bu bob shu uchta og'riqni yopadi: loglarni bir joyga yig'ish, muammoda xabar olish, falokatdan tiklanish. Hammasi 25-bobdagi namuna vazifalar API stegi ustiga quriladi.
1-qism: Logging β loglarni bir joyga yig'ish¶
Nega markazlashtirilgan log¶
Bitta serverda bitta ilova ishlatganda log oddiy: node app.js chiqishini ko'rasiz. Lekin production o'sgani sari:
- Ilova bir nechta konteynerda (nginx + app + postgres + redis).
- Konteynerlar bir nechta serverda (yoki Kubernetes Pod'larida β qulasa o'chib, yangisi tug'iladi va eski log yo'qoladi).
- Muammo qaysi birida ekanini oldindan bilmaysiz.
Har biriga alohida SSH qilib docker logs qidirish β kechki tushga aylanadi. Yechim β barcha loglarni bitta markazga oqizish va u yerdan qidirish:
π Markazlashtirilgan log = "barcha server/konteyner loglarini bitta joyga yig'ib, bitta interfeysdan qidirish". Foydasi: SSH qilmaysiz, konteyner o'lsa ham logi qoladi, bir nechta xizmat logini birga ko'rib muammoni ulay olasiz (korrelyatsiya).
Boshlang'ich: docker logs va journald¶
Markazga o'tishdan oldin, mavjud loglarni eslaylik. Docker har konteynerning stdout/stderr ini ushlaydi:
docker logs vazifalar # konteyner loglari
docker logs -f vazifalar # jonli kuzatish (follow)
docker logs --since 1h vazifalar # oxirgi 1 soat
docker logs --tail 100 vazifalar # oxirgi 100 qator
19-bobda systemd xizmati loglarini journalctl -u vazifalar -f bilan ko'rgandik β bu journald, systemd'ning markaziy log jamlovchisi. Konteynersiz (systemd) deploy'da loglar shu yerda; Docker'da esa Docker'ning log drayveri boshqaradi.
Docker'ning standart log drayveri β json-file (har konteyner logini diskka JSON fayl qilib yozadi). Asosiy drayverlar:
| Drayver | Nima qiladi |
|---|---|
json-file |
Standart. Diskka JSON fayl (docker logs shu yerdan o'qiydi). |
local |
json-file ga o'xshash, lekin samaraliroq va avto-rotatsiyali. |
journald |
Loglarni systemd journal'ga yuboradi (journalctl bilan ko'riladi). |
β οΈ
json-filedrayveri standartda log fayllarni cheklamaydi β uzoq ishlagan konteyner diskni jimgina to'ldirib, serverni o'ldirishi mumkin. Cheklash kerak (pastda).
Log fayllar disk to'ldirib yubormasligi¶
Ikki joyda cheklash kerak.
1) Docker log drayveri darajasida β har konteyner logiga hajm/fayllar soni chegarasi. compose.yaml da:
services:
vazifalar:
image: ghcr.io/foydalanuvchi/vazifalar-api:latest
logging:
driver: json-file
options:
max-size: "10m" # bitta log fayl maksimum 10 MB
max-file: "3" # eng ko'pi 3 ta fayl (qolgani o'chadi)
Bu β Docker o'zi qiladigan rotatsiya: fayl 10 MB ga yetganda yangisini boshlaydi, 3 tadan oshganda eng eskisini o'chiradi. Disk hech qachon 30 MB dan oshmaydi (shu konteyner uchun).
2) Oddiy fayl loglar uchun β logrotate. Agar ilovangiz (yoki nginx) bevosita faylga yozsa (masalan /var/log/vazifalar/app.log), uni logrotate aylantiradi. logrotate β Linux'ning standart vositasi (odatda har kuni cron orqali ishlaydi). Config /etc/logrotate.d/<nom> ga qo'yiladi:
/var/log/vazifalar/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 deploy deploy
sharedscripts
postrotate
systemctl reload vazifalar.service > /dev/null 2>&1 || true
endscript
}
Har direktiva nima qiladi:
dailyβ har kuni aylantir (weekly/monthlyham bor).rotate 14β 14 ta eski nusxani saqla, keyin eng eskisini o'chir (~2 hafta).compressβ eski loglarni.gzqil (joy tejaydi).delaycompressβ eng oxirgi aylantirilganini siqishni bir qadam kechiktiradi (ilova hali yozayotgan bo'lsa muammo bo'lmasin).missingokβ log fayli yo'q bo'lsa xato berma.notifemptyβ bo'sh faylni aylantirma.create 0640 deploy deployβ aylantirgandan keyin yangi bo'sh faylni shu ruxsat va egasi bilan yarat.postrotate ... endscriptβ aylantirgandan keyin ilovaga "yangi faylga yoz" deb signal beradi (reload).sharedscriptsβ bir nechta fayl bo'lsa ham skriptni bir marta ishlatadi.
π‘ logrotate config'ni sinash:
sudo logrotate --debug /etc/logrotate.d/vazifalar(haqiqatan aylantirmasdan nima qilishini ko'rsatadi). Bu bob uchun bu config'ni Docker ichidagi haqiqiylogrotate --debugbilan tekshirdim βdaily,rotate 14,create 0640 deploy deploy,postrotateto'g'ri parse bo'ldi.
Strukturali (JSON) log¶
Oddiy matn log:
Strukturali (JSON) log:
Farqi: JSON logni mashina o'qiy oladi β user_id=42 bo'yicha filtr, level=error bo'yicha qidiruv juda oson bo'ladi. Matn logda buni grep + regex bilan azoblanib ajratish kerak. Loki/Elasticsearch kabi tizimlar JSON maydonlaridan avtomatik filtr quradi.
π Production'da strukturali log yozing (har til uchun kutubxona bor: Node β
pino/winston, Python βstructlog, Go βslog). Vaqt, daraja (level), xabar (msg) va kontekst (user_id,request_id) ni alohida maydon qiling. Keyin markaziy log tizimida ulardan filtr qilasiz.
Markaziy stek: Loki + Alloy (Prometheus oilasi)¶
25-bobda Prometheus + Grafana ni ko'rdik. Loki β o'sha oiladan: "loglar uchun Prometheus" deb ataladi. U log matnini indekslamaydi, faqat labellarni (job, container, level) indekslaydi β shuning uchun arzon va tez. Komponentlar:
- Loki β loglarni saqlovchi va so'rovga javob beruvchi server.
- Collector β loglarni manbalardan yig'ib, label qo'shib, Loki'ga push qiladi. Hozirgi tavsiya β Grafana Alloy (yangi, universal collector); eski nomi Promtail (hali ishlaydi, lekin Alloy afzal).
- Grafana β Loki'ni ma'lumot manbai sifatida ulab, LogQL bilan qidirasiz (PromQL'ning log varianti).
LogQL so'rovi PromQL'ga o'xshaydi β avval label bo'yicha tanlaysiz, keyin filtrlaysiz:
Birinchisi: vazifalar-api loglaridan ichida "error" so'zi borlarini. Ikkinchisi: level=error loglarni JSON sifatida ochib, user_id=42 bo'yicha filtr. Bitta server o'rniga butun infratuzilma bo'ylab.
Loki + Alloy + Grafana stegini Compose bilan ko'tarish (25-bobdagi monitoring stegiga qo'shiladi):
services:
loki:
image: grafana/loki:3.5.0
command: -config.file=/etc/loki/config.yaml
ports:
- "3100:3100"
volumes:
- ./loki-config.yaml:/etc/loki/config.yaml:ro
- loki-data:/loki
restart: unless-stopped
alloy:
image: grafana/alloy:latest
command:
- run
- /etc/alloy/config.alloy
- --storage.path=/var/lib/alloy/data
volumes:
- ./config.alloy:/etc/alloy/config.alloy:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
depends_on:
- loki
restart: unless-stopped
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-data:/var/lib/grafana
depends_on:
- loki
restart: unless-stopped
volumes:
loki-data:
grafana-data:
Alloy docker.sock va konteyner loglar papkasini o'qib, har konteyner logini avtomatik yig'adi va Loki'ga push qiladi. Grafana'da Loki'ni manba qilib ulaysiz va LogQL bilan qidirasiz.
βΉοΈ Loki'ni Grafana'da ko'rish, real konteyner loglarini yig'ish va LogQL natijalarini ko'rish β jonli ish: bu stekni o'z serveringizda
docker compose up -dbilan ko'tarib, Grafana > Explore > Loki'da sinab ko'ring. Men bu yerda compose faylnidocker compose configbilan tekshirdim (sintaksis to'g'ri), lekin jonli log oqimi UI'da sinaladi.
ELK/EFK bilan qisqa taqqos¶
Boshqa mashhur stek β ELK (Elasticsearch + Logstash + Kibana) yoki EFK (Logstash o'rniga Fluentd/Fluent Bit):
| Loki + Alloy + Grafana | ELK / EFK | |
|---|---|---|
| Indekslash | Faqat labellar (yengil, arzon) | To'liq matn (kuchli qidiruv, og'irroq) |
| Resurs | Kam (RAM/disk tejamkor) | Ko'p (Elasticsearch RAM ochko'z) |
| UI | Grafana (metrika bilan birga) | Kibana (boy, lekin alohida) |
| Qachon | Metrika allaqachon Grafana'da bo'lsa, oddiy/o'rta loyiha | To'liq matn bo'yicha murakkab qidiruv, katta hajm |
π‘ Agar metrikangiz allaqachon Grafana'da bo'lsa (25-bob), Loki mantiqan to'g'ri keladi β bitta UI'da metrika va log birga. ELK kuchliroq qidiruv beradi, lekin resurs va boshqaruvi og'irroq. Boshlash uchun Loki.
2-qism: Alerting β muammoda xabar olish¶
Loglar bor, metrika bor β lekin ekranga 24/7 qarab o'tirmaysiz. Muammo boshlanganda tizim o'zi xabar bersin. Bu β alerting.
Prometheus alert qoidalari¶
25-bobda Prometheus metrikani yig'di. Endi unga qoida beramiz: "agar shu PromQL ifoda rost bo'lsa β alert ot". Qoidalar alohida faylda (alert-rules.yml):
groups:
- name: vazifalar-api
rules:
- alert: InstanceDown
expr: up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "{{ $labels.instance }} ishlamayapti"
description: "Target 2 daqiqadan beri javob bermayapti."
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m])) > 0.05
for: 5m
labels:
severity: warning
annotations:
summary: "Yuqori xatolik darajasi (5xx > 5%)"
description: "Oxirgi 5 daqiqada 5xx javoblar ulushi 5% dan oshdi."
- alert: DiskAlmostFull
expr: |
(node_filesystem_avail_bytes{mountpoint="/"}
/ node_filesystem_size_bytes{mountpoint="/"}) < 0.10
for: 10m
labels:
severity: critical
annotations:
summary: "Disk to'lib bormoqda"
description: "/ bo'limida 10% dan kam bo'sh joy qoldi."
Har qoidaning 5 qismi:
alert:β alert nomi (InstanceDown).expr:β PromQL ifoda. Rost (natija qaytsa) bo'lsa β alert "faollashadi".up == 0= target javob bermayapti.for:β ifoda shu muddat davomida rost bo'lib turishi shart, shundan keyinfiringbo'ladi. Bu β vaqtinchalik sakrashlardan (flap) kelib chiqadigan soxta alertlarni filtrlaydi.up == 02 daqiqa davom etsa β haqiqiy muammo.labels:β alertga yorliq qo'shadi (severity: critical). Alertmanager shular bo'yicha routing qiladi.annotations:β odam o'qiy oladigan matn (summary,description).{{ $labels.instance }}β alert qaysi target'dan kelganini ko'rsatadi.
Prometheus'ga bu fayl haqida aytamiz (prometheus.yml):
rule_files:
- "alert-rules.yml"
alerting:
alertmanagers:
- static_configs:
- targets:
- "alertmanager:9093"
π
for:β alertning eng muhim kaliti.for: 0(yoki yo'q) = ifoda bir sekund rost bo'lsayoq alert. Bu spam keltiradi.for: 5m= "5 daqiqa muammo bo'lib tursa". Haqiqiy muammoni o'tkinchidan ajratadi.
Alertmanager: routing, grouping, receiver'lar¶
Prometheus alertni otadi, lekin uni kimga, qanday yetkazishni bilmaydi. Bu β Alertmanager ishi. U uchta katta muammoni hal qiladi:
- Grouping (guruhlash) β 10 ta server bir vaqtda yiqilsa, 10 ta alohida xabar emas, bitta guruhlangan xabar.
- Routing β alertni labellari bo'yicha to'g'ri kanalga yo'naltiradi (
critical-> Telegram,warning-> email). - Inhibition / repeat β takror xabarlarni cheklaydi (
repeat_interval), bir alert boshqasini bostiradi (kritik bor ekan, ogohlantirishni yubormaydi).
alertmanager.yml:
global:
resolve_timeout: 5m
route:
receiver: telegram-default
group_by: ["alertname", "job"]
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- matchers:
- severity = critical
receiver: telegram-critical
repeat_interval: 1h
receivers:
- name: telegram-default
telegram_configs:
- bot_token: "123456:REPLACE_WITH_TOKEN"
chat_id: -1001234567890
send_resolved: true
- name: telegram-critical
telegram_configs:
- bot_token: "123456:REPLACE_WITH_TOKEN"
chat_id: -1001234567890
send_resolved: true
message: "CRITICAL: {{ .CommonAnnotations.summary }}"
inhibit_rules:
- source_matchers:
- severity = critical
target_matchers:
- severity = warning
equal: ["alertname", "instance"]
Asosiy kalitlar:
routeβ alertlar daraxti. Yuqorida β standart yo'nalish;routes:ichida maxsus shartlar.group_byβ qaysi labellar bir xil bo'lsa, bir guruhga qo'shsin (alertname+job).group_waitβ birinchi xabardan oldin biroz kutadi (30s), shu vaqtda kelgan o'xshash alertlarni birga yuboradi.repeat_intervalβ hal bo'lmagan alert qancha vaqtda bir takror eslatiladi (standart 4h, kritiklar 1h).matchersβ qaysi alertlar shu yo'nalishga tushadi (severity = critical).receiversβ qayerga yuborish. Bu yerda Telegram; email/Slack uchunemail_configs/slack_configsbor.
Telegram bot tokenini @BotFather dan, chat_id ni bot orqali olasiz (guruh uchun -100... bilan boshlanadi).
β οΈ
bot_tokenβ maxfiy. Uni git'ga qo'ymang. Production'da Docker secret yoki muhit o'zgaruvchisi orqali bering. YuqoridagiREPLACE_WITH_TOKENβ namuna o'rni.
amtool bilan tekshirish¶
Alertmanager bilan keladigan amtool config'ni va alertlarni tekshiradi:
# Config to'g'riligini tekshirish (deploy'dan oldin SHART)
amtool check-config alertmanager.yml
# Alert qaysi receiver'ga ketishini test qilish (haqiqatan yubormay)
amtool config routes test --config.file=alertmanager.yml severity=critical
π‘ Bu bobdagi
alertmanager.ymlni haqiqiyamtool check-configbilan tekshirdim: SUCCESS β global config, route, 1 inhibit rule, 2 receiver topildi.alert-rules.ymlni esapromtool check rulesbilan: SUCCESS, 3 rule. Deploy'dan oldin doim shu ikki buyruqni ishlating.
Healthcheck va uptime monitoring¶
Yuqoridagi alertlar server ichidan keladi (Prometheus serveringizda). Lekin agar butun server yoki tarmoq o'lsa? Prometheus ham o'lgan bo'ladi β sizga xabar yetmaydi. Shuning uchun ikki qatlam kerak:
- Blackbox exporter (ichkaridan, lekin tashqaridan qaragandek) β saytingizga HTTP so'rov yuborib, javob beradimi, sertifikat amal qiladimi tekshiradi. Prometheus uni "scrape" qiladi:
scrape_configs:
- job_name: "blackbox-http"
metrics_path: /probe
params:
module: [http_2xx]
static_configs:
- targets:
- "https://vazifalar.example.uz"
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: "blackbox-exporter:9115"
- Tashqi uptime (UptimeRobot va boshqalar) β butunlay boshqa joydan (boshqa data-markaz) saytingizni tekshiradi. Server bilan birga sizning Prometheus'ingiz ham o'lsa, tashqi xizmat baribir SMS/email yuboradi. Bu β eng oddiy, lekin eng ishonchli "sayt ko'rinadimi?" tekshiruvi.
π Qoida: o'zingizni o'zingiz kuzata olmaysiz. Kamida bitta tashqi uptime monitor qo'ying (UptimeRobot bepul tarif beradi) β server butunlay o'lsa, ichki Prometheus emas, faqat shu sizni ogohlantiradi.
3-qism: Ishonchlilik (SRE) asoslari β SLI, SLO, SLA, error budget¶
Alert qachon kerak? "100% ishlamasa" desangiz β mukammallik mumkin emas, har chiqindan alert kelaveradi. Buni o'lchashning aniq tili bor β Google ixtiro qilgan SRE (Site Reliability Engineering) atamalari. Kirish darajasida:
- SLI (Service Level Indicator) β o'lchov. "So'rovlarning necha foizi muvaffaqiyatli (2xx/3xx)?" yoki "javob vaqti 300ms dan kammi?". Bu β 25-bobdagi metrikadan kelib chiqadigan raqam.
- SLO (Service Level Objective) β maqsad. "So'rovlarning 99.9% muvaffaqiyatli bo'lsin (oyiga)." Ichki maqsad, jamoa o'ziga qo'yadi.
- SLA (Service Level Agreement) β shartnoma. Mijoz bilan rasmiy kelishuv: "99.9% bo'lmasa, pul qaytaramiz." SLA odatda SLO dan biroz bo'shroq (xavfsizlik chegarasi).
- Error budget β xato byudjeti. 99.9% SLO = oyiga 0.1% "uzilishga ruxsat". Bu β taxminan 43 daqiqa/oy. Mana shu β sizning "byudjetingiz".
Error budget'ning kuchi β u qaror beradi:
- Byudjet hali to'lmagan (43 daqiqadan kam uzildi) -> jasur bo'l, yangi feature deploy qil, tajriba qil.
- Byudjet tugadi (oy oxirigacha 43 daqiqa o'tib ketdi) -> to'xta, faqat barqarorlik ustida ishla, riskli deploy qilma.
| SLO | Yiliga ruxsat etilgan uzilish | Oyiga taxminan |
|---|---|---|
| 99% ("ikki to'qqiz") | ~3.65 kun | ~7 soat |
| 99.9% ("uch to'qqiz") | ~8.76 soat | ~43 daqiqa |
| 99.99% ("to'rt to'qqiz") | ~52.6 daqiqa | ~4.3 daqiqa |
π‘ Boshlang'ich loyiha uchun 99.9% real maqsad. 100% maqsad qilmang β har qo'shimcha "to'qqiz" eksponensial qimmat va deyarli imkonsiz. Error budget falsafasi: "biroz uzilishga ruxsat bor, uni aqlli sarflang". Alertni SLO atrofida sozlang β har minutlik chiqindan emas, byudjetni jiddiy yeyayotgan muammodan ogohlantirsin.
4-qism: Backup va recovery β falokatdan tiklanish¶
Eng oxirgi himoya qatlami. Metrika va log "nimadir buzildi" deganda yordam beradi; backup esa "ma'lumot yo'qoldi" deganda β yagona umid.
Nega backup¶
- DB buzilishi β disk xatosi, kutilmagan o'chish paytida baza shikastlanadi.
- Inson xatosi β kimdir
DROP TABLE users;yokiDELETEniWHEREsiz ishlatadi (eng ko'p uchraydigan sabab!). - Ransomware / hujum β disk shifrlanadi, to'lov so'raladi.
- Disk o'limi β apparat shunchaki o'ladi.
- Noto'g'ri deploy β migratsiya ma'lumotni buzadi.
DB backup: pg_dump / mysqldump¶
PostgreSQL uchun pg_dump, MySQL/MariaDB uchun mysqldump β bazani bitta matn (SQL) faylga "to'kadi". Bu fayldan keyin bazani to'liq qayta tiklash mumkin:
# PostgreSQL: bazani siqilgan SQL faylga olish
pg_dump -U vazifalar vazifalar | gzip > backup.sql.gz
# MySQL/MariaDB ekvivalenti
mysqldump -u vazifalar -p vazifalar | gzip > backup.sql.gz
| gzip β chiqishni darhol siqadi (SQL matn yaxshi siqiladi, ko'pincha 5-10 barobar).
Volume backup: tar¶
Foydalanuvchi yuklagan fayllar (rasmlar, hujjatlar) bazada emas, volumeda (10-bob). Ularni tar bilan arxivlaysiz:
-c yarat, -z gzip bilan siq, -f fayl nomi, -C <dir> . β shu papka ichidagini arxivla.
3-2-1 qoidasi va retention¶
Backup faylni server ichida qoldirish yetarli emas β server o'lsa, backup ham o'ladi. Sanoat standarti β 3-2-1 qoidasi:
- 3 nusxa (asl + 2 backup),
- 2 xil saqlash turida/joyida,
- 1 nusxa off-site (boshqa shahar/data-markaz yoki bulut β S3, Cloudflare R2,
rclonebilan).
Retention β eski backup'larni avtomatik o'chirish (yo'qsa disk to'ladi). "Oxirgi 14 kunlik kunlik backup'larni saqla" odatiy.
π 3-2-1 qoidasini soddalashtiring: kamida bitta nusxa boshqa joyda bo'lsin. Hammasi bitta serverda bo'lsa β server o'chsa, hammasi ketadi.
rclonebilan kuniga bir marta bulut saqlashga nusxa ko'chirish β eng oson off-site yo'l.
Eng muhimi: RESTORE'ni sinash¶
β οΈ Sinalmagan backup β backup emas. Eng ko'p uchraydigan falokat: yillab backup olinadi, falokat kuni ma'lum bo'ladi-ki, backup buzuq edi / bo'sh edi / qaytarib bo'lmaydi. Backup olishning yagona maqsadi β qaytara olish. Buni isbotlamaguningizcha backup'ingiz bor deb hisoblamang.
Restore β backup'ning teskarisi:
# PostgreSQL: siqilgan backup'dan bazani tiklash
gunzip -c backup.sql.gz | psql -U vazifalar vazifalar
# Volume'ni tiklash
tar -xzf files.tar.gz -C /opt/vazifalar-api/uploads
Doimo test bazaga restore qilib sinang (ishlab turgan production'ga emas!): backup ochiladimi, jadvallar to'g'rimi, qatorlar soni mantiqiymi. Buni oyiga bir marta jadvalga qo'ying.
π‘ Bu bobdagi backup/restore mantig'ini haqiqatan sinab ko'rdim:
tarbilan sanali arxiv yaratish,find -mtime +14 -deletebilan eski'larni o'chirish (14 kundan eski fayl o'chdi, yangisi qoldi), vagzip | ... | gunzipround-trip (siqildi, to'liq qaytarildi) β hammasi lokal bash'da ishladi.pg_dump/psqlreal bazani talab qiladi (illustrativ), lekin tar/find/gzip mantig'i tekshirilgan.
To'liq avtomatik backup skripti¶
Hammasini birlashtiramiz β kuniga bir marta cron ishlatadigan skript: DB backup + volume backup + sanali nom + eski'larni tozalash.
#!/usr/bin/env bash
# backup.sh β vazifalar-api uchun kunlik DB + volume backup
set -euo pipefail
# --- Sozlamalar ---
BACKUP_DIR="/var/backups/vazifalar"
DB_NAME="vazifalar"
DB_USER="vazifalar"
DATA_DIR="/opt/vazifalar-api/uploads" # foydalanuvchi yuklagan fayllar (volume)
RETENTION_DAYS=14 # 14 kundan eski backup'lar o'chiriladi
STAMP="$(date +%Y-%m-%d_%H%M%S)" # masalan 2026-06-13_032001
mkdir -p "$BACKUP_DIR"
# --- 1) PostgreSQL backup (pg_dump, siqilgan) ---
DB_FILE="$BACKUP_DIR/db_${DB_NAME}_${STAMP}.sql.gz"
pg_dump -U "$DB_USER" "$DB_NAME" | gzip > "$DB_FILE"
echo "DB backup: $DB_FILE"
# --- 2) Volume (yuklamalar) backup (tar) ---
FILES_FILE="$BACKUP_DIR/files_${STAMP}.tar.gz"
tar -czf "$FILES_FILE" -C "$DATA_DIR" .
echo "Fayllar backup: $FILES_FILE"
# --- 3) Eski backup'larni tozalash (retention) ---
find "$BACKUP_DIR" -name 'db_*.sql.gz' -mtime "+${RETENTION_DAYS}" -delete
find "$BACKUP_DIR" -name 'files_*.tar.gz' -mtime "+${RETENTION_DAYS}" -delete
echo "Tozalandi: ${RETENTION_DAYS} kundan eski backup'lar o'chirildi"
# --- 4) (Tavsiya) off-site nusxa: 3-2-1 qoidasi ---
# rclone copy "$DB_FILE" "$FILES_FILE" remote:vazifalar-backups/
echo "Backup tugadi: $STAMP"
Cron bilan har kuni 03:00 da (3-bobni eslang):
Yoki 19-bobdagidek systemd timer bilan (loglar journalctl da, o'tkazib yuborilgan ishni Persistent=true qoplaydi).
Mos restore skripti:
#!/usr/bin/env bash
# restore.sh β backup faylidan DB ni tiklash
set -euo pipefail
if [ $# -ne 1 ]; then
echo "Foydalanish: $0 <db_backup_file.sql.gz>"
exit 1
fi
DB_FILE="$1"
DB_NAME="vazifalar"
DB_USER="vazifalar"
if [ ! -f "$DB_FILE" ]; then
echo "Xato: fayl topilmadi: $DB_FILE"
exit 1
fi
echo "DIQQAT: '$DB_NAME' bazasi $DB_FILE dan tiklanadi (mavjud ma'lumot almashtiriladi)."
gunzip -c "$DB_FILE" | psql -U "$DB_USER" "$DB_NAME"
echo "Restore tugadi: $DB_FILE -> $DB_NAME"
π
set -euo pipefailβ har backup skriptida bo'lsin (3-bob): xatoda darhol to'xta (-e), e'lon qilinmagan o'zgaruvchida xato (-u), quvur (|) o'rtasidagi xato ham aniqlansin (pipefail).pg_dumpyiqilsa, skript "muvaffaqiyat" deb yolg'on aytmasligi uchun muhim.βΉοΈ
pg_dump/psqlqatorlari haqiqiy bazani talab qiladi β ularni o'z serveringizda ishlating. Skriptlarning tar/find/gzip/sana mantig'i va sintaksisi (bash -n+ haqiqiy ishga tushirish) bu bobda tekshirilgan.
Yakun¶
Monitoringni to'liq qildik: 25-bobda metrika ("nimadir buzildi"), bu bobda log ("nega buzildi"), alert ("buzilganda xabar ber"), va backup ("yo'qolsa qaytar"). Markazlashtirilgan logni (Loki + Alloy + Grafana) ko'rdik, logrotate va Docker log limitlari bilan diskni himoya qildik, strukturali JSON log yozishni o'rgandik. Alerting'da Prometheus qoidalari (expr/for/labels/annotations) va Alertmanager (routing, grouping, Telegram receiver, amtool), tashqi uptime monitoring; SRE tilida SLI/SLO/SLA/error budget; va to'liq avtomatik backup + restore skripti β eng muhim qoida bilan: restore'ni sinamaguningizcha backup'ingizga ishonmang.
Tizimingiz endi nafaqat ishlaydi, balki ishonchli: kuzatiladi, ogohlantiradi va falokatdan tiklanadi. Keyingi 27-bobda butun shu infratuzilmani β serverlar, paketlar, config'lar β qo'lda emas, kod sifatida boshqarishni o'rganamiz: Infrastructure as Code (Ansible va Terraform).
26-bob mashqlari¶
Oson¶
- Markazlashtirilgan log nima va nega bir nechta server/konteynerda kerak? Bir-ikki jumlada ayting.
docker logs -f --tail 50 vazifalarbuyrug'idagi-fva--tail 50nima qiladi?json-fileDocker log drayverining standart holatda qanday xavfi bor? Uni qanday cheklash mumkin (compose.yamlda ikki opsiya)?- Oddiy matn log va strukturali (JSON) log orasidagi farq nima? JSON logning bitta amaliy afzalligini ayting.
- SLI, SLO va SLA atamalarini bittadan jumlada izohlang. Qaysi biri mijoz bilan rasmiy shartnoma?
O'rta¶
- Prometheus alert qoidasidagi
for: 5mnima vazifa bajaradi? Agar uni olib tashlasangiz qanday muammo paydo bo'ladi? - Alertmanager nima uchun kerak β Prometheus o'zi xabar yubora olmaydimi?
groupingvaroutingni bittadan jumlada tushuntiring. - 99.9% SLO oyiga taxminan qancha uzilishga "ruxsat" beradi? Error budget tugaganda jamoa nima qilishi kerak?
- 3-2-1 backup qoidasini tushuntiring. Nega faqat serverning o'zida backup saqlash xavfli?
- "Sinalmagan backup β backup emas" iborasi nimani anglatadi? Restore'ni qayerda sinash kerak (production'dami?) va nega?
Qiyin¶
up == 0shartini 3 daqiqa davom etgandacriticaldarajali,{{ $labels.job }}nisummaryda ko'rsatadiganJobDownnomli Prometheus alert qoidasini yozing (alert-rules.ymlformatida).forvalabels/annotationsni to'g'ri qo'ying.severity = criticalalertlarni Telegram'ga, qolganlarini email'ga yo'naltiradigan minimalalertmanager.ymlyozing:routedagroup_by, ikkita receiver (telegram-critical,email-default), va kritiklar uchun maxsusroutesyozuvi bilan. Config'ni qaysi buyruq bilan tekshirasiz?- Kunlik backup skripti yozing: PostgreSQL
mybazabazasinipg_dump | gzipbilan/var/backupsga sanali nom (db_YYYY-MM-DD.sql.gz) bilan olsin,/opt/app/datapapkasinitarqilsin, va 7 kundan eskidb_*.sql.gzfayllarni o'chirsin.set -euo pipefailishlating. So'ng buni har kuni 02:00 da ishlatadigan crontab qatorini yozing.
Yechim β 11
groups:
- name: vazifalar-api
rules:
- alert: JobDown
expr: up == 0
for: 3m
labels:
severity: critical
annotations:
summary: "{{ $labels.job }} ishlamayapti"
description: "{{ $labels.job }} ({{ $labels.instance }}) 3 daqiqadan beri javob bermayapti."
expr: up == 0 β target javob bermasa rost bo'ladi. for: 3m β shart 3 daqiqa davom etsa firing (o'tkinchi chiqindan filtr). severity: critical β Alertmanager shu label bo'yicha Telegram'ga yo'naltiradi. {{ $labels.job }} β alert qaysi job'dan kelganini xabarga qo'yadi. Tekshirish: promtool check rules alert-rules.yml.
Yechim β 12
route:
receiver: email-default
group_by: ["alertname", "job"]
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- matchers:
- severity = critical
receiver: telegram-critical
repeat_interval: 1h
receivers:
- name: email-default
email_configs:
- to: "jamoa@example.uz"
from: "alert@example.uz"
smarthost: "smtp.example.uz:587"
auth_username: "alert@example.uz"
auth_password: "REPLACE_WITH_PASSWORD"
- name: telegram-critical
telegram_configs:
- bot_token: "123456:REPLACE_WITH_TOKEN"
chat_id: -1001234567890
send_resolved: true
Standart receiver β email-default (hamma narsa email'ga). routes ichidagi matchers: severity = critical β faqat kritiklarni telegram-critical ga yo'naltiradi (va tezroq, har 1 soatda takror). group_by o'xshash alertlarni bitta xabarga jamlaydi. Tekshirish: amtool check-config alertmanager.yml, marshrutni sinash: amtool config routes test --config.file=alertmanager.yml severity=critical.
Yechim β 13
#!/usr/bin/env bash
# backup.sh β mybaza uchun kunlik backup
set -euo pipefail
BACKUP_DIR="/var/backups"
DB_NAME="mybaza"
DB_USER="mybaza"
DATA_DIR="/opt/app/data"
RETENTION_DAYS=7
STAMP="$(date +%Y-%m-%d)"
mkdir -p "$BACKUP_DIR"
# DB backup (sanali nom)
pg_dump -U "$DB_USER" "$DB_NAME" | gzip > "$BACKUP_DIR/db_${STAMP}.sql.gz"
# Volume backup
tar -czf "$BACKUP_DIR/files_${STAMP}.tar.gz" -C "$DATA_DIR" .
# 7 kundan eski DB backup'larni o'chir
find "$BACKUP_DIR" -name 'db_*.sql.gz' -mtime +7 -delete
echo "Backup tugadi: $STAMP"
Crontab (har kuni 02:00):
STAMP="$(date +%Y-%m-%d)" sanali nom beradi (db_2026-06-13.sql.gz). pg_dump | gzip bazani siqilgan SQL faylga to'kadi. tar -czf ... -C "$DATA_DIR" . papkani arxivlaydi. find ... -mtime +7 -delete 7 kundan eski DB backup'larni o'chirib retention'ni ta'minlaydi. set -euo pipefail β pg_dump yiqilsa skript yolg'on "muvaffaqiyat" demaydi. Crontab'da >> ... 2>&1 chiqish va xatolarni log faylga yozadi.
β¬ οΈ Oldingi: 25 β Monitoring: Prometheus va Grafana Β· π README Β· Keyingi: 27 β Infrastructure as Code: Ansible va Terraform β‘οΈ