Capistrano è un tool molto potente che facilita molto la vita, spesso tediosa, del sistemista, eseguendo al suo posto alcuni task (operazioni più o meno semplici) in modo automatico.
Il compito per cui Capistrano si è subito distinto è il deployment delle applicazioni Rails, ovvero la sua "messa in produzione". Ma la sua potenza non si ferma certo al deployment, infatti nel corso della sua storia si è sempre più generalizzato, fino ad eseguire i compiti più disparati, come ad esempio, il monitoraggio di sistemi, la migrazione di intere piattaforme hosting da apache a lighttpd... tanto per rendere l'idea.
In questo articolo esaminiamo alcune principali caratteristiche di Capistrano, per poi fare un semplice esempio di integrazione con Rails.
Prerequisiti e installazione
Per lavorare con Capistrano e seguire gli esempi di questo articolo occorrerà avere installato:
- Ruby (1.8 o superiori)
- Rubygems (non è indispensabile ma è fortemente consigliato)
- un server POSIX compatibile (GNU/Linux, FreeBSD, etc) con accesso SSH. Se si utilizzano delle password per accedere ai vari server, queste devono essere tutte uguali. È consigliabile usare chiavi pubbliche per aggirare il problema e per sentirsi un po' più sicuri.
Per sfruttare al meglio Capistrano è consigliabile avere un minimo di conoscenza di Ruby, il linguaggio con il quale è scritto, e dell'ambiente dei sistemi UNIX-like
Detto questo possiamo procedere all'installazione:
# gem install Capistrano
Nota: la versione 1.8.6 di Ruby ha dei bug sull'implementazione dei thread, che possono creare problemi a Capistrano. In questo caso è lo stesso programma che ci suggerisce di usare gem install fastthread
.
Una volta installato tutto l'occorrente passiamo alle caratteristiche.
Capfile
Capistrano (similmente a Make e Rake) utilizza un file di configurazione che definisce tutti i task destinati ai vari server, e in generale tutta la sua logica. Questo file è chiamato Capfile, ed è il file che Capistrano cerca nella directory principale del progetto, per poi caricarlo.
Il Capfile è un tipico esempio di DSL ovvero uno pseudo-linguaggio studiato appositamente per uno scopo, in questo caso quello di eseguire task remoti, con il vantaggio di essere molto semplice da usare. Questo viene realizzato grazie alla flessibilità di Ruby che permette facilmente di creare DSL.
Esempio di Capfile
desc "stampa il nomehost e la versione del kernel" task :informazioni, :host => "server.net" do run "hostname ; uname -a" end
Con il comando desc
assegnamo una descrizione al task, passando come argomento una string. Questa descrizione la ritroveremo ogni volta che visualizzeremo la lista dei task, ad esempio. Per richiedere questa lista dei task lanciamo il comando cap -T
.
# cap -T cap informazioni # stampa il nome host e la versione del kernel cap invoke # Invoke a single command on the remote servers cap shell # Begin an interactive Capistrano session
È tedioso specificare per ogni azione il (oppure i) server di destinazione, per questo è consigliabile assegnare un "ruolo" a determinati host, magari facendo in modo di passare sempre da un gateway.
set :gateway, "server-pubblico.net" role :db, "db.server-interno.net" role :web, "webapp.server-interno.net" task :rimuovi_tmp, :roles => :tmp do run "rm -r /tmp/*" end task :web_restart, :roles => :web do run "apachectl -k restart" end
In questo modo Capistrano ci collegherà prima al gateway (server-pubblico.net
) e per poi passare ai server interni (db
, webapp
). Questo è molto comodo se si ha una rete di server interni accessibili soltanto attraverso un server pubblico. Proviamo:
# cap web_restart * executing 'web_restart' * executing "apachectl -k restart" servers: ["webapp.server-interno.net"] starting connection to gateway 'server-pubblico.net' Password: gateway connection established * establishing connection to 'webapp.server-interno.net' via gateway connected: 'webapp.server-interno.net' (via gateway) [webapp.server-interno.org] executing command ** [out :: webapp.server-interno.net] apache stopped ** [out :: webapp.server-interno.net] apache started command finished
Nel Capfile è possibile assegnare valori alle variabili in diversi modi, eccone alcuni:
Assegnamento statico
set :variabile, "pippo"
Assegnamento dinamico
set(:variabile) do Capistrano::CLI.ui.ask "scrivi qui il valore della variabile: " end
Assegnamento da riga di comando attraverso il flag '-s'
cap -s variabile=pippo nometask
Abbiamo analizzato brevemente le principali caratteristiche di questo tool, passiamo al suo utilizzo con Rails.
Capistrano e Rails
Innanzitutto bisogna creare il Capfile, per questo compito ci viene in aiuto con il comando capify (incluso in Capistrano)
# capify nomeproj [add] writing 'nomeproj/Capfile' [add] writing 'nomeproj/config/deploy.rb' [done] capified!
Il Capfile generato non fa altro che caricare il file deploy.rb
ed "informare" Capistrano che si sta lavorando con un applicazione Rails, e quindi di caricare dei task di default.
Alcuni task
[kalos@eloisa] > cd nomeproj ; cap -T cap deploy # Deploys your project. cap deploy:check # Test deployment dependencies. cap deploy:cleanup # Clean up old releases. [...]
I task predefiniti su Rails sono tutti creati partendo dal namespace "deploy", che non è altro che il nome di un gruppo di task, questo permette una più elevata pulizia concettuale. Ad esempio nella stessa applicazione potremmo definire un namespace "apache" e dei task "restart, stop, start, clean".
Ora impostiamo le variabili nel file config/deploy.rb
.
file config/deploy.rb
set :application, "nomeproj" # nome del progetto set :repository, "http://eloisa/svn/nomeproj/trunk" # URI del repository set :deploy_to, "/var/web/apps/#{application}" # destinazione del deploying set :scm, :subversion # sistema di [D]VCS. Oltre a subversion sono supportati: git, mercurial, darcs etc. #### i vari ruoli divisi per host/server role :app, "eloisa" role :web, "eloisa" role :db, "db.eloisa", :primary => true
Per aggiungere dei task personalizzati in un'applicazione Rails si deve modificare il file "Capfile", e magari utilizzare config/deploy.rb per impostare ulteriori variabili.
Prepariamoci, finalmente, ad effettuare il nostro primo deployment:
# cap deploy:setup * executing 'deploy:setup' * executing "umask 02 && mkdir -p /var/web/apps/nomeproj /var/web/apps/nomeproj/releases /var/web/apps/nomeproj/shared /var/web/apps/nomeproj/shared/system /var/web/apps/nomeproj/shared/log /var/web/apps/nomeproj/shared/pids" servers: ["eloisa"] Password: [eloisa] executing command command finished
Questo comando crea delle directory che ci serviranno per organizzare e tracciare al meglio il nostro lavoro.
Nota: Si possono trovare più informazioni sui vari task eseguendo cap -e nometask
, per una guida generica invece andate con il solito cap -h
Controlliamo che ci sia tutto l'occorrente per eseguire correttamente il deployment.
# cap -q deploy:check Password: You appear to have all necessary dependencies installed
Tutto ok. Possiamo avviare il deployment.
# cap deploy:cold
Questo task è utile la prima volta che si effettua la "messa in produzione" di un'applicazione Rails: prende i sorgenti dall'ultima versione presente nel repository, crea una sottodirectory univoca in "releases" e un collegamento simbolico alla directory current
ln -s /nomeproj/releases/20080310142111 /nomeproj/current
subito dopo esegue le migration
rake Rails_ENV=production db:migrate
e come ultima operazione riavvia il backend cgi del webserver (fatscgi, mongrel).
Note: il riavvio del backend Ruby è affidato allo script "script/spin" che l'utente deve creare. Ecco un esmpio di questo script:
/path/current/script/process/spawner -p 11000 -i 3
Da adesso in poi possiamo aggiornare tutte le nostre Web Applications Rails semplicemente utilizzando:
# cap deploy
Semplice no? E se avessimo fatto un aggiornamente sbagliato? Con Capistrano è banale tornare alla versione precedente.
# cap deploy:rollback
Arrivati a questo punto la conoscenza con Capistrano è fatta. Può sembrare molto il lavoro iniziale, ma una volta utilizzato non se ne riesce più a fare a meno!