Nasazování změn v aplikaci na web provází často mnoho starostí. Nahrávání souborů je přerušeno v půlce, databázi se nepodaří obnovit ze zálohy, některé části nefungují… Nasazování oprav je ale často životně důležité. Jak si tedy tento složitý proces ulehčit?
Představme si následující běžnou situaci: spravujeme a zároveň vyvíjíme web, který kromě u nás v počítači běží ještě na serveru. Pokud provedeme změnu v lokální verzi, potřebujeme úpravu dostat i do ostrého provozu.
V nejhorším případě nahrajeme upravené soubory na server přes FTP a na webu letmo zkontrolujeme, jestli náhodou něco nepřestalo fungovat. V lepším případě využijeme nějaký nástroj pro správu verzí, například Git nebo Mercurial. V ještě lepším případě máme pro svou aplikaci poctivě napsané testy a po nahrání upravených souborů je spustíme a ověříme, zda všechno stále funguje. A v ideálním případě máme kromě ostrého serveru ještě jeden, na kterém nejdříve provedeme testy a pokud proběhnou úspěšně, překlopíme ho na ostrý.
Celý proces od úpravy kódu po aktualizaci ostrého serveru je poměrně náročný. Jak celý proces rozumně zautomatizovat? Na scénu příchází Fabric.
Fabric pomůže, kde může
Fabric je nástroj napsaný v Pythonu, pomocí kterého si lze snadno ulehčit pravidelně vykonávané série příkazů, a to i na vzdáleném serveru. Základem je přístup pomocí SSH.
To, že se jedná o nástroj v Pythonu, neznamená, že by ho nešlo použít i pro projekty v jiných jazycích. Tato ukázka bude pracovat s projektem napsaným v Djangu, spravovaným pomocí Gitu. Postup by ale zůstal podobný i v ostatních případech.
Osobně využívám služeb operačního systému Linux, na systému Windows může být postup někdy nepatrně složitější a některé systémové příkazy mohou vypadat trochu jinak.
Instalace
Pro instalaci Fabricu se předpokládá, že je na vašem počítači nainstalován a správně nastaven Python. Poté by měla instalace pomocí následujícího příkazu proběhnout bez problémů:
pip install fabric
První krůčky
Nejdůležitějším souborem bude fabfile.py, který vytvoříme v kořenovém adresáři našeho projektu. Pro začátek může být jeho obsah třeba tento:
from fabric.api import local
def test():
print 'Test jestli vse funguje'
local('uname -o')
Soubor spustíme pomocí příkazu
fab test
a pokud se vše podařilo správně, měli byste dostat výstup podobný tomuto:
Test jestli vse funguje
[localhost] local: uname -o
GNU/Linux
Done.
K samotnému skriptu jen dodám, že naimportovaná funkce local() spouští příkazy jen na lokálním počítači.
První krůčky vzdáleně
Základním bodem je spolupráce se vzdáleným serverem. Jak na ni? Nejsrozumitelnější bude opět ukázka:
from fabric.api import env, run
env.hosts = ['glor.cz']
# lze nastavit i uzivatele a port
# env.hosts = ['user@server:port']
def uptime():
run('uptime')
Po spuštění příkazem fab uptime dostaneme následující výsledek:
[glor.cz] Executing task 'uptime'
[glor.cz] run: uptime
[glor.cz] out: 11:18:59 up 10:14, 1 user, load average: 0.16, 0.29, 0.34
Done.
Disconnecting from glor.cz... done.
Serverů můžeme samozřejmě nastavit více, případně můžeme pro každou úlohu (funkci) nastavit příslušný server – více o tom v dokumentaci.
Vzdálený server jde ještě nastavit druhým způsobem – přes funkci. Toto řešení může být častokrát vhodnější. Pro každý server můžete nastavit specifické vlastnosti, například cestu, ve které chceme akce provádět:
from fabric.api import env, run
def production():
env.hosts = ['glor.cz']
env.cwd = '/home/yetty/projects/MujProjekt'
def ls():
run('ls')
Samotné spuštění pak provedeme příkazem fab production ls.
Užitečný skript na závěr
Zbývá převést teorii do praxe a pomocí mocného nástroje vytvořit ještě něco užitečného. Napišme si nejdříve příkaz, který nám bude suplovat všechny potřebné úkony k nahrání změn do centrálního repositáře.
def push():
local('./manage.py test')
local('git add -p')
local('git commit')
local('git push')
Logicky bude následovat příkaz, který změny na serveru stáhne, ozkouší a případně uvede do chodu.
from fabric.api import env, run, local, settings, abort, prefix, sudo
from fabric.contrib.console import confirm
env.hosts = ['glor.cz']
env.cwd = '/home/yetty/projects/MujProjekt'
def deploy():
with prefix('workon mujprojekt'):
run('git pull')
with settings(warn_only=True):
result = run('./manage.py test')
if result.failed and not confirm('Tests failed. Continue?'):
if confirm('Return to previous version?'):
run('git reset --hard @{1}')
abort('Aborting...')
run('./manage.py compress')
sudo('service mujprojekt restart')
Co uvedená funkce vlastně dělá? Výraz with prefix(...) přidá obsah závorky před každý příkaz. V tomto případě je požadována nástavba nad virtualenv – virtualenvwrapper. Při použití čistého virtualenvu by závorka obsahovala source cesta/k/bin/activate.
Následuje stažení změn z repositáře. Pomocí funkce settings() vypneme ukončení skriptu při chybě a výsledek testování si uložíme do proměnné. Pokud testy neproběhnou správně, informujeme uživatele a nabídneme návrat k předchozí verzi.
Pokud testy proběhly správně nebo si i přes chyby přál uživatel pokračovat, provedeme nutné operace před restartem a pak samotný restart. Já například komprimuji styly a javascriptové soubory pomocí aplikace django-compressor.
Co by se dalo do skriptu ještě přidat? Třeba migrování databáze, nebo sesbírání statických souborů. Potřebám programátora se meze nekladou…