Jednoduchý deploy skript nejen pro web v Silexu

Abych si ulehčil kopírování webů napsaných v PHP frameworku Silex na svůj server, vytvořil jsem si jednoduchý skript, který zařídí vše potřebné. Využívá rsync, ssh a nezávisí na žádných dalších balíčcích.

Reklama

Od chvíle, co si hraju se Symfony 2 a Silexem, koketuju rovněž s nejrůznějšími nástroji určenými pro nakopírování hotové aplikace na produkční server. Řešení se nabízejí mraky, od Gitu přes specializované skripty až po různě zaintegrované balíčky, které závisejí na Composeru a PHP knihovnách v projektu. Viz článek o nástroji Magallanes.

Podobně jsem se setkal a vyzkoušel řadu deploy nástrojů vyžadujících konfiguraci psanou v Ruby nebo Pythonu.

Přestože mnoho nástrojů, které jsem vyzkoušel, jsou robustní řešení, žádný mi moc nevyhovoval pro potřebu rychlého překopírování a nějakých vzdálených úprav u malého webu. Nechci nic přidávat do projektu jako takového, nechci se učit Ruby a nechci špinit PHP aplikaci nějakou konfigurací pro věc psanou v Pythonu.

Navíc se nechci přizpůsobovat nějakému univerzálnímu nástroji a vytvářet složitou konfiguraci jen proto, aby udělal zdánlivě jednoduchou věc, kterou potřebuji dle svých představ.

Nakonec jsem tedy využil toho, že v OS X je Bash, ve kterém si mohu vytvořit potřebný deploy skript zcela podle sebe a nepotřebuji k tomu přítomnost žádných dalších aplikací nebo knihoven v projektu.

Deploy skript pro Silex v shellu Bash

Jako základ jsem použil skript uvedený v návodu od Michaela Birche. Na začátku specifikuju lokální složku s projektem. Následuje ji cesta na vzdáleném serveru, ke kterému se má skript připojit. Další dva záznamy specifikují uživatelské jméno pro připojení na vzdálený server a adresu vzdáleného serveru.

Skript po spuštění zobrazí v terminálu datum a čas začátku kopírování a informaci o tom, co bude provádět. Poté je volán příkaz rsync s příslušnými atributy, který zajistí synchronizaci vzdálené složky s lokální kopií.

Jelikož v Silexu využívám cacheování, doplnil jsem příkaz pro smazání složky s cache na vzdáleném serveru.

Poté od sebe odečtu datum a čas začátku a konce operace a zobrazím celkovou délku jejího trvání. Celý záznam je rovněž umístěn do textového souboru, který může posloužit pro nějakou pozdější analýzu.

Volání rsync využívá seznam ze souboru rsync_exclude.txt, ve kterém mám uvedeny soubory a složky, které chci ze synchronizace vyloučit.

Tip: Návod pro Připojení k linuxovému serveru z Windows bez hesla.

Celý skript je zde:

#!/bin/bash
# create a file deploy_log.txt in LOCAL_DIR
# create a file rsync_exclude.txt in LOCAL_DIR
# configure the following
LOCAL_DIR="/Users/janpolzer/Sites/polzer/"
REMOTE_DIR="/var/www/honza/polzer.cz"
REMOTE_USER="honza"
REMOTE_IP="192.168.0.10"

start=`date +%s`

((
echo -e "\n"
echo -e "-----------------------------------\n"
echo "$(date)"
echo -e "\n"
echo 'rsync with production dir on web server'
rsync -acvzh  --exclude-from ${LOCAL_DIR}'rsync_exclude.txt' ${LOCAL_DIR} ${REMOTE_USER}@${REMOTE_IP}:${REMOTE_DIR}
echo 'clearing the cache'
ssh ${REMOTE_USER}@${REMOTE_IP} "rm -r ${REMOTE_DIR}/public/cache/*"
end=`date +%s`
runtime=$((end-start))
echo "Finished after $runtime seconds."
) 2>&1) | tee -a ${LOCAL_DIR}'deploy_log.txt'

Toto řešení mi přijde maximálně jednoduché a konfigurovatelné a nepotřebuji pro něj nic speciálního. Bash je prakticky na každém stroji s Linuxem i OS X a znalost skriptování patří k základní výbavě práce s Linuxem.

Výstup deploy skriptu v okně terminálu:

Deploy skript

Jednoduše lze přidat také volání uglifyjs nebo třeba nějakého CSS preprocesoru, jak ukazuje původní návrh skriptu v odkazovaném článku. Do budoucna jím nahradím zřejmě i deploy skripty u aplikací v Symfony 2, pro které zatím využívám hpatoio/DeployBundle.

Reklama

Komentáře

Aby to nebylo spíš naopak.

Specializované nástroje řeší spousty dalších věcí - migraci databáze, konzistenci aplikace atd. Proto je lepší neobjevovat znovu kolo.

Navrhované řešení je sice jednoduché, ale co uživatelé, kteří používají aplikaci v okamžiku deploye? Ti mají smůlu?

jeste by me zajimalo jak autor dela rollback, kdyz je potreba nasadit predchozi verzi.

Ale tak samozřejmě toto není na podobnou věc stavěné. Takže odpověď je nijak. Bokem si appku dávám do Gitu. Já tu o jednoduchém deploy skriptu k webu bez databáze a vy sem taháte migraci databáze.

Majitel Maxiorla. Nabízím mimo jiné placené poradenství pro Drupal. Jsem i na Twitteru.

A k čemu mi je milion různých skriptů, rozdělených podle složitosti projektu? Navíc když z jednoduchého projektu se snadno stane složitý.

