18-bo‘lim

Yuklanish jarayoni va init tizimi

BIOS va UEFI, yuklovchi, yadro yuklanishi, initramfs, PID 1 va systemd, xizmatlarni boshqarish va daemon yaratish.

🕑 23 daqiqa o‘qish 📄 1 009 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. To'liq zanjir
  2. UEFI va BIOS
  3. Yadro parametrlari
  4. initramfs nima uchun kerak?
  5. PID 1
  6. systemd birliklari
  7. Yuklanish tezligini tahlil qilish
  8. Daemon yaratish
  9. Loglarni ko'rish
  10. Xulosa

Tugmani bosgandan qobiq belgisi chiqqunicha o'nlab bosqich o'tadi. Ularni bilish nosozliklarni topishda hal qiluvchi ahamiyatga ega.

To'liq zanjir #

Quvvat tugmasidan qobiqqacha 1. UEFI / BIOS Apparatni tekshiradi, yuklash qurilmasini topadi 2. Yuklovchi (GRUB) Yadro va initramfs ni xotiraga yuklaydi 3. Yadro Xotirani sozlaydi, drayverlarni yuklaydi 4. initramfs Haqiqiy ildiz diskini topadi va ulaydi 5. PID 1 (systemd) Xizmatlarni bog'liqlik tartibida ishga tushiradi 6. Kirish (login) getty yoki grafik menejer, keyin qobiq Har bosqich keyingisini yuklaydi va boshqaruvni unga topshiradi Nosozlikni topish uchun qaysi bosqichda to'xtaganini aniqlang
Har bir bosqich o'zidan katta va murakkabroq dasturni yuklaydi

UEFI va BIOS #

XususiyatBIOS (eski)UEFI (zamonaviy)
Disk jadvaliMBRGPT
Maksimal disk2 TB9 ZB
Bo'limlar soni4 ta asosiy128+
Yuklovchi joyiBirinchi 512 baytEFI bo'limidagi fayl
Xavfsiz yuklashYo'qSecure Boot
Terminal
[ -d /sys/firmware/efi ] && echo "UEFI" || echo "BIOS"
Natija
UEFI
Terminal
sudo efibootmgr
Natija
BootCurrent: 0001
BootOrder: 0001,0000,2001
Boot0000* Windows Boot Manager
Boot0001* ubuntu
Boot2001* EFI USB Device
Terminal
lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT
Natija
NAME   SIZE FSTYPE MOUNTPOINT
nvme0n1 476G
├─p1    512M vfat   /boot/efi
├─p2      1G ext4   /boot
└─p3    474G LVM2_member

Yadro parametrlari #

Terminal
cat /proc/cmdline
Natija
BOOT_IMAGE=/vmlinuz-6.8.0-45-generic root=UUID=a1b2c3d4 ro quiet splash
ParametrMa'nosi
root=Ildiz fayl tizimi qayerda
roAvval faqat o'qishga ulash
quietYuklanish xabarlarini yashirish
singleBir foydalanuvchili rejim
init=/bin/bashsystemd o'rniga qobiq
nomodesetVideo drayverni yuklamaslik
Parolni unutganda

GRUB menyusida e bosib, linux qatoriga qo'shing:

Natija
init=/bin/bash

Ctrl+X bilan yuklaganingizda systemd o'rniga to'g'ridan-to'g'ri qobiq ochiladi - parolsiz, root sifatida.

Keyin:

Terminal
mount -o remount,rw /
passwd husanboy
exec /sbin/init

Bu jismoniy kirish - parolni chetlab o'tish demakdir. Shuning uchun serverlarda:

  1. GRUB ga parol qo'yiladi;
  2. Disk shifrlanadi (LUKS);
  3. Secure Boot yoqiladi.

Shifrlanmagan disk va jismoniy kirish - hamma parol va huquqlar ma'nosiz demakdir.

initramfs nima uchun kerak? #

Terminal
lsinitramfs /boot/initrd.img-$(uname -r) | head -12
Natija
.
bin
conf
etc
init
lib
scripts
usr/lib/modules/6.8.0-45-generic/kernel/drivers/md/raid1.ko
usr/lib/modules/6.8.0-45-generic/kernel/drivers/scsi/sd_mod.ko
usr/lib/modules/6.8.0-45-generic/kernel/fs/ext4/ext4.ko
"Tovuq va tuxum" muammosi

