Dřív nebo později něco přestane fungovat — služba nenaběhne, port je „obsazený", disk je plný, proces nejde zabít. Začátečník v tu chvíli hádá a náhodně zkouší příkazy z internetu. Sysadmin měří: zeptá se systému, co se děje, přečte logy a mění vždycky jen jednu věc. Tahle kapitola tě naučí ten druhý přístup — systematické ladění, kde tě k příčině dovede důkaz, ne dojem.
Pár pojmů na úvod
- Systematický přístup = neházet příkazy naslepo. Nejdřív zjisti co se změnilo, pak přečti logy, pak měň jednu věc a sleduj efekt. Tři pravidla, která ti ušetří hodiny.
- Log = záznam toho, co program dělal. Když něco spadne, skoro vždy to někam napsal proč — tvým úkolem je to jen najít a přečíst, ne to uhodnout.
- Syscall (systémové volání) = způsob, jakým proces žádá jádro o práci (otevři soubor, čti ze sítě). Když proces „visí", často čeká právě uvnitř nějakého syscallu — a to se dá odposlechnout.
- Port = číslo, na kterém služba naslouchá (např. web na 80, SSH na 22). Dva programy nemůžou držet stejný port zároveň — odtud „adresa se už používá".
- File descriptor (fd) = číselný odkaz na otevřený soubor/socket uvnitř procesu. Dokud ho někdo drží, soubor „žije" (proto nejde odpojit disk nebo uvolnit smazaný soubor).
- Zombie = proces, který už doběhl, ale rodič si ještě nevyzvedl jeho návratový kód. Nezabere paměť,
jen řádek v tabulce — a
killna něj neplatí, protože už neběží.
Zlaté pravidlo: co se změnilo?
Systém, který včera jel a dnes nejede, se nezměnil sám. Než sáhneš po nástrojích, polož si otázky:
- Nainstaloval/aktualizoval jsem něco? (
dnf history,journalctlkolem té doby) - Měnil jsem konfiguraci? (kdy naposledy? existuje
.bak?) - Došlo místo na disku, došla paměť? (o tom níž)
- Restartoval se stroj a něco nenaběhlo?
🚩 Nejčastější chyba juniora: rovnou googlí chybovou hlášku a lepí příkazy, aniž by věděl, co se vlastně rozbilo. Deset minut přemýšlení „co bylo jinak" často nahradí hodinu bezhlavého zkoušení.
Druhé pravidlo je stejně důležité: měň vždycky jen jednu věc a pak ověř. Když najednou přepíšeš tři řádky konfigurace, restartuješ službu a smažeš cache — a ono to začne jet — nevíš, co pomohlo. Příště budeš zase tápat. Jedna změna → jeden test → závěr.
Čti logy dřív, než začneš hádat
Logy jsou první místo, kam se dívat. V moderních distrech (systemd) je centrální nástroj journalctl.
# poslední řádky logu + „vysvětlivky" u chyb, skoč na konec (-e)
journalctl -xe
# log konkrétní služby (třeba nginx)
journalctl -u nginx
# jen od posledního bootu, sleduj živě (jako tail -f)
journalctl -u nginx -b -f
# co se dělo mezi časy (pozor na timestampy!)
journalctl --since "10:00" --until "10:15"
Pro jádro a hardware (disky, USB, ovladače, OOM killer) je klasika dmesg:
sudo dmesg -T # -T = lidsky čitelné časy místo sekund od bootu
sudo dmesg -w # sleduj živě (zapoj USB a koukej, co jádro řekne)
💡 Timestamp je půl řešení. Vždy si najdi v logu čas, kdy problém nastal, a čti řádky kolem něj — ne úplný konec logu. Chyba na konci může být následek, ne příčina. První skutečná chyba bývá o pár řádků výš a o pár vteřin dřív.
„Služba nejede" — status → journalctl
Nejběžnější scénář. Postup je vždy stejný:
# 1) Jaký je stav? (běží? spadla? proč?)
systemctl status nginx
# 2) Přečti log té konkrétní služby — tam je důvod
journalctl -u nginx -e
# 3) Oprav příčinu (např. překlep v configu), pak zkus znovu
sudo systemctl restart nginx
# 4) Ověř, že jede, a případně nastav autostart při bootu
systemctl status nginx
sudo systemctl enable nginx
systemctl status ti řekne active (running), failed, nebo inactive, obvykle i posledních pár
řádků logu a exit code. Když vidíš failed, důvod je v journalctl -u <služba>. Typicky: chyba
v konfiguraci, obsazený port (viz níž), chybějící soubor, špatná práva.
🚩
sudo systemctl restartnaslepo dokola je past. Když služba padá pořád dokola, restart nic nevyřeší — jen skryje log. Přečti proč padá, teprve pak restartuj.
„Port je obsazený" — ss → lsof → kill
Hláška typu bind: address already in use znamená, že port už někdo drží. Musíš zjistit kdo:
# co poslouchá na portech: -t TCP, -u UDP, -l listening, -p proces, -n čísla místo jmen
ss -tulpn
# cíleně: kdo drží port 8080?
sudo ss -tulpn | grep :8080
# nebo přímo přes lsof
sudo lsof -i :8080
lsof -i :8080 ti vypíše jméno procesu a PID. Teď se rozhodni: je to něco, co tam nemá být (starý
zapomenutý proces), nebo legitimní služba, kterou máš vypnout přes systemctl? Pokud je to opravdu
zbloudilý proces:
kill <PID> # slušně požádej proces, ať skončí (SIGTERM)
# ...počkej pár vteřin, ověř...
sudo ss -tulpn | grep :8080
kill -9 <PID> # AŽ když -15 nezabralo (tvrdé zabití, SIGKILL)
🚩
sudouss/lsofpotřebuješ, abys viděl procesy cizích uživatelů (jinak u portu neuvidíš jméno ani PID). Bezsudočasto dostaneš jen prázdno a myslíš si, že port nikdo nedrží.
„Disk je plný" — df → du → najdi viníka
No space left on device — nejdřív zjisti, který oddíl je plný (ne vždy ten, co čekáš):
df -h # přehled oddílů: velikost, použito, volno, %, kam jsou připojené
Najdi řádek se 100 % (nebo skoro). Teď se do toho adresáře přesuň a hledej, co žere místo:
# největší položky v aktuálním adresáři, seřazené
du -sh ./* 2>/dev/null | sort -h
# klasický „sestup do díry": najdi tučný adresář, vejdi, opakuj
du -sh /var/* 2>/dev/null | sort -h
Nejčastější viníci: /var/log (rozbující logy), staré Docker image/volume, /tmp, cache, zapomenutý
velký soubor po stažení. Pozor na dvě různé věci, které dojdou:
- Místo (
df -h) — bloky na disku. - Inody (
df -i) — počet souborů. Můžeš mít 50 % místa a přesto „plno", když ti milion malých souborů vyčerpal inody. Kdyždf -hukazuje volno, ale zápis stejně selže — zkontrolujdf -i.
💡 Smazání velkého souboru, který stále drží běžící proces, místo neuvolní — místo se vrátí až proces skončí (nebo restartuješ). Kdo ho drží, zjistíš přes
lsof(viz další sekce). Časté u logů, které někdorm-nul, ale služba do nich pořád píše.
„Nejde odpojit disk / target is busy" — lsof
umount: target is busy znamená, že něco má na tom mountu otevřený soubor nebo tam stojí pracovním
adresářem. Musíš najít viníka:
# kdo má něco otevřené pod /mnt/disk?
sudo lsof +D /mnt/disk
# nebo obecněji — které procesy sahají na to zařízení/cestu
sudo fuser -vm /mnt/disk
Uvidíš PID(y) a jména procesů. Nejčastější banalita: ty sám stojíš terminálem v tom adresáři
(cd /mnt/disk). Stačí cd ~ a odpojení projde. Jinak procesy slušně ukonči a zkus znovu:
cd ~ # neblokuj to vlastním shellem
sudo umount /mnt/disk
🚩
umount -l(lazy) mount jen „schová", ale odpojení dokončí až později — není to řešení, jen odklad. Nejdřív zjisti kdo drží, pak to řeš, ne obcházej.
„Proces visí" — strace a /proc
Proces žere CPU nebo naopak nic nedělá a „zamrzl"? Podívej se, co zrovna dělá — jaké syscally volá:
# připoj se k běžícímu procesu a sleduj jeho systémová volání
sudo strace -p <PID>
Když výpis stojí na read(...) nebo futex(...) a nehýbe se, proces na něco čeká (na data, na
zámek). Když se řítí openat za openat, něco horečně hledá. Doplňkově tě hodně řekne /proc/<PID>/,
kde jádro vystavuje stav procesu jako soubory (přesně to „všechno je soubor"):
ls -l /proc/<PID>/fd # co má proces otevřeno (soubory, sockety)
cat /proc/<PID>/status # stav: běží (R), spí (S), nepřerušitelně čeká (D), zombie (Z)…
cat /proc/<PID>/cmdline | tr '\0' ' ' # čím přesně byl spuštěn (i s argumenty)
Stav D (uninterruptible sleep) je důležitý: proces čeká na I/O (typicky pomalý/odumřelý disk nebo
síťový mount) a nejde ho zabít ani kill -9 — jádro ho pustí, až I/O dopadne. To není chyba procesu,
ale toho, na co čeká.
„Proces nejde zabít / zombie"
Dvě různé situace, které vypadají podobně, ale mají jinou příčinu:
- Zombie (
Z) — proces už doběhl, jen na něj rodič nesebral návratový kód.killneplatí, protože už neběží. Řešení je zabít nebo probrat rodiče (najdeš ho vestatusjakoPPid); až rodič zombie „vyzvedne" (nebo zemře a převezme ho init), zombie zmizí. Zombie sám o sobě neškodí — jen zabírá řádek v tabulce procesů. Dstate — proces čeká na I/O akill -9na něj neplatí (viz výš). Nezabíjej to dokola — najdi, na jaký disk/mount čeká, a vyřeš to (odumřelý NFS, vadný disk vdmesg).
ps -eo pid,ppid,stat,comm | grep ' Z' # najdi zombie a jejich rodiče (PPID)
💡 Na výkonové problémy (proces žere 100 % CPU nebo paměť) je samostatná kapitola o výkonu —
top/htop,ps aux --sort=-%mem. Tady jde o diagnostiku zaseknutí, ne o měření zátěže.
Rozhodovací postup (když nevíš, kde začít)
Klíč není znát nazpaměť všechny přepínače, ale mít postup: co se změnilo → logy → zúžit na druh problému → správný nástroj → jedna změna → ověřit.
Failure modes — časté omyly při ladění
- Hádání místo měření. „Asi to bude tím…" a rovnou měníš config. Nejdřív se zeptej systému
(status, logy,
ss,lsof) — důkaz > dojem. - Přeinstalace místo diagnózy. Windows reflex „přeinstaluju to". V Linuxu skoro vždy najdeš proč to spadlo a opravíš jednu věc — přeinstalace tě jen připraví o příležitost pochopit příčinu.
kill -9naslepo. SIGKILL nedá procesu šanci uklidit (dopsat soubor, uvolnit zámek) a naDstate ani zombie stejně neplatí. Nejdřív slušnýkill(SIGTERM),-9až jako poslední možnost.- Ignorování timestampů. Čteš úplný konec logu a řešíš řádek, který je následek. Najdi čas, kdy problém nastal, a čti kolem něj — první skutečná chyba bývá dřív.
- Měnění víc věcí naráz. Přepíšeš config, smažeš cache a restartuješ zároveň → zajede to → nevíš co pomohlo. Jedna změna, jeden test, jeden závěr.
🛠️ Cvičení
- Přečti si, proč něco spadlo. Vyber běžící službu (
systemctl list-units --type=service), zjisti její stav přessystemctl status <služba>a pak si zobraz její log přesjournalctl -u <služba>. Najdi v logu timestamp posledního startu. Proč je lepší číst log služby než celýjournalctl? - Kdo drží port? Spusť
ss -tulpna najdi nějakou naslouchající službu (třeba:22SSH). Pak zjisti stejný proces přessudo lsof -i :22. Porovnej, co ti oba nástroje řeknou o PID a jménu procesu. - Najdi žrouta místa. Pomocí
df -hzjisti, který oddíl máš nejvíc zaplněný. Přesuň se do jeho adresáře a přesdu -sh ./* | sort -hnajdi tři největší položky. Zkontroluj idf -i— máš dost inodů? - Nahlédni do běžícího procesu. Vyber PID nějakého svého procesu (
ps aux) a podívej se do/proc/<PID>/: co je vestatus(řádekState)? Co je vfd/? Sestav zcmdline, čím byl spuštěn. - Odpoj „busy" adresář. Otevři terminál,
cddo nějakého adresáře (klidně/tmp), a z jiného terminálu zjisti přeslsof +D /tmp, že tam ten shell „drží". Pakcd ~a ověř, že už tam nefiguruje.
Náčrt řešení — rozbal, až si cvičení zkusíš sám
- Log služby — stav zjistíš
systemctl status <služba>(uvidíšactive/failed+ posledních pár řádků logu), plný logjournalctl -u <služba>(přidej-epro skok na konec,-bjen od posledního bootu). Timestamp startu je řádekStarted …. Číst log konkrétní služby je lepší, protože celýjournalctlmíchá zprávy ze všech procesů — v šumu bys příčinu hledal těžko. Pozor: první skutečná chyba bývá výš, ne úplně na konci. - Kdo drží port —
ss -tulpnvypíše všechny naslouchající sockety (-tTCP,-uUDP,-llistening,-pproces,-nčísla); u portu 22 uvidíšsshda jeho PID.sudo lsof -i :22řekne totéž jinou cestou (proces + PID + typ socketu). Bezsudobys u cizích procesů PID/jméno neviděl. Pozor: dva programy nemůžou držet stejný port — odtud „address already in use". - Žrout místa —
df -hukáže procenta zaplnění po oddílech; do nejplnějšího se přesuň adu -sh ./* 2>/dev/null | sort -hseřadí položky od nejmenší po největší (viník je dole).df -iukazuje inody — můžeš mít volné místo, ale vyčerpané inody (spousta malých souborů) a zápis stejně selže. Pozor: smazaný soubor, který drží běžící proces, místo neuvolní, dokud proces neskončí (najdeš přeslsof). - Do procesu —
/proc/<PID>/statusmá řádekState:(např.S (sleeping),R (running),D= čeká na I/O,Z= zombie) aPPid:(rodič);fd/je seznam otevřených souborů a socketů (symlinky na cíle);cmdlineobsahuje spouštěcí příkaz s argumenty oddělenými\0(čitelně:tr '\0' ' ' < /proc/<PID>/cmdline). Pozor:/procje virtuální okno jádra, ne soubory na disku. - Busy adresář —
lsof +D /tmpvypíše procesy, které mají něco otevřené pod tou cestou, včetně shellu, jehož pracovní adresář (cwd) tam stojí. Protoumounthlásítarget is busy. Jakmile udělášcd ~, shell už/tmpnedrží a vlsofzmizí. Pozor:umount -l(lazy) problém neřeší, jen odloží — vždy nejdřív najdi a uvolni viníka.
🧠 Otázky & odpovědi
Jak mám postupovat, když něco přestane fungovat?
Systematicky, ne hádáním. Nejdřív se zeptej co se změnilo — instaloval jsem něco, měnil config,
restartoval stroj, došlo místo? Pak přečti logy (journalctl -xe pro systém, dmesg -T pro jádro
a hardware) a najdi v nich čas, kdy problém nastal — čti řádky kolem něj, ne jen konec. Teprve pak měň
jednu věc a ověř efekt. Když měníš víc věcí naráz a zajede to, nevíš co pomohlo, a příště tápeš zas.
Port hlásí address already in use — jak zjistím kdo ho drží?
Zjistíš, který proces na portu naslouchá, a rozhodneš, jestli tam patří. Použij sudo ss -tulpn (vypíše
naslouchající TCP/UDP sockety i s PID a jménem procesu) nebo cíleně sudo lsof -i :8080. Oba ti dají
PID. Pokud je to legitimní služba, vypni ji přes systemctl; pokud je to zbloudilý proces, slušně ho
ukonči přes kill <PID> a -9 až když měkký kill nezabere. sudo je nutné, jinak u cizích procesů PID
neuvidíš a budeš si myslet, že port nikdo nedrží.
Proč nejde odpojit disk — umount hlásí target is busy?
Protože něco má na tom mountu otevřený soubor nebo tam stojí pracovním adresářem. Najdi viníka přes
sudo lsof +D /mnt/disk (nebo sudo fuser -vm /mnt/disk) — dostaneš PID a jméno procesu. Nejčastější
banalita je, že tam stojíš ty sám terminálem (cd do toho adresáře) — stačí cd ~ a odpojení projde.
Jinak ty procesy ukonči a zkus znovu. umount -l (lazy) není řešení, jen odklad — problém tím jen schováš.
Proces nejde zabít ani přes kill -9 — co s tím?
Znamená to jednu ze dvou věcí a kill -9 naslepo nepomůže ani u jedné. Buď je to zombie (stav Z) —
proces už doběhl, jen si rodič nevyzvedl jeho návratový kód; kill neplatí, protože už neběží, takže
musíš zabrat nebo probrat rodiče (PPid ve status). Nebo je proces ve stavu D (čeká na I/O,
typicky pomalý či odumřelý disk nebo síťový mount) — jádro ho pustí, až I/O dopadne, a kill -9 na něj
neplatí. Zjisti stav v cat /proc/<PID>/status a řeš příčinu, ne symptom.
Kdy použít strace a co mi vlastně řekne?
Když proces „visí" nebo se chová divně a chceš vidět, co zrovna dělá na úrovni jádra. sudo strace -p <PID> se připojí k běžícímu procesu a vypisuje jeho syscally v reálném čase. Když výpis stojí na
read() nebo futex(), proces na něco čeká (data, zámek); když se řítí spousta openat(), něco horečně
hledá (třeba chybějící soubor). Doplní ho /proc/<PID>/ — status (stav procesu), fd/ (co má otevřeno).
Je to rozdíl mezi hádáním proč to visí a skutečným pohledem dovnitř.