Když můžu mít jedno Capistrano s triviálním konfigurákem a ať jde o projekt o jaký chce, jen dám "cap deploy" a hotovo.

Proč milion skriptů? Už každého jeden na míru. Spouštěný vždy stejným příkazem, protože to mám stejně pojmenováno. Z tohoto pohledu je to úplně stejná obsluha jako Capistrano.

Samozřejmě od určité velikosti projektu je výhodnější specializovaný deploy nástroj, protože je rychlejší mu napsat konfiguraci, než si vytvořit skript v bashi. Ale o tom tu nemluvím.

A stejně tak to nikomu nevnucuji, takže se nečertěte, Capistrano tu nikdo nikomu nebere. V článku jenom píšu o tom, že mi prostě pro malý projekt nevyhovuje a proč. Kolik lidí, tolik potřeb.

Majitel Maxiorla. Nabízím mimo jiné placené poradenství pro Drupal. Jsem i na Twitteru.

Než rsyncovat bordel, který můžu mít u sebe (editované nebo dokonce necommitnuté soubory, dočasné soubory), tak raději nasazuji z gitu. Tím se dá přesně dosledovat, co bylo nasazeno a můžu si být jistý, že tam není nic navíc, co jsem zapomněl excludnout nebo smazat.

Volba --checksum/-c je zbytečná, kontrola obsahu úplně všech souborů jen zdržuje. Naopak mi chybí mazání souborů, které jsou v cílovém adresáři, ale nejsou ve zdrojovém.

Díky za tip, vylepším to.

Majitel Maxiorla. Nabízím mimo jiné placené poradenství pro Drupal. Jsem i na Twitteru.

Ale zase snaha o automatizaci se cení, přeci to tam nebudeme ládovat Total Commanderem :)

Jasně. Ale zase ta jistota, že se zkopírovalo přesně to, co mělo, případně jistota, kdo to vlastně při větším počtu operací pokazil, je u ručního kopírování taky výhoda ;-)

Majitel Maxiorla. Nabízím mimo jiné placené poradenství pro Drupal. Jsem i na Twitteru.

měl bych k tomu pár doporučení.

První řádek bych nahradil "#!/usr/bin/env bash", je to více přenosné než čekat bash v /bin/bash

Za první řádek přidej:
set -o errexit #ukonci skript, pokud nejaky prikaz selze
set -o nounset #ukonci skript, pokud mas preklep v promennych a pouzivas jeste neinicializovanou

Na řádku 12 je zbytečné jedno obalení závorkami, stačí pouze jeden subshell, pak na řádku 24 stačí také odebrat tu druhou závorku

Přepínače do rsync rozepiš na jejich dlouhé tvary, ať je pak jasné, že rsync -a je rsync --archive atd.

Lepší řešení je nejprve rsyncem nakopírovat data do tmp adresáře a podé buď simlinkovat nebo rsyncovat lokální. Během rsyncu je totiž web nekonzistentní a pokud to děláš ze slabého připojení, může se ti to rozbít...

Tenhle skript se dá navázat na git push a bude se deployovat při každém push, pro jednodušší weby to opravdu stačí a není potřeba rešit složité sync nástroje.

Super, díky za tipy. Rozepsání rsync asi dělat nebudu, přijde mi to zbytečné. Nebo má jiný přínos než lepší orientaci?

Jinak, ta konzistence může být u navštěvovanějšího webu problém, to je pravda. V daném případě jsem to neřešil, ale do budoucna to asi udělám tak, že se index.php nahradí dočasně nějakým hlášením o úpravě webu a pak se zase vrátí zpět. Nebo je to špatný nápad?

Git je v plánu, zároveň jsem ještě doplnil i generátor sitemapy. To bohužel již přes skript v Pythonu, který mám bokem dané aplikace. Našel jsem sice skript pro bash, který to umí taky s využitím sed a lynx, nicméně nefungoval a úprava už byla nad mé schopnosti.

Majitel Maxiorla. Nabízím mimo jiné placené poradenství pro Drupal. Jsem i na Twitteru.

ano, rozepsání je jen kvůli orientaci, když k takovému kódu příjdeš po roce, netušíš co dělá a musíš do nápovědy, ale je to marginální.

Hlášení o úpravě webu bych dělal jen u delšího výpadku, v případě rsyncu je i u velkého webu problém na max. pár desítek vteřin, u malého si toho nikdo nevšimne. Deploy bez výpadku je v php plný pastí, vždy podle projektu/frameworku jsem provozoval jiné řešení.

Nejlehčí řešení je rsyncovat projekt někam jinám např. do adresáře podle datumu /var/www/deploy/polzer.cz/$(date +%Y-%m-%d). Získáš s tím zároveň i jednoduchou možnost rollbacku. Máš několik možností:

1. použít symlinky
2. použít symlinky a přes htaccess podvrhnout adresář
3. změnit konfiguraci v apache/nginx a načítat z jiného adresáře

Pasti, na které narazíš:
- php-fpm si zjistí symlinky při startu a poté změny ignoruje, nutný restart/reload
- php opcache si bude pořád pamatovat staré soubory a je nutné jí reloadovat (pozor pro cli a pro web je samostatná)
- různé cache ve frameworcích/aplikacích používají absolutní cesty v filesystému, jako např. Nette, Wordpress. Možnost použít symlinky to trochu komplikuje

Lze provozovat i složitější řešení, přes např. apache vhost si odzkoušet, jestli vůbec nová verze funguje (alespoň, že lze načíst homepage) a poté prohodit s produkční verzí.

Po deseti letech jsem se ale dostal ke clusteru a každý web běží minimálně ve dvou instancí a deploy bez výpadků je tak jednodušší.

Přidat komentář