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ř.