Yadro ildiz fayl tizimini ulashi kerak. Buning uchun unga kerak:

  • Disk kontrolleri drayveri (NVMe, SATA, RAID);
  • Fayl tizimi drayveri (ext4, XFS, Btrfs);
  • Shifrlangan bo'lsa - LUKS moduli;
  • LVM bo'lsa - LVM vositalari.

Lekin bu drayverlar diskda yotibdi, unga esa hali kira olmaymiz.

initramfs - xotiraga yuklanadigan kichik vaqtinchalik fayl tizimi. Unda kerakli modullar va init skripti bor. U:

  1. Kerakli modullarni yuklaydi;
  2. Shifrlangan diskdan parolni so'raydi;
  3. LVM/RAID ni yig'adi;
  4. Haqiqiy ildizni ulaydi;
  5. switch_root bilan boshqaruvni unga o'tkazadi.

Yadroni yangilagandan keyin initramfs ni qayta qurish kerak:

Terminal
sudo update-initramfs -u -k all

Aks holda tizim yuklanmay qolishi mumkin - eng ko'p uchraydigan "yuklanmayapti" sababi.

PID 1 #

C
#include <stdio.h>
#include <unistd.h>

int main(void) {
    pid_t ozim = getpid();
    pid_t ota = getppid();

    printf("Bizning PID     : %s\n", ozim == 1 ? "1 - biz init miz" : "1 emas");
    printf("Otamiz bormi?   : %s\n", ota > 0 ? "ha" : "yo'q");
    printf("Ota PID 1 mi?   : %s\n",
           ota == 1 ? "ha - to'g'ridan-to'g'ri init dan" : "yo'q");

    printf("\nPID 1 ning maxsus xossalari:\n");
    printf("  - Uni o'ldirib bo'lmaydi (yadro panic beradi)\n");
    printf("  - Yetim jarayonlar unga meros qoladi\n");
    printf("  - U zombi jarayonlarni yig'ishi shart\n");
    printf("  - Odatiy signal ta'siri unga qo'llanmaydi\n");

    return 0;
}
Natija
Bizning PID     : 1 emas
Otamiz bormi?   : ha
Ota PID 1 mi?   : yo'q

PID 1 ning maxsus xossalari:
  - Uni o'ldirib bo'lmaydi (yadro panic beradi)
  - Yetim jarayonlar unga meros qoladi
  - U zombi jarayonlarni yig'ishi shart
  - Odatiy signal ta'siri unga qo'llanmaydi
Terminal
ps -p 1 -o pid,comm,args
Natija
    PID COMMAND         COMMAND
      1 systemd         /sbin/init splash
Docker konteynerlarida PID 1 muammosi

Konteynerda sizning dasturingiz PID 1 bo'ladi. Bu ikki muammo tug'diradi:

1. Zombi jarayonlar to'planadi

Konteyner ichida dasturingiz bola yaratib, ularni yig'masa, ular abadiy zombi bo'lib qoladi - chunki ularni yig'adigan "haqiqiy init" yo'q.

2. Signallar ishlamaydi

PID 1 uchun odatiy signal ta'siri qo'llanmaydi. Ishlovchi o'rnatilmagan bo'lsa, SIGTERM shunchaki e'tiborsiz qoladi.

Natija: docker stop 10 soniya kutadi, keyin SIGKILL yuboradi. Ma'lumot yo'qoladi.

Yechimlar:

DOCKERFILE
# 1. Kichik init ishlatish
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["node", "server.js"]
Terminal
# 2. Docker ning o'z init i
docker run --init mening-obrazim
DOCKERFILE
# 3. exec shakli - qobiq oradan chiqadi
CMD ["node", "server.js"]      # to'g'ri
# CMD node server.js           # noto'g'ri - PID 1 bu sh

Uchinchisi eng ko'p uchraydigan xato: CMD ning qobiq shaklida PID 1 bo'lib /bin/sh qoladi va u signalni dasturingizga uzatmaydi.

systemd birliklari #

