PM2 je správce procesů pro Node.js: malý démon na pozadí, který spustí tvoji aplikaci, restartuje ji, když spadne, ukládá její výstup do logů a po restartu stroje všechno znovu nahodí. Při správném použití se skládá ze čtyř věcí - souboru ecosystem.config.js v repozitáři, příkazu pm2 start nad tímto souborem, modulu pm2-logrotate, aby logy nezaplnily disk, a dvojice pm2 save a pm2 startup, díky které si stroj pamatuje, co má spouštět. Většina problémů s PM2 vzniká tím, že se jedna ze čtyř věcí vynechá, nebo tím, že se PM2 spustí tam, kde už tvůj proces hlídá někdo jiný.
Právě to rozhoduje o tom, jestli ho vůbec potřebuješ. Na běžném virtuálním nebo dedikovaném serveru tvoji aplikaci nic nerestartuje, dokud to sám nenastavíš, a PM2 je rozumná volba. V kontejneru na hostingovém panelu je dohlížitelem už sama platforma a druhý dohlížitel jí crashe zakrývá - tento případ podrobně rozebírá článek PM2 vs hostingový panel, takže ho tu neopakujeme. Tento průvodce počítá se serverem, který si provozuješ sám, a ukazuje PM2 tak, jak se tam má nastavit.
Co je PM2 a jak funguje#
PM2 má dvě části. Démon je dlouho běžící proces Node, kterému tvoje aplikace patří: spouští je, hlídá, restartuje a zapisuje jejich standardní výstup i standardní chybový výstup do souborů. CLI - příkaz pm2 - je klient, který s démonem komunikuje přes socket. Když zadáš pm2 start, CLI nastartuje démona, pokud ještě neběží, požádá ho o spuštění aplikace, vypíše tabulku a skončí. Aplikace běží dál, protože běží démon.
Vše, co PM2 ví, je uloženo v PM2_HOME, což je ve výchozím stavu ~/.pm2 uživatele, který PM2 spustil. V tomto adresáři jsou logy (~/.pm2/logs), soubory PID, vlastní log démona (~/.pm2/pm2.log) a uložený seznam procesů (~/.pm2/dump.pm2). Důležitý důsledek: démon je vázaný na uživatele. Pokud aplikaci spustíš jako deploy a později zadáš sudo pm2 ls, ptáš se démona uživatele root, který o ní nikdy neslyšel, a dostaneš prázdnou tabulku. Vyber jednoho uživatele, nejlépe neprivilegovaného, který vlastní adresář aplikace, a nikdy je nemíchej.
Instalace je jediný globální balíček:
$ npm install -g pm2$ pm2 --versionPříkazy a konfigurační klíče PM2 jsou stabilní už léta, ale výchozí hodnoty se mezi hlavními verzemi občas posunou. Pokud je pro tebe nějaké číslo v tomto průvodci podstatné, ověř si ho podle pm2 --version a oficiální dokumentace dané verze.
Spuštění aplikace: pm2 start, názvy a interpretery#
Nejjednodušší forma bere skript a název. Název vždy zadávej; výchozí je název souboru a čtyři aplikace, které se všechny jmenují index, se spravují nepříjemně.
$ pm2 start dist/server.js --name api$ pm2 start dist/server.js --name api -- --port 3000 # args after -- go to your app$ pm2 start npm --name web -- start # runs "npm start"$ pm2 lspm2 ls (také pm2 list nebo pm2 status) vypíše jeden řádek na proces: id, název, režim (fork nebo cluster), počítadlo restartů, stav, CPU a paměť. Sloupec, který sleduj především, je počítadlo restartů. Číslo, které roste, i když zrovna nenasazuješ, znamená, že aplikace padá a PM2 ji tiše zase zvedá.
Spouštění přes npm start funguje, ale mezi PM2 a tvoji aplikaci staví npm: další proces, který zabírá paměť, a další mezičlánek pro signály při vypnutí. Pokud to jde, je lepší nasměrovat PM2 přímo na skutečný vstupní soubor.
PM2 se neomezuje na JavaScript. Interpreter vybírá podle přípony souboru - .py dostane python, .sh dostane bash, .rb dostane ruby, .php dostane php - a pomocí --interpreter ho můžeš nastavit výslovně. Pro zkompilovaný binární soubor nebo cokoli, co je samo spustitelné, je interpreter none:
$ pm2 start worker.py --name worker --interpreter python3$ pm2 start ./bin/server --name go-api --interpreter none$ pm2 start /srv/app/.venv/bin/gunicorn --name web --interpreter none \ -- app:app --bind 127.0.0.1:8000 --workers 2Dvě věci, které je třeba vědět o Pythonu pod PM2. Za prvé, mnoho současných distribucí dodává python3 a žádný python, takže výchozí interpreter podle přípony skončí chybou, že interpreter nebyl nalezen; nastav interpreter a nejlépe ho nasměruj na vlastní binárku virtuálního prostředí, aby byly v cestě správné balíčky. Za druhé, Python ukládá standardní výstup do vyrovnávací paměti, když není připojen k terminálu, což pod PM2 znamená, že se řádky logu objevují po dávkách, nebo vůbec, dokud proces neskončí. Nastav v prostředí PYTHONUNBUFFERED=1 nebo spusť s -u. Samotné vytvoření prostředí popisuje Python requirements a virtualenvy a server před ním článek nasazení FastAPI nebo Flasku.
Soubor ecosystem#
Parametry příkazové řádky žijí v něčí historii shellu. Soubor ecosystem žije v repozitáři, prochází revizí a na každém stroji spouští aplikaci stejně. pm2 init simple vytvoří kostru; realistický soubor vypadá takto:
module.exports = { apps: [ { name: "api", script: "dist/server.js", cwd: "/srv/api", instances: 2, exec_mode: "cluster", max_memory_restart: "400M", node_args: "--max-old-space-size=320", watch: false, time: true, kill_timeout: 10000, env: { NODE_ENV: "development", PORT: 3000 }, env_production: { NODE_ENV: "production", PORT: 3000 }, }, { name: "worker", script: "worker.py", cwd: "/srv/api", interpreter: "/srv/api/.venv/bin/python", exec_mode: "fork", env: { PYTHONUNBUFFERED: "1" }, }, ],};$ pm2 start ecosystem.config.js --env production$ pm2 reload ecosystem.config.js --env production # after a deploy$ pm2 start ecosystem.config.js --only worker # one app from the fileKlíče, na kterých záleží, a co ve skutečnosti dělají:
| Klíč | Co dělá |
|---|---|
name | Označení pro všechny ostatní příkazy |
script | Vstupní soubor nebo binárka, relativně k cwd |
args | Argumenty předané tvé aplikaci |
cwd | Pracovní adresář; nastav ho výslovně |
interpreter | Výchozí je node; cesta, nebo none |
node_args | Parametry pro samotný Node, například velikost heapu |
instances | Kolik procesů; max znamená jeden na CPU |
exec_mode | fork (výchozí) nebo cluster |
env / env_<name> | Prostředí, vybírá se pomocí --env <name> |
| Klíč | Co dělá |
|---|---|
max_memory_restart | Restartuje proces nad touto pamětí, např. 400M |
autorestart | Výchozí je true; false pro jednorázové úlohy |
max_restarts | Počet nestabilních restartů po sobě, než se to vzdá |
min_uptime | Jak dlouho musí proces žít, aby se počítal jako spuštěný |
restart_delay | Pevná pauza před každým restartem, v ms |
exp_backoff_restart_delay | Rostoucí pauza mezi restarty, v ms |
kill_timeout | Čekání po stop signálu před SIGKILL, v ms |
cron_restart | Restart podle výrazu cron |
time | Před každý řádek logu přidá časové razítko |
Několik z nich si zaslouží víc než buňku v tabulce.
`env` a `env_production`. Blok env se uplatní vždy; --env production přes něj přimíchá env_production. To je užitečné, ale není to úložiště tajemství - soubor ecosystem je v repozitáři. Přihlašovací údaje drž v souboru mimo repozitář s přísnými oprávněními a načítej je na začátku souboru ecosystem (například pomocí require("dotenv").config({ path: "/etc/api/api.env" })), nebo ať si je aplikace čte sama. Proč na tomto rozdílu záleží, vysvětluje článek proměnné prostředí a tajemství.
`max_memory_restart`. PM2 kontroluje paměť v intervalech, ne při každé alokaci, takže jde spíš o úklid po pomalých únicích paměti než o pevný strop. Navíc proces restartuje náhle, uprostřed požadavku. Drž hodnotu nad běžnou špičkou spotřeby a přidej pod ni limit heapu V8, aby Node selhal způsobem, který si můžeš přečíst, dřív než zasáhne PM2 nebo jádro - výpočty včetně toho, proč má každý worker v clusteru vlastní heap, najdeš v článku limity paměti v Node vysvětleně.
`max_restarts` a `min_uptime`. Proces, který skončí před uplynutím min_uptime, se počítá jako nestabilní; po max_restarts nestabilních startech za sebou to PM2 vzdá a označí ho jako errored. Zdokumentované výchozí hodnoty jsou 16 restartů a 1000 ms. Pokud tvoje aplikace padá až po několika sekundách - třeba když čeká na spojení s databází - nikdy se nepočítá jako nestabilní a PM2 ji restartuje donekonečna. Lepší nástroj je exp_backoff_restart_delay: 100: pauza roste s každým pádem a vynuluje se, jakmile aplikace chvíli vydrží, takže mrtvá databáze nevyústí v nekonečnou smyčku.
`kill_timeout`. Při zastavení PM2 pošle SIGINT a počká tuto dobu, než pošle SIGKILL. Výchozích 1600 ms je méně než pomalý požadavek. Pokud tvoje aplikace při vypínání dokončuje spojení, zvyš hodnotu tak, aby pokryla tvůj nejdelší požadavek, a ujisti se, že handler naslouchá SIGINT stejně jako SIGTERM. Stranu aplikace popisuje článek graceful shutdown a health checky.
Cluster mode a instance#
exec_mode: "cluster" používá modul cluster z Node: PM2 spustí několik kopií tvé aplikace, které sdílejí jeden naslouchající port, a příchozí spojení se mezi ně rozdělují. Je to jediný způsob, jak může jedna aplikace v Node využít víc než jedno jádro CPU, aniž bys psal forkování sám, a právě to umožňuje reloady bez výpadku.
Tři fakta pro správná očekávání:
- Cluster mode je jen pro Node. Proces v Pythonu, Go nebo Bunu takhle port sdílet nemůže. Pro ně
instancesnad 1 ve fork režimu spustí několik kopií, které se všechny snaží navázat na stejný port, a všechny kromě první selžou. Použij vlastní workery aplikačního serveru ---workersu Gunicornu,--workersu Uvicornu - a PM2 nech na jedné instanci. - `instances: "max"` počítá logické CPU stroje. Na VDS je to počet tvých vCPU, což je v pořádku.
0znamená totéž a-1znamená všechna kromě jednoho, takže jádro zůstane databázi na jediném stroji. - Každá instance je plná kopie tvé aplikace. Paměť na instanci se násobí, stav v paměti se nesdílí a vše, co je v aplikaci naplánované, běží jednou na každou instanci. Kompromisy - sticky sessions, úlohy spuštěné čtyřikrát, dimenzování workerů podle jader, která opravdu máš - jsou popsané v sekci o clusteru v článku PM2 vs hostingový panel.
Zvětšení nebo zmenšení běžícího clusteru nevyžaduje restart:
$ pm2 scale api 4$ pm2 scale api +1Změna platí do dalšího spuštění ze souboru ecosystem, kde stále stojí instances: 2. Pokud to myslíš vážně, uprav soubor.
Restart, reload, stop a delete#
Tyto čtyři příkazy se v PM2 pletou nejčastěji a rozdíl mezi nimi není kosmetický.
| Příkaz | Co se stane |
|---|---|
pm2 restart api | Zabije všechny instance a pak je spustí znovu |
pm2 reload api | Cluster mode: vyměňuje instance jednu po druhé |
pm2 stop api | Zastaví ji; zůstane v seznamu |
pm2 delete api | Zastaví ji a odstraní ze seznamu |
restart má mezeru: na chvíli nic nenaslouchá a požadavky v tu chvíli selžou. reload v cluster režimu spustí novou instanci, počká, až je připravená, zastaví jednu starou a opakuje to, dokud nejsou všechny instance nové - vždy je tedy něco, co přijímá spojení. Ve fork režimu není co postupně vyměňovat, takže reload jednoduše přejde na restart.
„Připravená“ znamená ve výchozím stavu to, že nová instance začala naslouchat. Pokud tvoje aplikace potřebuje před obsluhou požadavků nahřát cache nebo otevřít pool databázových spojení, řekni PM2, aby počkalo na výslovný signál:
wait_ready: true,listen_timeout: 10000,server.listen(process.env.PORT, () => { if (process.send) process.send("ready");});Pokud signál nedorazí během listen_timeout, PM2 stejně pokračuje, takže rozbité vydání pořád nahradí funkční. Reload je pohodlí, ne health check; co dalšího musí platit, aby bylo nasazení opravdu bez mezery, popisuje článek nasazení bez výpadku na malém serveru.
Ještě jedna past. PM2 zachytí prostředí při prvním spuštění procesu a znovu ho používá. Když změníš proměnnou prostředí a spustíš pm2 restart api, zůstane stará hodnota. Přidej --update-env nebo restartuj ze souboru ecosystem:
$ pm2 reload ecosystem.config.js --env production --update-envA rozdíl mezi stop a delete je důležitý kvůli další sekci: zastavený proces je pořád v seznamu a uloží se jako zastavený; smazaný zmizí jen do chvíle, než obnovíš starý dump, který ho ještě obsahuje.
Logy a pm2-logrotate#
Každý proces má dva soubory: ~/.pm2/logs/<name>-out.log pro standardní výstup a ~/.pm2/logs/<name>-error.log pro standardní chybový výstup. V cluster režimu zapisuje každá instance vlastní dvojici s id v názvu, pokud nenastavíš merge_logs: true.
$ pm2 logs # all apps, streaming$ pm2 logs api --lines 200 # last 200 lines, then stream$ pm2 logs api --err # error stream only$ pm2 flush api # empty this app's log filesNastav v souboru ecosystem time: true, pokud tvůj logger nezapisuje časová razítka sám. Bez nich je soubor logu seznam událostí, o kterých nevíš, kdy se staly.
Hned po instalaci tyto soubory rostou donekonečna. Upovídaná aplikace, která zapisuje pár stovek kilobajtů za minutu, zaplní malý disk za několik týdnů a plný disk s sebou stáhne i databázi. Řešením je modul PM2:
$ pm2 install pm2-logrotate$ pm2 set pm2-logrotate:max_size 20M$ pm2 set pm2-logrotate:retain 14$ pm2 set pm2-logrotate:compress true$ pm2 conf pm2-logrotate| Nastavení | Výchozí | Co dělá |
|---|---|---|
max_size | 10M | Rotuje soubor, jakmile tuto velikost překročí |
retain | 30 | Kolik rotovaných souborů se ponechá na jeden log |
compress | false | Zkomprimuje rotované soubory pomocí gzip |
rotateInterval | 0 0 * * * | Rotuje i podle tohoto cronu, ve výchozím stavu denně |
Modul běží jako vlastní proces uvnitř démona a objeví se v pm2 ls, což je v pořádku. Nastavení jsou vázaná na uživatele, stejně jako všechno v PM2. Pokud bys raději nechal logy v systémovém journalu, systemd to zvládne bez modulu; o tom, co by v nich vůbec mělo být, je článek logy, které stojí za to uchovat.
pm2 save a pm2 startup: přežití restartu stroje#
PM2 se při startu stroje samo nespustí. Napravují to dva příkazy a každý dělá jinou práci.
pm2 startup vygeneruje jednotku systemd, která při startu stroje spustí démona PM2 pro tvého uživatele. Spuštěný jako běžný uživatel nic neinstaluje; vypíše příkaz, který by to udělal, protože instalace jednotky vyžaduje root:
$ pm2 startup[PM2] To setup the Startup Script, copy/paste the following command:sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u deploy --hp /home/deployZkopíruj tento řádek přesně a spusť ho. Vytvoří a povolí jednotku s názvem pm2-deploy.service (pro uživatele deploy). Cesty v něm závisejí na tom, kde máš na stroji nainstalovaný Node, takže žádný řádek nekopíruj z návodu na internetu.
pm2 save zapíše aktuální seznam procesů do ~/.pm2/dump.pm2. Při startu stroje jednotka spustí démona a provede pm2 resurrect, který znovu spustí vše, co v tom souboru bylo. Postup je tedy tento:
- Spusť vše, co má běžet:
pm2 start ecosystem.config.js --env production. - Zkontroluj to:
pm2 ls, všeonline, počítadla restartů na nule. - Ulož to:
pm2 save. - Jednorázově nainstaluj spouštěcí jednotku:
pm2 startupa pak spusť vypsaný řádek sesudo. - Otestuj to:
sudo reboot, přihlas se zpět,pm2 ls.
Krok 5 lidé vynechávají nejčastěji, a restart stroje není vhodná chvíle zjišťovat, že se seznam nikdy neuložil.
Pokud se změní cesta k Node - například novou verzí přes nvm - jednotka dál ukazuje na starou binárku. Spusť dvojici znovu: pm2 unstartup systemd, pak pm2 startup a jím vypsaný příkaz, pak pm2 save. Po aktualizaci samotného balíčku PM2 přes npm install -g pm2 spusť pm2 update, aby se běžící démon nahradil novou verzí a nezůstal na staré.
Jednotku můžeš zkontrolovat jako každou jinou: systemctl status pm2-deploy. Když už stejně čteš výstup systemd, stojí za to vědět, že aplikaci můžeš provozovat jako vlastní jednotku úplně bez PM2 - popisuje to článek služby systemd pro tvoje aplikace a pro jediný proces je to štíhlejší varianta.
Sledování: pm2 monit, describe a počítadlo restartů#
$ pm2 monit # terminal dashboard: CPU, memory, logs per process$ pm2 describe api # full detail: paths, restarts, uptime, env$ pm2 reset api # zero the restart counterpm2 monit je živý pohled v terminálu se seznamem procesů, CPU a pamětí každého procesu a panelem s logy. Hodí se při nasazení nebo zátěžovém testu a ve čtyři ráno je k ničemu, protože cokoli ukazuje, jen když se někdo dívá. pm2 describe je příkaz pro rozbor po události: vypíše cestu ke skriptu, interpreter, umístění souborů logu, uptime, počet restartů a nestabilní restarty.
Počítadlo restartů je nejlevnější alert, jaký máš. Po záměrném nasazení ho vynuluj (pm2 reset api) a jakékoli nenulové číslo potom je pád, který jsi nezpůsobil. Pokud se na něj nikdo nebude dívat, stačí malá úloha v cronu, která spustí pm2 jlist (vypíše seznam procesů jako JSON) a ozve se, když se změní restart_time nebo status; je to tucet řádků skriptu a smyčky pádů zachytí dávno před uživateli. PM2 má také placený hostovaný dashboard; nic v tomto průvodci ho nepotřebuje.
Časté chyby#
Watch mode v produkci. watch: true restartuje aplikaci při každé změně souboru v jejím adresáři. V produkci to znamená, že každý zápis logu uvnitř projektu, každý upload a každý soubor cache spustí restart a restart zapíše řádek logu, který spustí další. Mimo vývoj drž watch: false. Pokud ho lokálně používáš, přidej ignore_watch: ["node_modules", "logs", "uploads"].
Dva démoni. Jeden spuštěný jako root, druhý jako tvůj uživatel, každý s polovinou aplikací. Spusť jednou pm2 ls a jednou sudo pm2 ls a ujisti se, že jen jeden z nich něco obsahuje. Potom z toho druhého smaž a ukonči ho pomocí pm2 kill.
Zapomenuté `pm2 save`. Všechno funguje až do prvního restartu stroje. Udělej z ukládání součást nasazovacího skriptu.
Dva dohlížitelé. PM2 v kontejneru, jehož platforma ho už restartuje, nebo PM2 spuštěné z jednotky systemd, kterou sis napsal sám, zatímco pm2 startup nainstaloval také jednu. Na jeden proces vol jednoho dohlížitele.
`instances: "max"` se stavovým kódem. Relace držené v paměti, WebSockety evidované v Map, plánovač uvnitř aplikace. Všechno se rozbije nebo znásobí, jakmile existuje druhá instance.
Logy Pythonu, které se neobjeví. Nebufferovaný výstup je ve výchozím stavu vypnutý. PYTHONUNBUFFERED=1.
Argumenty na špatném místě. V pm2 start server.js --name api -- --port 3000 jde všechno za -- do tvé aplikace. Parametry Node jako --max-old-space-size patří do node_args nebo --node-args, ne za dvojitou pomlčku, jinak se tiše ignorují.
Brát `max_memory_restart` jako opravu. Únik paměti skrývá tím, že proces restartuje podle rozvrhu, který sis nevybral. Najdi ten únik.
FAQ#
Je PM2 zdarma?
Ano. Správce procesů je open source a vše v tomto průvodci používá jen bezplatné CLI a bezplatný modul pm2-logrotate. Placená je jen volitelná hostovaná monitorovací nástěnka, kterou k provozu PM2 nepotřebuješ.
Mám použít PM2, nebo systemd?
Pro jeden proces na serveru je systemd už nainstalovaný a zvládne to bez dalšího démona. PM2 si své místo zaslouží, když chceš cluster mode v Node s postupnými reloady, nebo několik malých aplikací spravovaných jedním příkazem. Obojí je v pořádku; provozovat oba pro stejnou aplikaci v pořádku není.
Umí PM2 spouštět Python, Go nebo shellový skript?
Ano. Nastav interpreter na binárku Pythonu (nejlépe uvnitř virtuálního prostředí), na none pro zkompilovanou binárku, nebo nech soubory .sh použít výchozí bash. Cluster mode a pm2 reload bez výpadku fungují jen pro Node, takže ostatní runtime dostanou jednu instanci a vlastní model workerů.
Kde PM2 ukládá moje logy?
V ~/.pm2/logs uživatele, který aplikaci spustil, jako <name>-out.log a <name>-error.log. pm2 describe <name> vypíše přesné cesty. Nainstaluj pm2-logrotate dřív, než se z nich stane problém s diskem.
Proč se moje aplikace po restartu stroje nevrátila?
Buď se nikdy nenainstaloval pm2 startup, nebo se po spuštění aplikace neprovedlo pm2 save, nebo se uložilo pod jiným uživatelem. Zkontroluj systemctl status pm2-<user>, pak pm2 ls jako tento uživatel, potom aplikaci spusť, ulož a stroj znovu restartuj.
Mám používat PM2 na hostingovém panelu?
Obvykle ne. Panel proces už restartuje, uchovává jeho výstup a sleduje pády a PM2 mezi tím mu je zakrývá. Spusť aplikaci raději přímo v popředí.


