Mashqlar — Node.js ilovani systemd xizmatiga aylantirish

~25 daq · Linux · Jarayonlar va tizim

Muammodan boshlaylik

Sizda oddiy Node.js API bor. Vazifa — uni "haqiqiy" xizmatga aylantirish:

  • Alohida foydalanuvchi nomidan ishlaydi
  • Server yuklanganda o'zi ishga tushadi
  • Qulasa — qayta ko'tariladi
  • SIGTERM da to'g'ri yopiladi
  • Loglari journald da
  • Xotirasi cheklangan

Bu — 18–27-darslarning hammasi bir joyda. WSL da ham ishlaydi (systemd yoqilgan bo'lsa — pastdagi eslatmaga qarang).

[!INFO] WSL da systemd: /etc/wsl.conf faylida [boot] bo'limiga systemd=true qo'shing, keyin PowerShell da wsl --shutdown va Ubuntu ni qayta oching. Tekshirish: systemctl --version. Yangi WSL o'rnatmalarida odatda allaqachon yoqilgan.


Tayyorgarlik: ilova

Node.js o'rnatilganini tekshiring (node -v). Bo'lmasa:

sudo apt install -y nodejs

Oddiy ilova (hech qanday paketsiz):

sudo mkdir -p /opt/salom
sudo tee /opt/salom/server.js > /dev/null << 'EOF'
const http = require('http');
const PORT = process.env.PORT || 3000;
let sorovlar = 0;

const server = http.createServer((req, res) => {
  sorovlar++;
  if (req.url === '/crash') {
    console.error('Ataylab qulatilmoqda!');
    process.exit(1);
  }
  if (req.url === '/leak') {
    global.axlat = global.axlat || [];
    for (let i = 0; i < 1e6; i++) global.axlat.push({ i, s: 'x'.repeat(100) });
    console.warn('Xotira:', Math.round(process.memoryUsage().rss / 1e6), 'MB');
  }
  res.end(`Salom! So'rov #${sorovlar}, PID ${process.pid}, foydalanuvchi ${process.env.USER || require('os').userInfo().username}\n`);
});

server.listen(PORT, () => console.log(`Ishga tushdi: ${PORT}-port, PID ${process.pid}`));

process.on('SIGTERM', () => {
  console.log('SIGTERM olindi, ulanishlar yopilmoqda...');
  server.close(() => {
    console.log('Toza yopildi.');
    process.exit(0);
  });
});
EOF

Qo'lda sinang:

node /opt/salom/server.js
# boshqa terminalda: curl localhost:3000
# Ctrl+C bilan to'xtating

1-mashq: Foydalanuvchi va ruxsatlar

  1. salom nomli tizim foydalanuvchisini yarating (uy papkasiz, kirish huquqisiz)
  2. /opt/salom ning egasini unga o'zgartiring
  3. Fayllar ruxsati: papka 750, fayl 640
  4. salom foydalanuvchisi nomidan faylni o'qish mumkinligini tekshiring
Yechim
sudo useradd --system --no-create-home --shell /usr/sbin/nologin salom
sudo chown -R salom:salom /opt/salom
sudo chmod 750 /opt/salom
sudo chmod 640 /opt/salom/server.js
sudo -u salom cat /opt/salom/server.js | head -3
id salom

2-mashq: Unit fayl

/etc/systemd/system/salom.service ni yozing:

  • salom foydalanuvchisi nomidan
  • PORT=3000 muhit o'zgaruvchisi
  • Xato bilan chiqsa — 3 soniyadan keyin qayta ishga tushsin
  • Yuklanishda avtomatik ishga tushsin

Keyin yoqing va holatini tekshiring.

Yechim
which node          # masalan: /usr/bin/node
sudo tee /etc/systemd/system/salom.service > /dev/null << 'EOF'
[Unit]
Description=Salom API
After=network.target

[Service]
Type=simple
User=salom
Group=salom
WorkingDirectory=/opt/salom
Environment=PORT=3000
ExecStart=/usr/bin/node /opt/salom/server.js
Restart=on-failure
RestartSec=3

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now salom
systemctl status salom
curl localhost:3000

curl javobida foydalanuvchi — salom.


3-mashq: Qulash va tiklanish

  1. curl localhost:3000/crash — ilovani qulating
  2. Darhol systemctl status salom — nima ko'rinyapti?
  3. 3 soniyadan keyin yana curl localhost:3000 — PID o'zgardimi?
  4. Loglardan qulash va qayta ishga tushishni toping
Yechim
curl localhost:3000/crash
systemctl status salom              # activating (auto-restart)
sleep 4
curl localhost:3000                 # yangi PID
journalctl -u salom -n 20 --no-pager
... Ataylab qulatilmoqda!
... salom.service: Main process exited, code=exited, status=1/FAILURE
... salom.service: Scheduled restart job, restart counter is at 1.
... Ishga tushdi: 3000-port, PID 5122

Restart=on-failure — chiqish kodi 0 bo'lmagani uchun qayta ishga tushirildi.


4-mashq: To'g'ri to'xtatish

  1. sudo systemctl stop salom — loglarda nima bo'lganini ko'ring
  2. Qancha vaqt ketdi? (time bilan)
  3. To'xtatilgandan keyin qayta ishga tushdimi? Nega?
Yechim
time sudo systemctl stop salom
journalctl -u salom -n 5 --no-pager
... SIGTERM olindi, ulanishlar yopilmoqda...
... Toza yopildi.
... salom.service: Deactivated successfully.

Bir zumda — chunki ilova SIGTERM ni ushlaydi (23-dars). Qayta ishga tushmadi: stop — qo'lda to'xtatish, va ilova exit(0) bilan chiqdi — on-failure faqat xatolarda ishlaydi.

sudo systemctl start salom

5-mashq: Xotira chegarasi

  1. Unit faylga MemoryMax=150M qo'shing
  2. Qayta yuklang
  3. curl localhost:3000/leak ni bir necha marta chaqiring
  4. Nima bo'ldi? Loglardan toping
Yechim

[Service] bo'limiga qo'shing:

sudo sed -i '/^RestartSec=3/a MemoryMax=150M' /etc/systemd/system/salom.service
sudo systemctl daemon-reload
sudo systemctl restart salom
systemctl show salom -p MemoryMax
for i in 1 2 3 4 5; do curl -s localhost:3000/leak; done
systemctl status salom
journalctl -u salom -n 15 --no-pager
... Xotira: 112 MB
... salom.service: A process of this unit has been killed by the OOM killer.
... salom.service: Failed with result 'oom-kill'.
... salom.service: Scheduled restart job, restart counter is at 2.

Chegara oshganda faqat shu xizmat o'ldirildi va qayta tug'ildi — server va boshqa xizmatlar zarar ko'rmadi. Docker dagi --memory ham aynan shu mexanizmda (cgroups) ishlaydi.


6-mashq: Xavfsizlik

  1. systemd-analyze security salom — baho qancha?
  2. Unit faylga NoNewPrivileges, ProtectSystem=strict, ProtectHome, PrivateTmp qo'shing
  3. Ilova ishlayotganini va baho yaxshilanganini tekshiring
Yechim
systemd-analyze security salom | tail -1
# → Overall exposure level for salom.service: 9.2 UNSAFE
sudo sed -i '/^MemoryMax=150M/a NoNewPrivileges=true\nProtectSystem=strict\nProtectHome=true\nPrivateTmp=true' \
  /etc/systemd/system/salom.service
sudo systemctl daemon-reload
sudo systemctl restart salom
curl localhost:3000
systemd-analyze security salom | tail -1
# → ... 6.1 MEDIUM

Ilova faqat o'qiydi va tarmoqqa javob beradi — yozish kerak emas, shuning uchun ProtectSystem=strict uni buzmaydi.


7-mashq: Qayta yuklanish sinovi (VPS yoki VM da)

Server qayta yuklangandan keyin xizmat o'zi ishga tushishini tekshiring.

Yechim
systemctl is-enabled salom          # enabled
sudo reboot
# ... qayta ulanib:
systemctl is-active salom           # active
curl localhost:3000
journalctl -u salom -b              # joriy yuklanishdagi loglar

WSL da: PowerShell da wsl --shutdown, keyin Ubuntu ni qayta oching.


Tozalash

sudo systemctl disable --now salom
sudo rm /etc/systemd/system/salom.service
sudo systemctl daemon-reload
sudo rm -rf /opt/salom
sudo userdel salom

Nima uchun shunday?

Nima uchun bu mashqlarda ilovani ataylab qulatdik va xotirani to'ldirdik?

Chunki tiklanish mexanizmlarini ular kerak bo'lmaguncha sinamasangiz — ular ishlashiga ishonch yo'q. Ko'p jamoalar Restart= ni yozib qo'yadi, lekin birinchi haqiqiy qulashda ma'lum bo'ladiki, ExecStart dagi yo'l noto'g'ri, yoki foydalanuvchi faylni o'qiy olmaydi, yoki enable unutilgan. Ataylab buzish — "chaos engineering" ning eng oddiy shakli: muvaffaqiyatsizlikni nazorat ostida keltirib chiqarib, tizim kutilgandek javob berishini tekshirish. Production da emas — aynan shunday mashqda.


Xulosa

Siz mashq qildingiz:

  • Tizim foydalanuvchisi, chown, chmod 750/640, sudo -u
  • Unit fayl: User, Environment, ExecStart, Restart=on-failure
  • daemon-reload, enable --now, status, stop
  • Qulashdan avtomatik tiklanish va loglardan kuzatish
  • SIGTERM bilan toza to'xtatish
  • MemoryMax — xotira chegarasi va OOM
  • ProtectSystem, NoNewPrivileges — izolyatsiya
  • systemd-analyze security — xavfsizlik bahosi

Keyingi bo'lim

6-bo'lim: Paketlar va muhit — apt, PATH, .bashrc, arxivlar.