TurNima uchun
.serviceXizmat (daemon)
.socketSoketni tinglash, so'rovda xizmatni ishga tushirish
.timerVaqt bo'yicha ishga tushirish (cron o'rniga)
.mountFayl tizimini ulash
.targetBirliklar guruhi (runlevel o'rniga)
.pathFayl o'zgarganda ishga tushirish
Terminal
systemctl list-units --type=service --state=running | head -6
Natija
UNIT                     LOAD   ACTIVE SUB     DESCRIPTION
cron.service             loaded active running Regular background program
dbus.service             loaded active running D-Bus System Message Bus
nginx.service            loaded active running A high performance web server
ssh.service              loaded active running OpenBSD Secure Shell server
systemd-journald.service loaded active running Journal Service
INI
[Unit]
Description=Mening veb xizmatim
After=network.target
Requires=postgresql.service

[Service]
Type=notify
User=veb
Group=veb
WorkingDirectory=/opt/mening-xizmatim
ExecStart=/opt/mening-xizmatim/server
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5

# Xavfsizlik cheklovlari
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/mening-xizmatim
AmbientCapabilities=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target
Terminal
sudo systemctl daemon-reload
sudo systemctl enable --now mening-xizmatim
systemctl status mening-xizmatim
systemd xavfsizlik cheklovlari

Yuqoridagi faylning "Xavfsizlik" qismi juda kuchli - u AppArmor profiliga o'xshash himoya beradi, lekin sozlash ancha oson:

SozlamaTa'siri
NoNewPrivilegessetuid orqali huquq ko'tarib bo'lmaydi
PrivateTmpO'z alohida /tmp katalogi
ProtectSystem=strictButun fayl tizimi faqat o'qishga
ProtectHome/home ko'rinmaydi
ReadWritePathsFaqat sanab o'tilgan joyga yozish
PrivateDevices/dev cheklangan
RestrictAddressFamiliesFaqat kerakli soket turlari

Xizmatingiz qanchalik himoyalanganini baholash:

Terminal
systemd-analyze security nginx.service
Natija
→ Overall exposure level for nginx.service: 8.1 EXPOSED 🙁

Ball 0 dan 10 gacha - past bo'lgani yaxshi. Har bir sozlamani qo'shgach ball tushadi.

Yuklanish tezligini tahlil qilish #

Terminal
systemd-analyze
Natija
Startup finished in 4.812s (firmware) + 2.104s (loader) + 3.284s (kernel)
+ 8.412s (userspace) = 18.613s
graphical.target reached after 8.401s in userspace
Terminal
systemd-analyze blame | head -6
Natija
4.821s NetworkManager-wait-online.service
2.104s snapd.service
1.284s docker.service
 892ms systemd-journal-flush.service
 621ms [email protected]
Terminal
systemd-analyze critical-chain
Natija
graphical.target @8.401s
└─multi-user.target @8.398s
  └─docker.service @7.112s +1.284s
    └─network-online.target @7.108s
      └─NetworkManager-wait-online.service @2.284s +4.821s

+ belgisi - xizmatning o'z ishlash vaqti; @ - u boshlangan payt.

Daemon yaratish #

C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>

/* An'anaviy daemon yaratish - klassik ikki fork usuli */
static int daemonlashtirish(void) {
    pid_t birinchi = fork();

    if (birinchi < 0) {
        return -1;
    }

    if (birinchi > 0) {
        _exit(0);                  /* ota chiqadi - bola yetim bo'ladi */
    }

    /* Yangi sessiya - terminaldan uziladi */
    if (setsid() < 0) {
        return -1;
    }

    /* Ikkinchi fork - endi terminal ola olmaymiz */
    pid_t ikkinchi = fork();

    if (ikkinchi < 0) {
        return -1;
    }

    if (ikkinchi > 0) {
        _exit(0);
    }

    umask(0);
    if (chdir("/") < 0) {          /* ulangan diskni band qilmaslik */
        return -1;
    }

    return 0;
}

int main(void) {
    printf("Daemon yaratish bosqichlari:\n");
    printf("  1. fork  - ota chiqadi, bola yetim bo'ladi\n");
    printf("  2. setsid - yangi sessiya, terminaldan uzilish\n");
    printf("  3. fork  - sessiya yetakchisi bo'lmaslik\n");
    printf("  4. umask(0) - huquqlarni to'liq nazorat qilish\n");
    printf("  5. chdir(\"/\") - ulangan diskni bo'shatish\n");
    printf("  6. 0,1,2 ni /dev/null ga yo'naltirish\n");

    /* Funksiya ishlatilganini kompilyatorga bildiramiz */
    printf("\nFunksiya mavjudmi? %s\n",
           daemonlashtirish != NULL ? "ha" : "yo'q");

    printf("\nsystemd bilan bularning hech biri KERAK EMAS\n");
    printf("Type=simple bilan oddiy dastur yozing\n");

    return 0;
}
Natija
Daemon yaratish bosqichlari:
  1. fork  - ota chiqadi, bola yetim bo'ladi
  2. setsid - yangi sessiya, terminaldan uzilish
  3. fork  - sessiya yetakchisi bo'lmaslik
  4. umask(0) - huquqlarni to'liq nazorat qilish
  5. chdir("/") - ulangan diskni bo'shatish
  6. 0,1,2 ni /dev/null ga yo'naltirish

Funksiya mavjudmi? ha

systemd bilan bularning hech biri KERAK EMAS
Type=simple bilan oddiy dastur yozing
Zamonaviy xizmat daemon bo'lishi shart emas

Yuqoridagi ikki fork usuli - 1980-yillar an'anasi. systemd davrida u nafaqat keraksiz, balki zararli:

MuammoSabab
systemd PID ni yo'qotadiOta chiqib ketadi
Loglar yo'qoladistdout /dev/null ga ketgan
Qayta ishga tushirish buziladiHolatni kuzatib bo'lmaydi

To'g'ri yondashuv - oddiy dastur yozing:

C
int main(void) {
    while (ishlaymiz) {
        sorovni_qayta_ishlash();
        printf("so'rov bajarildi\n");     /* journald yig'adi */
    }
}
INI
[Service]
Type=simple
ExecStart=/opt/xizmat/server

Loglar avtomatik journald ga tushadi:

Terminal
journalctl -u mening-xizmatim -f

Agar xizmat "tayyorman" deb aytishi kerak bo'lsa, Type=notify va sd_notify(0, "READY=1") ishlating - bu systemd ga aniq signal beradi.

Loglarni ko'rish #

Terminal
journalctl -b -p err
Natija
sen 09 08:14:22 husanboy-pc kernel: ACPI Error: No handler for Region
sen 09 08:14:31 husanboy-pc bluetoothd[891]: Failed to set mode: Blocked
BuyruqNima ko'rsatadi
journalctl -bJoriy yuklanish loglari
journalctl -b -1Oldingi yuklanish
journalctl -u nginx -fXizmat loglarini kuzatish
journalctl -p errFaqat xatolar
journalctl --since "1 hour ago"Vaqt bo'yicha
journalctl -kFaqat yadro xabarlari
journalctl --disk-usageLoglar egallagan joy
Terminal
dmesg -T | tail -3
Natija
[Mon Sep  9 08:14:18 2026] EXT4-fs (nvme0n1p3): mounted filesystem
[Mon Sep  9 08:14:19 2026] systemd[1]: systemd 255 running in system mode
[Mon Sep  9 08:14:22 2026] nvidia: loading out-of-tree module
Amaliy topshiriq
  1. Tizimingiz UEFI yoki BIOS ekanini aniqlang.
  2. /proc/cmdline dagi yadro parametrlarini tushuntiring.
  3. lsinitramfs bilan initramfs ichidagi modullarni ko'ring.
  4. initramfs nima uchun kerakligini o'z so'zingiz bilan ayting.
  5. ps -p 1 bilan PID 1 nima ekanini aniqlang.
  6. Docker da PID 1 muammosini va uch yechimini sanang.
  7. O'zingizning .service faylingizni yozing.
  8. systemd-analyze security bilan xizmatni baholang.
  9. systemd-analyze blame bilan sekin xizmatni toping.
  10. journalctl -b -p err bilan yuklanish xatolarini ko'ring.

Xulosa #

  • Yuklanish: UEFI → yuklovchi → yadro → initramfs → PID 1 → login.
  • UEFI GPT bilan ishlaydi va Secure Boot ni qo'llab-quvvatlaydi.
  • Yadro parametrlari /proc/cmdline da ko'rinadi.
  • init=/bin/bash bilan parolni chetlab o'tish mumkin - disk shifrlash shart.
  • initramfs "tovuq va tuxum" muammosini hal qiladi.
  • Yadro yangilangach initramfs ni qayta quring.
  • PID 1 ni o'ldirib bo'lmaydi; u zombi larni yig'adi.
  • Konteynerda PID 1 SIGTERM ni e'tiborsiz qoldiradi.
  • CMD ning exec shaklini ishlating.
  • systemd birliklari: .service, .socket, .timer, .target.
  • systemd xavfsizlik cheklovlari AppArmor kabi himoya beradi.
  • Zamonaviy xizmat daemon bo'lishi shart emas - Type=simple.

Keyingi bo'limda virtualizatsiya va konteynerlarni ko'ramiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.